]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_codegen_ssa/back/write.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / librustc_codegen_ssa / back / write.rs
index 3afa4758253d919f4c1f0f3a74f4e7383596d759..d81a767abd447ead9a8b2e2aa02fae102ea12403 100644 (file)
@@ -1,5 +1,4 @@
-use super::command::Command;
-use super::link::{self, get_linker, remove};
+use super::link::{self, remove};
 use super::linker::LinkerInfo;
 use super::lto::{self, SerializedModule};
 use super::symbol_export::symbol_name_for_instance_in_crate;
@@ -11,14 +10,6 @@ use crate::{
 
 use crate::traits::*;
 use jobserver::{Acquired, Client};
-use rustc::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId};
-use rustc::middle::cstore::EncodedMetadata;
-use rustc::middle::exported_symbols::SymbolExportLevel;
-use rustc::session::config::{
-    self, Lto, OutputFilenames, OutputType, Passes, Sanitizer, SwitchWithOptPath,
-};
-use rustc::session::Session;
-use rustc::ty::TyCtxt;
 use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfilerRef;
@@ -33,7 +24,15 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental::{
     copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
 };
+use rustc_middle::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::middle::exported_symbols::SymbolExportLevel;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::cgu_reuse_tracker::CguReuseTracker;
+use rustc_session::config::{
+    self, Lto, OutputFilenames, OutputType, Passes, Sanitizer, SwitchWithOptPath,
+};
+use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{sym, Symbol};
@@ -51,6 +50,34 @@ use std::thread;
 
 const PRE_LTO_BC_EXT: &str = "pre-lto.bc";
 
+/// What kind of object file to emit.
+#[derive(Clone, Copy, PartialEq)]
+pub enum EmitObj {
+    // No object file.
+    None,
+
+    // Just uncompressed llvm bitcode. Provides easy compatibility with
+    // emscripten's ecc compiler, when used as the linker.
+    Bitcode,
+
+    // Object code, possibly augmented with a bitcode section.
+    ObjectCode(BitcodeSection),
+}
+
+/// What kind of llvm bitcode section to embed in an object file.
+#[derive(Clone, Copy, PartialEq)]
+pub enum BitcodeSection {
+    // No bitcode section.
+    None,
+
+    // An empty bitcode section (to placate tools such as the iOS linker that
+    // require this section even if they don't use it).
+    Marker,
+
+    // A full, uncompressed bitcode section.
+    Full,
+}
+
 /// Module-specific configuration for `optimize_and_codegen`.
 pub struct ModuleConfig {
     /// Names of additional optimization passes to run.
@@ -74,10 +101,10 @@ pub struct ModuleConfig {
     pub emit_no_opt_bc: bool,
     pub emit_bc: bool,
     pub emit_bc_compressed: bool,
-    pub emit_lto_bc: bool,
     pub emit_ir: bool,
     pub emit_asm: bool,
-    pub emit_obj: bool,
+    pub emit_obj: EmitObj,
+
     // Miscellaneous flags.  These are mostly copied from command-line
     // options.
     pub verify_llvm_ir: bool,
@@ -88,118 +115,158 @@ pub struct ModuleConfig {
     pub vectorize_slp: bool,
     pub merge_functions: bool,
     pub inline_threshold: Option<usize>,
-    pub new_llvm_pass_manager: Option<bool>,
-    // Instead of creating an object file by doing LLVM codegen, just
-    // make the object file bitcode. Provides easy compatibility with
-    // emscripten's ecc compiler, when used as the linker.
-    pub obj_is_bitcode: bool,
-    pub no_integrated_as: bool,
-    pub embed_bitcode: bool,
-    pub embed_bitcode_marker: bool,
+    pub new_llvm_pass_manager: bool,
 }
 
 impl ModuleConfig {
-    fn new(passes: Vec<String>) -> ModuleConfig {
-        ModuleConfig {
-            passes,
-            opt_level: None,
-            opt_size: None,
-
-            pgo_gen: SwitchWithOptPath::Disabled,
-            pgo_use: None,
-
-            sanitizer: None,
-            sanitizer_recover: Default::default(),
-            sanitizer_memory_track_origins: 0,
-
-            emit_no_opt_bc: false,
-            emit_pre_lto_bc: false,
-            emit_bc: false,
-            emit_bc_compressed: false,
-            emit_lto_bc: false,
-            emit_ir: false,
-            emit_asm: false,
-            emit_obj: false,
-            obj_is_bitcode: false,
-            embed_bitcode: false,
-            embed_bitcode_marker: false,
-            no_integrated_as: false,
-
-            verify_llvm_ir: false,
-            no_prepopulate_passes: false,
-            no_builtins: false,
-            time_module: true,
-            vectorize_loop: false,
-            vectorize_slp: false,
-            merge_functions: false,
-            inline_threshold: None,
-            new_llvm_pass_manager: None,
+    fn new(kind: ModuleKind, sess: &Session, no_builtins: bool) -> ModuleConfig {
+        // If it's a regular module, use `$regular`, otherwise use `$other`.
+        // `$regular` and `$other` are evaluated lazily.
+        macro_rules! if_regular {
+            ($regular: expr, $other: expr) => {
+                if let ModuleKind::Regular = kind { $regular } else { $other }
+            };
         }
-    }
 
-    fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
-        self.verify_llvm_ir = sess.verify_llvm_ir();
-        self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
-        self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
-        self.inline_threshold = sess.opts.cg.inline_threshold;
-        self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager;
-        self.obj_is_bitcode =
-            sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled();
-        let embed_bitcode =
-            sess.target.target.options.embed_bitcode || sess.opts.debugging_opts.embed_bitcode;
-        if embed_bitcode {
+        let opt_level_and_size = if_regular!(Some(sess.opts.optimize), None);
+
+        let save_temps = sess.opts.cg.save_temps;
+
+        let should_emit_obj = sess.opts.output_types.contains_key(&OutputType::Exe)
+            || match kind {
+                ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object),
+                ModuleKind::Allocator => false,
+                ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata),
+            };
+
+        let emit_obj = if !should_emit_obj {
+            EmitObj::None
+        } else if sess.target.target.options.obj_is_bitcode
+            || sess.opts.cg.linker_plugin_lto.enabled()
+        {
+            EmitObj::Bitcode
+        } else if sess.opts.debugging_opts.embed_bitcode {
             match sess.opts.optimize {
                 config::OptLevel::No | config::OptLevel::Less => {
-                    self.embed_bitcode_marker = embed_bitcode;
+                    EmitObj::ObjectCode(BitcodeSection::Marker)
                 }
-                _ => self.embed_bitcode = embed_bitcode,
-            }
-        }
-
-        // Copy what clang does by turning on loop vectorization at O2 and
-        // slp vectorization at O3. Otherwise configure other optimization aspects
-        // of this pass manager builder.
-        self.vectorize_loop = !sess.opts.cg.no_vectorize_loops
-            && (sess.opts.optimize == config::OptLevel::Default
-                || sess.opts.optimize == config::OptLevel::Aggressive);
-
-        self.vectorize_slp =
-            !sess.opts.cg.no_vectorize_slp && sess.opts.optimize == config::OptLevel::Aggressive;
-
-        // Some targets (namely, NVPTX) interact badly with the MergeFunctions
-        // pass. This is because MergeFunctions can generate new function calls
-        // which may interfere with the target calling convention; e.g. for the
-        // NVPTX target, PTX kernels should not call other PTX kernels.
-        // MergeFunctions can also be configured to generate aliases instead,
-        // but aliases are not supported by some backends (again, NVPTX).
-        // Therefore, allow targets to opt out of the MergeFunctions pass,
-        // but otherwise keep the pass enabled (at O2 and O3) since it can be
-        // useful for reducing code size.
-        self.merge_functions = match sess
-            .opts
-            .debugging_opts
-            .merge_functions
-            .unwrap_or(sess.target.target.options.merge_functions)
-        {
-            MergeFunctions::Disabled => false,
-            MergeFunctions::Trampolines | MergeFunctions::Aliases => {
-                sess.opts.optimize == config::OptLevel::Default
-                    || sess.opts.optimize == config::OptLevel::Aggressive
+                _ => EmitObj::ObjectCode(BitcodeSection::Full),
             }
+        } else {
+            EmitObj::ObjectCode(BitcodeSection::None)
         };
+
+        ModuleConfig {
+            passes: if_regular!(
+                {
+                    let mut passes = sess.opts.cg.passes.clone();
+                    if sess.opts.debugging_opts.profile {
+                        passes.push("insert-gcov-profiling".to_owned());
+                    }
+                    passes
+                },
+                vec![]
+            ),
+
+            opt_level: opt_level_and_size,
+            opt_size: opt_level_and_size,
+
+            pgo_gen: if_regular!(
+                sess.opts.cg.profile_generate.clone(),
+                SwitchWithOptPath::Disabled
+            ),
+            pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None),
+
+            sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer.clone(), None),
+            sanitizer_recover: if_regular!(
+                sess.opts.debugging_opts.sanitizer_recover.clone(),
+                vec![]
+            ),
+            sanitizer_memory_track_origins: if_regular!(
+                sess.opts.debugging_opts.sanitizer_memory_track_origins,
+                0
+            ),
+
+            emit_pre_lto_bc: if_regular!(
+                save_temps || need_pre_lto_bitcode_for_incr_comp(sess),
+                false
+            ),
+            emit_no_opt_bc: if_regular!(save_temps, false),
+            emit_bc: if_regular!(
+                save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode),
+                save_temps
+            ),
+            emit_bc_compressed: match kind {
+                ModuleKind::Regular | ModuleKind::Allocator => {
+                    // Emit compressed bitcode files for the crate if we're
+                    // emitting an rlib. Whenever an rlib is created, the
+                    // bitcode is inserted into the archive in order to allow
+                    // LTO against it.
+                    need_crate_bitcode_for_rlib(sess)
+                }
+                ModuleKind::Metadata => false,
+            },
+            emit_ir: if_regular!(
+                sess.opts.output_types.contains_key(&OutputType::LlvmAssembly),
+                false
+            ),
+            emit_asm: if_regular!(
+                sess.opts.output_types.contains_key(&OutputType::Assembly),
+                false
+            ),
+            emit_obj,
+
+            verify_llvm_ir: sess.verify_llvm_ir(),
+            no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes,
+            no_builtins: no_builtins || sess.target.target.options.no_builtins,
+
+            // Exclude metadata and allocator modules from time_passes output,
+            // since they throw off the "LLVM passes" measurement.
+            time_module: if_regular!(true, false),
+
+            // Copy what clang does by turning on loop vectorization at O2 and
+            // slp vectorization at O3.
+            vectorize_loop: !sess.opts.cg.no_vectorize_loops
+                && (sess.opts.optimize == config::OptLevel::Default
+                    || sess.opts.optimize == config::OptLevel::Aggressive),
+            vectorize_slp: !sess.opts.cg.no_vectorize_slp
+                && sess.opts.optimize == config::OptLevel::Aggressive,
+
+            // Some targets (namely, NVPTX) interact badly with the
+            // MergeFunctions pass. This is because MergeFunctions can generate
+            // new function calls which may interfere with the target calling
+            // convention; e.g. for the NVPTX target, PTX kernels should not
+            // call other PTX kernels. MergeFunctions can also be configured to
+            // generate aliases instead, but aliases are not supported by some
+            // backends (again, NVPTX). Therefore, allow targets to opt out of
+            // the MergeFunctions pass, but otherwise keep the pass enabled (at
+            // O2 and O3) since it can be useful for reducing code size.
+            merge_functions: match sess
+                .opts
+                .debugging_opts
+                .merge_functions
+                .unwrap_or(sess.target.target.options.merge_functions)
+            {
+                MergeFunctions::Disabled => false,
+                MergeFunctions::Trampolines | MergeFunctions::Aliases => {
+                    sess.opts.optimize == config::OptLevel::Default
+                        || sess.opts.optimize == config::OptLevel::Aggressive
+                }
+            },
+
+            inline_threshold: sess.opts.cg.inline_threshold,
+            new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
+        }
     }
 
     pub fn bitcode_needed(&self) -> bool {
-        self.emit_bc || self.obj_is_bitcode || self.emit_bc_compressed || self.embed_bitcode
+        self.emit_bc
+            || self.emit_bc_compressed
+            || self.emit_obj == EmitObj::Bitcode
+            || self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)
     }
 }
 
-/// Assembler name and command used by codegen when no_integrated_as is enabled
-pub struct AssemblerCommand {
-    name: PathBuf,
-    cmd: Command,
-}
-
 // HACK(eddyb) work around `#[derive]` producing wrong bounds for `Clone`.
 pub struct TargetMachineFactory<B: WriteBackendMethods>(
     pub Arc<dyn Fn() -> Result<B::TargetMachine, String> + Send + Sync>,
@@ -252,8 +319,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub cgu_reuse_tracker: CguReuseTracker,
     // Channel back to the main control thread to send messages to
     pub coordinator_send: Sender<Box<dyn Any + Send>>,
-    // The assembler command if no_integrated_as option is enabled, None otherwise
-    pub assembler_cmd: Option<Arc<AssemblerCommand>>,
 }
 
 impl<B: WriteBackendMethods> CodegenContext<B> {
@@ -288,7 +353,7 @@ fn generate_lto_work<B: ExtraBackendMethods>(
         B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules).unwrap_or_else(|e| e.raise())
     };
 
-    let result = lto_modules
+    lto_modules
         .into_iter()
         .map(|module| {
             let cost = module.cost();
@@ -303,9 +368,7 @@ fn generate_lto_work<B: ExtraBackendMethods>(
                 0,
             )
         }))
-        .collect();
-
-    result
+        .collect()
 }
 
 pub struct CompiledModules {
@@ -341,9 +404,9 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
 
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
-    let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins);
+    let no_builtins = attr::contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
     let subsystem =
-        attr::first_attr_value_str_by_name(&tcx.hir().krate().attrs, sym::windows_subsystem);
+        attr::first_attr_value_str_by_name(&tcx.hir().krate().item.attrs, sym::windows_subsystem);
     let windows_subsystem = subsystem.map(|subsystem| {
         if subsystem != sym::windows && subsystem != sym::console {
             tcx.sess.fatal(&format!(
@@ -358,89 +421,9 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     let linker_info = LinkerInfo::new(tcx);
     let crate_info = CrateInfo::new(tcx);
 
-    // Figure out what we actually need to build.
-    let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
-    let mut metadata_config = ModuleConfig::new(vec![]);
-    let mut allocator_config = ModuleConfig::new(vec![]);
-
-    if sess.opts.debugging_opts.profile {
-        modules_config.passes.push("insert-gcov-profiling".to_owned())
-    }
-
-    modules_config.pgo_gen = sess.opts.cg.profile_generate.clone();
-    modules_config.pgo_use = sess.opts.cg.profile_use.clone();
-    modules_config.sanitizer = sess.opts.debugging_opts.sanitizer.clone();
-    modules_config.sanitizer_recover = sess.opts.debugging_opts.sanitizer_recover.clone();
-    modules_config.sanitizer_memory_track_origins =
-        sess.opts.debugging_opts.sanitizer_memory_track_origins;
-    modules_config.opt_level = Some(sess.opts.optimize);
-    modules_config.opt_size = Some(sess.opts.optimize);
-
-    // Save all versions of the bytecode if we're saving our temporaries.
-    if sess.opts.cg.save_temps {
-        modules_config.emit_no_opt_bc = true;
-        modules_config.emit_pre_lto_bc = true;
-        modules_config.emit_bc = true;
-        modules_config.emit_lto_bc = true;
-        metadata_config.emit_bc = true;
-        allocator_config.emit_bc = true;
-    }
-
-    // Emit compressed bitcode files for the crate if we're emitting an rlib.
-    // Whenever an rlib is created, the bitcode is inserted into the archive in
-    // order to allow LTO against it.
-    if need_crate_bitcode_for_rlib(sess) {
-        modules_config.emit_bc_compressed = true;
-        allocator_config.emit_bc_compressed = true;
-    }
-
-    modules_config.emit_pre_lto_bc = need_pre_lto_bitcode_for_incr_comp(sess);
-
-    modules_config.no_integrated_as =
-        tcx.sess.opts.cg.no_integrated_as || tcx.sess.target.target.options.no_integrated_as;
-
-    for output_type in sess.opts.output_types.keys() {
-        match *output_type {
-            OutputType::Bitcode => {
-                modules_config.emit_bc = true;
-            }
-            OutputType::LlvmAssembly => {
-                modules_config.emit_ir = true;
-            }
-            OutputType::Assembly => {
-                modules_config.emit_asm = true;
-                // If we're not using the LLVM assembler, this function
-                // could be invoked specially with output_type_assembly, so
-                // in this case we still want the metadata object file.
-                if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
-                    metadata_config.emit_obj = true;
-                    allocator_config.emit_obj = true;
-                }
-            }
-            OutputType::Object => {
-                modules_config.emit_obj = true;
-            }
-            OutputType::Metadata => {
-                metadata_config.emit_obj = true;
-            }
-            OutputType::Exe => {
-                modules_config.emit_obj = true;
-                metadata_config.emit_obj = true;
-                allocator_config.emit_obj = true;
-            }
-            OutputType::Mir => {}
-            OutputType::DepInfo => {}
-        }
-    }
-
-    modules_config.set_flags(sess, no_builtins);
-    metadata_config.set_flags(sess, no_builtins);
-    allocator_config.set_flags(sess, no_builtins);
-
-    // Exclude metadata and allocator modules from time_passes output, since
-    // they throw off the "LLVM passes" measurement.
-    metadata_config.time_module = false;
-    allocator_config.time_module = false;
+    let regular_config = ModuleConfig::new(ModuleKind::Regular, sess, no_builtins);
+    let metadata_config = ModuleConfig::new(ModuleKind::Metadata, sess, no_builtins);
+    let allocator_config = ModuleConfig::new(ModuleKind::Allocator, sess, no_builtins);
 
     let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
     let (codegen_worker_send, codegen_worker_receive) = channel();
@@ -454,7 +437,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
         coordinator_receive,
         total_cgus,
         sess.jobserver.clone(),
-        Arc::new(modules_config),
+        Arc::new(regular_config),
         Arc::new(metadata_config),
         Arc::new(allocator_config),
         coordinator_send.clone(),
@@ -877,7 +860,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
         }
     }
 
-    assert_eq!(object.is_some(), module_config.emit_obj);
+    assert_eq!(object.is_some(), module_config.emit_obj != EmitObj::None);
     assert_eq!(bytecode.is_some(), module_config.emit_bc);
     assert_eq!(bytecode_compressed.is_some(), module_config.emit_bc_compressed);
 
@@ -954,7 +937,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     coordinator_receive: Receiver<Box<dyn Any + Send>>,
     total_cgus: usize,
     jobserver: Client,
-    modules_config: Arc<ModuleConfig>,
+    regular_config: Arc<ModuleConfig>,
     metadata_config: Arc<ModuleConfig>,
     allocator_config: Arc<ModuleConfig>,
     tx_to_llvm_workers: Sender<Box<dyn Any + Send>>,
@@ -1011,17 +994,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
     }));
 
-    let assembler_cmd = if modules_config.no_integrated_as {
-        // HACK: currently we use linker (gcc) as our assembler
-        let (linker, flavor) = link::linker_and_flavor(sess);
-
-        let (name, mut cmd) = get_linker(sess, &linker, flavor);
-        cmd.args(&sess.target.target.options.asm_args);
-        Some(Arc::new(AssemblerCommand { name, cmd }))
-    } else {
-        None
-    };
-
     let ol = if tcx.sess.opts.debugging_opts.no_codegen
         || !tcx.sess.opts.output_types.should_codegen()
     {
@@ -1048,7 +1020,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         coordinator_send,
         diag_emitter: shared_emitter.clone(),
         output_filenames: tcx.output_filenames(LOCAL_CRATE),
-        regular_module_config: modules_config,
+        regular_module_config: regular_config,
         metadata_module_config: metadata_config,
         allocator_module_config: allocator_config,
         tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol, false)),
@@ -1057,7 +1029,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
         target_arch: tcx.sess.target.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
-        assembler_cmd,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
@@ -1535,7 +1506,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     }
 }
 
-pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
+pub const CODEGEN_WORKER_ID: usize = usize::MAX;
 
 /// `FatalError` is explicitly not `Send`.
 #[must_use]
@@ -1591,44 +1562,6 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
     });
 }
 
-pub fn run_assembler<B: ExtraBackendMethods>(
-    cgcx: &CodegenContext<B>,
-    handler: &Handler,
-    assembly: &Path,
-    object: &Path,
-) {
-    let assembler = cgcx.assembler_cmd.as_ref().expect("cgcx.assembler_cmd is missing?");
-
-    let pname = &assembler.name;
-    let mut cmd = assembler.cmd.clone();
-    cmd.arg("-c").arg("-o").arg(object).arg(assembly);
-    debug!("{:?}", cmd);
-
-    match cmd.output() {
-        Ok(prog) => {
-            if !prog.status.success() {
-                let mut note = prog.stderr.clone();
-                note.extend_from_slice(&prog.stdout);
-
-                handler
-                    .struct_err(&format!(
-                        "linking with `{}` failed: {}",
-                        pname.display(),
-                        prog.status
-                    ))
-                    .note(&format!("{:?}", &cmd))
-                    .note(str::from_utf8(&note[..]).unwrap())
-                    .emit();
-                handler.abort_if_errors();
-            }
-        }
-        Err(e) => {
-            handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
-            handler.abort_if_errors();
-        }
-    }
-}
-
 enum SharedEmitterMessage {
     Diagnostic(Diagnostic),
     InlineAsmError(u32, String),