summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_ssa/src/back
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs241
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs151
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs63
4 files changed, 257 insertions, 211 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 6cce95427..0dc0dee86 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -23,20 +23,23 @@ use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
use rustc_span::DebuggerVisualizerFile;
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
-use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
-use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
+use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
+use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, Target};
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use super::command::Command;
use super::linker::{self, Linker};
use super::metadata::{create_rmeta_file, MetadataPosition};
use super::rpath::{self, RPathConfig};
-use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
+use crate::{
+ errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+};
use cc::windows_registry;
use regex::Regex;
use tempfile::Builder as TempFileBuilder;
+use itertools::Itertools;
use std::borrow::Borrow;
use std::cell::OnceCell;
use std::collections::BTreeSet;
@@ -93,7 +96,7 @@ pub fn link_binary<'a>(
let tmpdir = TempFileBuilder::new()
.prefix("rustc")
.tempdir()
- .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+ .unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
let out_filename = out_filename(
sess,
@@ -206,11 +209,29 @@ pub fn link_binary<'a>(
}
pub fn each_linked_rlib(
+ sess: &Session,
info: &CrateInfo,
f: &mut dyn FnMut(CrateNum, &Path),
-) -> Result<(), String> {
+) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
let mut fmts = None;
+
+ let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
+ if lto_active {
+ for combination in info.dependency_formats.iter().combinations(2) {
+ let (ty1, list1) = &combination[0];
+ let (ty2, list2) = &combination[1];
+ if list1 != list2 {
+ return Err(errors::LinkRlibError::IncompatibleDependencyFormats {
+ ty1: format!("{ty1:?}"),
+ ty2: format!("{ty2:?}"),
+ list1: format!("{list1:?}"),
+ list2: format!("{list2:?}"),
+ });
+ }
+ }
+ }
+
for (ty, list) in info.dependency_formats.iter() {
match ty {
CrateType::Executable
@@ -220,30 +241,31 @@ pub fn each_linked_rlib(
fmts = Some(list);
break;
}
+ CrateType::Dylib if lto_active => {
+ fmts = Some(list);
+ break;
+ }
_ => {}
}
}
let Some(fmts) = fmts else {
- return Err("could not find formats for rlibs".to_string());
+ return Err(errors::LinkRlibError::MissingFormat);
};
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
Some(_) => {}
- None => return Err("could not find formats for rlibs".to_string()),
+ None => return Err(errors::LinkRlibError::MissingFormat),
}
- let name = info.crate_name[&cnum];
+ let crate_name = info.crate_name[&cnum];
let used_crate_source = &info.used_crate_source[&cnum];
if let Some((path, _)) = &used_crate_source.rlib {
f(cnum, &path);
} else {
if used_crate_source.rmeta.is_some() {
- return Err(format!(
- "could not find rlib for: `{}`, found rmeta (metadata) file",
- name
- ));
+ return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
} else {
- return Err(format!("could not find rlib for: `{}`", name));
+ return Err(errors::LinkRlibError::NotFound { crate_name });
}
}
}
@@ -340,10 +362,7 @@ fn link_rlib<'a>(
// -whole-archive and it isn't clear how we can currently handle such a
// situation correctly.
// See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
- sess.err(
- "the linking modifiers `+bundle` and `+whole-archive` are not compatible \
- with each other when generating rlibs",
- );
+ sess.emit_err(errors::IncompatibleLinkingModifiers);
}
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
NativeLibKind::Static { bundle: Some(false), .. }
@@ -365,12 +384,8 @@ fn link_rlib<'a>(
));
continue;
}
- ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
- sess.fatal(&format!(
- "failed to add native library {}: {}",
- location.to_string_lossy(),
- e
- ));
+ ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
+ sess.emit_fatal(errors::AddNativeLibrary { library_path: location, error });
});
}
}
@@ -386,8 +401,8 @@ fn link_rlib<'a>(
true,
);
- ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
- sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e));
+ ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
+ sess.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
});
}
@@ -452,14 +467,11 @@ fn collate_raw_dylibs<'a, 'b>(
// FIXME: when we add support for ordinals, figure out if we need to do anything
// if we have two DllImport values with the same name but different ordinals.
if import.calling_convention != old_import.calling_convention {
- sess.span_err(
- import.span,
- &format!(
- "multiple declarations of external function `{}` from \
- library `{}` have different calling conventions",
- import.name, name,
- ),
- );
+ sess.emit_err(errors::MultipleExternalFuncDecl {
+ span: import.span,
+ function: import.name,
+ library_name: &name,
+ });
}
}
}
@@ -502,7 +514,7 @@ fn link_staticlib<'a>(
)?;
let mut all_native_libs = vec![];
- let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| {
+ let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
let name = codegen_results.crate_info.crate_name[&cnum];
let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
@@ -561,7 +573,7 @@ fn link_staticlib<'a>(
all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
});
if let Err(e) = res {
- sess.fatal(&e);
+ sess.emit_fatal(e);
}
ab.build(out_filename);
@@ -674,9 +686,7 @@ fn link_dwarf_object<'a>(
}) {
Ok(()) => {}
Err(e) => {
- sess.struct_err("linking dwarf objects with thorin failed")
- .note(&format!("{:?}", e))
- .emit();
+ sess.emit_err(errors::ThorinErrorWrapper(e));
sess.abort_if_errors();
}
}
@@ -749,8 +759,7 @@ fn link_natively<'a>(
// then it should not default to linking executables as pie. Different
// versions of gcc seem to use different quotes in the error message so
// don't check for them.
- if sess.target.linker_is_gnu
- && flavor != LinkerFlavor::Ld
+ if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
&& unknown_arg_regex.is_match(&out)
&& out.contains("-no-pie")
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
@@ -768,8 +777,7 @@ fn link_natively<'a>(
// Detect '-static-pie' used with an older version of gcc or clang not supporting it.
// Fallback from '-static-pie' to '-static' in that case.
- if sess.target.linker_is_gnu
- && flavor != LinkerFlavor::Ld
+ if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
&& unknown_arg_regex.is_match(&out)
&& (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
@@ -882,29 +890,20 @@ fn link_natively<'a>(
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
let escaped_output = escape_string(&output);
- let mut err = sess.struct_err(&format!(
- "linking with `{}` failed: {}",
- linker_path.display(),
- prog.status
- ));
- err.note(&format!("{:?}", &cmd)).note(&escaped_output);
- if escaped_output.contains("undefined reference to") {
- err.help(
- "some `extern` functions couldn't be found; some native libraries may \
- need to be installed or have their path specified",
- );
- err.note("use the `-l` flag to specify native libraries to link");
- err.note("use the `cargo:rustc-link-lib` directive to specify the native \
- libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)");
- }
- err.emit();
-
+ // FIXME: Add UI tests for this error.
+ let err = errors::LinkingFailed {
+ linker_path: &linker_path,
+ exit_status: prog.status,
+ command: &cmd,
+ escaped_output: &escaped_output,
+ };
+ sess.diagnostic().emit_err(err);
// If MSVC's `link.exe` was expected but the return code
// is not a Microsoft LNK error then suggest a way to fix or
// install the Visual Studio build tools.
if let Some(code) = prog.status.code() {
if sess.target.is_like_msvc
- && flavor == LinkerFlavor::Msvc
+ && flavor == LinkerFlavor::Msvc(Lld::No)
// Respect the command line override
&& sess.opts.cg.linker.is_none()
// Match exactly "link.exe"
@@ -980,9 +979,10 @@ fn link_natively<'a>(
but `link.exe` was not found",
);
sess.note_without_error(
- "please ensure that VS 2013, VS 2015, VS 2017, VS 2019 or VS 2022 \
- was installed with the Visual C++ option",
+ "please ensure that Visual Studio 2017 or later, or Build Tools \
+ for Visual Studio were installed with the Visual C++ option.",
);
+ sess.note_without_error("VS Code is a different product, and is not sufficient.");
}
sess.abort_if_errors();
}
@@ -1035,16 +1035,36 @@ fn link_natively<'a>(
if sess.target.is_like_osx {
match (strip, crate_type) {
- (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+ (Strip::Debuginfo, _) => {
+ strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-S"))
+ }
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
- strip_symbols_in_osx(sess, &out_filename, Some("-x"))
+ strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-x"))
+ }
+ (Strip::Symbols, _) => {
+ strip_symbols_with_external_utility(sess, "strip", &out_filename, None)
}
- (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None),
(Strip::None, _) => {}
}
}
+ if sess.target.os == "illumos" {
+ // Many illumos systems will have both the native 'strip' utility and
+ // the GNU one. Use the native version explicitly and do not rely on
+ // what's in the path.
+ let stripcmd = "/usr/bin/strip";
+ match strip {
+ // Always preserve the symbol table (-x).
+ Strip::Debuginfo => {
+ strip_symbols_with_external_utility(sess, stripcmd, &out_filename, Some("-x"))
+ }
+ // Strip::Symbols is handled via the --strip-all linker option.
+ Strip::Symbols => {}
+ Strip::None => {}
+ }
+ }
+
Ok(())
}
@@ -1056,8 +1076,13 @@ fn strip_value(sess: &Session) -> Strip {
}
}
-fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
- let mut cmd = Command::new("strip");
+fn strip_symbols_with_external_utility<'a>(
+ sess: &'a Session,
+ util: &str,
+ out_filename: &Path,
+ option: Option<&str>,
+) {
+ let mut cmd = Command::new(util);
if let Some(option) = option {
cmd.arg(option);
}
@@ -1068,14 +1093,14 @@ fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Opti
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
sess.struct_warn(&format!(
- "stripping debug info with `strip` failed: {}",
- prog.status
+ "stripping debug info with `{}` failed: {}",
+ util, prog.status
))
.note(&escape_string(&output))
.emit();
}
}
- Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
+ Err(e) => sess.fatal(&format!("unable to run `{}`: {}", util, e)),
}
}
@@ -1091,11 +1116,12 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
// both executables and dynamic shared objects. Everywhere else the runtimes
// are currently distributed as static libraries which should be linked to
// executables only.
- let needs_runtime = match crate_type {
- CrateType::Executable => true,
- CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
- CrateType::Rlib | CrateType::Staticlib => false,
- };
+ let needs_runtime = !sess.target.is_like_android
+ && match crate_type {
+ CrateType::Executable => true,
+ CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
+ CrateType::Rlib | CrateType::Staticlib => false,
+ };
if !needs_runtime {
return;
@@ -1187,7 +1213,10 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
// only the linker flavor is known; use the default linker for the selected flavor
(None, Some(flavor)) => Some((
PathBuf::from(match flavor {
- LinkerFlavor::Gcc => {
+ LinkerFlavor::Gnu(Cc::Yes, _)
+ | LinkerFlavor::Darwin(Cc::Yes, _)
+ | LinkerFlavor::WasmLld(Cc::Yes)
+ | LinkerFlavor::Unix(Cc::Yes) => {
if cfg!(any(target_os = "solaris", target_os = "illumos")) {
// On historical Solaris systems, "cc" may have
// been Sun Studio, which is not flag-compatible
@@ -1200,9 +1229,14 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
"cc"
}
}
- LinkerFlavor::Ld => "ld",
- LinkerFlavor::Lld(_) => "lld",
- LinkerFlavor::Msvc => "link.exe",
+ LinkerFlavor::Gnu(_, Lld::Yes)
+ | LinkerFlavor::Darwin(_, Lld::Yes)
+ | LinkerFlavor::WasmLld(..)
+ | LinkerFlavor::Msvc(Lld::Yes) => "lld",
+ LinkerFlavor::Gnu(..) | LinkerFlavor::Darwin(..) | LinkerFlavor::Unix(..) => {
+ "ld"
+ }
+ LinkerFlavor::Msvc(..) => "link.exe",
LinkerFlavor::EmCc => {
if cfg!(windows) {
"emcc.bat"
@@ -1227,15 +1261,20 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|| stem == "clang"
|| stem.ends_with("-clang")
{
- LinkerFlavor::Gcc
+ LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
- LinkerFlavor::Lld(LldFlavor::Wasm)
- } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
- LinkerFlavor::Ld
- } else if stem == "link" || stem == "lld-link" {
- LinkerFlavor::Msvc
+ LinkerFlavor::WasmLld(Cc::No)
+ } else if stem == "ld" || stem.ends_with("-ld") {
+ LinkerFlavor::from_cli(LinkerFlavorCli::Ld, &sess.target)
+ } else if stem == "ld.lld" {
+ LinkerFlavor::Gnu(Cc::No, Lld::Yes)
+ } else if stem == "link" {
+ LinkerFlavor::Msvc(Lld::No)
+ } else if stem == "lld-link" {
+ LinkerFlavor::Msvc(Lld::Yes)
} else if stem == "lld" || stem == "rust-lld" {
- LinkerFlavor::Lld(sess.target.lld_flavor)
+ let lld_flavor = sess.target.linker_flavor.lld_flavor();
+ LinkerFlavor::from_cli(LinkerFlavorCli::Lld(lld_flavor), &sess.target)
} else {
// fall back to the value in the target spec
sess.target.linker_flavor
@@ -1249,7 +1288,8 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
// linker and linker flavor specified via command line have precedence over what the target
// specification specifies
- let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli);
+ let linker_flavor =
+ sess.opts.cg.linker_flavor.map(|flavor| LinkerFlavor::from_cli(flavor, &sess.target));
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
return ret;
}
@@ -1320,7 +1360,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
let verbatim = lib.verbatim.unwrap_or(false);
if sess.target.is_like_msvc {
Some(format!("{}{}", name, if verbatim { "" } else { ".lib" }))
- } else if sess.target.linker_is_gnu {
+ } else if sess.target.linker_flavor.is_gnu() {
Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
} else {
Some(format!("-l{}", name))
@@ -1607,7 +1647,7 @@ fn add_pre_link_objects(
let empty = Default::default();
let objects = if self_contained {
&opts.pre_link_objects_self_contained
- } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
+ } else if !(sess.target.os == "fuchsia" && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))) {
&opts.pre_link_objects
} else {
&empty
@@ -1647,7 +1687,7 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor)
fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
match (crate_type, &sess.target.link_script) {
(CrateType::Cdylib | CrateType::Executable, Some(script)) => {
- if !sess.target.linker_is_gnu {
+ if !sess.target.linker_flavor.is_gnu() {
sess.fatal("can only use link script when linking with GNU-like linker");
}
@@ -1890,7 +1930,7 @@ fn add_rpath_args(
out_filename: out_filename.to_path_buf(),
has_rpath: sess.target.has_rpath,
is_like_osx: sess.target.is_like_osx,
- linker_is_gnu: sess.target.linker_is_gnu,
+ linker_is_gnu: sess.target.linker_flavor.is_gnu(),
};
cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
}
@@ -2134,7 +2174,7 @@ fn add_order_independent_options(
if sess.target.os == "fuchsia"
&& crate_type == CrateType::Executable
- && flavor != LinkerFlavor::Gcc
+ && !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
{
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
@@ -2747,12 +2787,12 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
let llvm_target = &sess.target.llvm_target;
if sess.target.vendor != "apple"
|| !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos")
- || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
+ || !matches!(flavor, LinkerFlavor::Darwin(..))
{
return;
}
- if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) {
+ if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
return;
}
@@ -2786,10 +2826,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
};
match flavor {
- LinkerFlavor::Gcc => {
+ LinkerFlavor::Darwin(Cc::Yes, _) => {
cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
}
- LinkerFlavor::Lld(LldFlavor::Ld64) => {
+ LinkerFlavor::Darwin(Cc::No, _) => {
cmd.args(&["-syslibroot", &sdk_root]);
}
_ => unreachable!(),
@@ -2852,7 +2892,10 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
if let Some(ld_impl) = sess.opts.unstable_opts.gcc_ld {
- if let LinkerFlavor::Gcc = flavor {
+ if let LinkerFlavor::Gnu(Cc::Yes, _)
+ | LinkerFlavor::Darwin(Cc::Yes, _)
+ | LinkerFlavor::WasmLld(Cc::Yes) = flavor
+ {
match ld_impl {
LdImpl::Lld => {
// Implement the "self-contained" part of -Zgcc-ld
@@ -2867,7 +2910,7 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
- if sess.target.lld_flavor != LldFlavor::Ld {
+ if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e505543b2..c49b19bdf 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,5 +1,6 @@
use super::command::Command;
use super::symbol_export;
+use crate::errors;
use rustc_span::symbol::sym;
use std::ffi::{OsStr, OsString};
@@ -16,7 +17,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
use rustc_session::Session;
-use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
+use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
use cc::windows_registry;
@@ -56,8 +57,13 @@ pub fn get_linker<'a>(
let mut cmd = match linker.to_str() {
Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
_ => match flavor {
- LinkerFlavor::Lld(f) => Command::lld(linker, f),
- LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => {
+ LinkerFlavor::Gnu(Cc::No, Lld::Yes)
+ | LinkerFlavor::Darwin(Cc::No, Lld::Yes)
+ | LinkerFlavor::WasmLld(Cc::No)
+ | LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
+ LinkerFlavor::Msvc(Lld::No)
+ if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
+ {
Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
}
_ => Command::new(linker),
@@ -68,9 +74,7 @@ pub fn get_linker<'a>(
// To comply with the Windows App Certification Kit,
// MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
let t = &sess.target;
- if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
- && t.vendor == "uwp"
- {
+ if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
if let Some(ref tool) = msvc_tool {
let original_path = tool.path();
if let Some(ref root_lib_path) = original_path.ancestors().nth(4) {
@@ -126,23 +130,22 @@ pub fn get_linker<'a>(
// to the linker args construction.
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
match flavor {
- LinkerFlavor::Gcc => {
- Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false })
- as Box<dyn Linker>
- }
- LinkerFlavor::Ld if sess.target.os == "l4re" => {
+ LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
}
- LinkerFlavor::Lld(LldFlavor::Ld)
- | LinkerFlavor::Lld(LldFlavor::Ld64)
- | LinkerFlavor::Ld => {
- Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true })
- as Box<dyn Linker>
- }
- LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
- Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
- }
- LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
+ LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
+ LinkerFlavor::Gnu(cc, _)
+ | LinkerFlavor::Darwin(cc, _)
+ | LinkerFlavor::WasmLld(cc)
+ | LinkerFlavor::Unix(cc) => Box::new(GccLinker {
+ cmd,
+ sess,
+ target_cpu,
+ hinted_static: false,
+ is_ld: cc == Cc::No,
+ is_gnu: flavor.is_gnu(),
+ }) as Box<dyn Linker>,
+ LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
@@ -211,6 +214,7 @@ pub struct GccLinker<'a> {
hinted_static: bool, // Keeps track of the current hinting mode.
// Link as ld
is_ld: bool,
+ is_gnu: bool,
}
impl<'a> GccLinker<'a> {
@@ -359,7 +363,7 @@ impl<'a> Linker for GccLinker<'a> {
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
match output_kind {
LinkOutputKind::DynamicNoPicExe => {
- if !self.is_ld && self.sess.target.linker_is_gnu {
+ if !self.is_ld && self.is_gnu {
self.cmd.arg("-no-pie");
}
}
@@ -373,7 +377,7 @@ impl<'a> Linker for GccLinker<'a> {
LinkOutputKind::StaticNoPicExe => {
// `-static` works for both gcc wrapper and ld.
self.cmd.arg("-static");
- if !self.is_ld && self.sess.target.linker_is_gnu {
+ if !self.is_ld && self.is_gnu {
self.cmd.arg("-no-pie");
}
}
@@ -431,26 +435,26 @@ impl<'a> Linker for GccLinker<'a> {
// FIXME(81490): ld64 doesn't support these flags but macOS 11
// has -needed-l{} / -needed_library {}
// but we have no way to detect that here.
- self.sess.warn("`as-needed` modifier not implemented yet for ld64");
- } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
+ self.sess.emit_warning(errors::Ld64UnimplementedModifier);
+ } else if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--no-as-needed");
} else {
- self.sess.warn("`as-needed` modifier not supported for current linker");
+ self.sess.emit_warning(errors::LinkerUnsupportedModifier);
}
}
self.hint_dynamic();
- self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+ self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
if !as_needed {
if self.sess.target.is_like_osx {
// See above FIXME comment
- } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
+ } else if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--as-needed");
}
}
}
fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
self.hint_static();
- self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+ self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
}
fn link_rlib(&mut self, lib: &Path) {
self.hint_static();
@@ -489,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> {
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
// flag but we have no way to detect that here.
// self.cmd.arg("-needed_framework").arg(framework);
- self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+ self.sess.emit_warning(errors::Ld64UnimplementedModifier);
}
self.cmd.arg("-framework").arg(framework);
}
@@ -504,11 +508,8 @@ impl<'a> Linker for GccLinker<'a> {
self.hint_static();
let target = &self.sess.target;
if !target.is_like_osx {
- self.linker_arg("--whole-archive").cmd.arg(format!(
- "-l{}{}",
- if verbatim { ":" } else { "" },
- lib
- ));
+ self.linker_arg("--whole-archive");
+ self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
@@ -553,21 +554,19 @@ impl<'a> Linker for GccLinker<'a> {
// eliminate the metadata. If we're building an executable, however,
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
// reduction.
- } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
- && !keep_metadata
- {
+ } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
self.linker_arg("--gc-sections");
}
}
fn no_gc_sections(&mut self) {
- if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
+ if self.is_gnu || self.sess.target.is_like_wasm {
self.linker_arg("--no-gc-sections");
}
}
fn optimize(&mut self) {
- if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
+ if !self.is_gnu && !self.sess.target.is_like_wasm {
return;
}
@@ -581,7 +580,7 @@ impl<'a> Linker for GccLinker<'a> {
}
fn pgo_gen(&mut self) {
- if !self.sess.target.linker_is_gnu {
+ if !self.is_gnu {
return;
}
@@ -611,7 +610,13 @@ impl<'a> Linker for GccLinker<'a> {
match strip {
Strip::None => {}
Strip::Debuginfo => {
- self.linker_arg("--strip-debug");
+ // The illumos linker does not support --strip-debug although
+ // it does support --strip-all as a compatibility alias for -s.
+ // The --strip-debug case is handled by running an external
+ // `strip` utility as a separate step after linking.
+ if self.sess.target.os != "illumos" {
+ self.linker_arg("--strip-debug");
+ }
}
Strip::Symbols => {
self.linker_arg("--strip-all");
@@ -667,8 +672,8 @@ impl<'a> Linker for GccLinker<'a> {
writeln!(f, "_{}", sym)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::LibDefWriteFailure { error });
}
} else if is_windows {
let res: io::Result<()> = try {
@@ -682,8 +687,8 @@ impl<'a> Linker for GccLinker<'a> {
writeln!(f, " {}", symbol)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write list.def file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::LibDefWriteFailure { error });
}
} else {
// Write an LD version script
@@ -699,8 +704,8 @@ impl<'a> Linker for GccLinker<'a> {
}
writeln!(f, "\n local:\n *;\n}};")?;
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write version script: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::VersionScriptWriteFailure { error });
}
}
@@ -752,13 +757,13 @@ impl<'a> Linker for GccLinker<'a> {
fn add_no_exec(&mut self) {
if self.sess.target.is_like_windows {
self.linker_arg("--nxcompat");
- } else if self.sess.target.linker_is_gnu {
+ } else if self.is_gnu {
self.linker_arg("-znoexecstack");
}
}
fn add_as_needed(&mut self) {
- if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
+ if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--as-needed");
} else if self.sess.target.is_like_solaris {
// -z ignore is the Solaris equivalent to the GNU ld --as-needed option
@@ -917,9 +922,8 @@ impl<'a> Linker for MsvcLinker<'a> {
self.cmd.arg(arg);
}
}
- Err(err) => {
- self.sess
- .warn(&format!("error enumerating natvis directory: {}", err));
+ Err(error) => {
+ self.sess.emit_warning(errors::NoNatvisDirectory { error });
}
}
}
@@ -973,8 +977,8 @@ impl<'a> Linker for MsvcLinker<'a> {
writeln!(f, " {}", symbol)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::LibDefWriteFailure { error });
}
let mut arg = OsString::from("/DEF:");
arg.push(path);
@@ -1174,22 +1178,19 @@ impl<'a> WasmLd<'a> {
// sharing memory and instantiating the module multiple times. As a
// result if it were exported then we'd just have no sharing.
//
- // * `--export=__wasm_init_memory` - when using `--passive-segments` the
- // linker will synthesize this function, and so we need to make sure
- // that our usage of `--export` below won't accidentally cause this
- // function to get deleted.
- //
- // * `--export=*tls*` - when `#[thread_local]` symbols are used these
- // symbols are how the TLS segments are initialized and configured.
+ // On wasm32-unknown-unknown, we also export symbols for glue code to use:
+ // * `--export=*tls*` - when `#[thread_local]` symbols are used these
+ // symbols are how the TLS segments are initialized and configured.
if sess.target_features.contains(&sym::atomics) {
cmd.arg("--shared-memory");
cmd.arg("--max-memory=1073741824");
cmd.arg("--import-memory");
- cmd.arg("--export=__wasm_init_memory");
- cmd.arg("--export=__wasm_init_tls");
- cmd.arg("--export=__tls_size");
- cmd.arg("--export=__tls_align");
- cmd.arg("--export=__tls_base");
+ if sess.target.os == "unknown" {
+ cmd.arg("--export=__wasm_init_tls");
+ cmd.arg("--export=__tls_size");
+ cmd.arg("--export=__tls_align");
+ cmd.arg("--export=__tls_base");
+ }
}
WasmLd { cmd, sess }
}
@@ -1314,10 +1315,12 @@ impl<'a> Linker for WasmLd<'a> {
// LLD will hide these otherwise-internal symbols since it only exports
// symbols explicitly passed via the `--export` flags above and hides all
- // others. Various bits and pieces of tooling use this, so be sure these
- // symbols make their way out of the linker as well.
- self.cmd.arg("--export=__heap_base");
- self.cmd.arg("--export=__data_end");
+ // others. Various bits and pieces of wasm32-unknown-unknown tooling use
+ // this, so be sure these symbols make their way out of the linker as well.
+ if self.sess.target.os == "unknown" {
+ self.cmd.arg("--export=__heap_base");
+ self.cmd.arg("--export=__data_end");
+ }
}
fn subsystem(&mut self, _subsystem: &str) {}
@@ -1438,7 +1441,7 @@ impl<'a> Linker for L4Bender<'a> {
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
// ToDo, not implemented, copy from GCC
- self.sess.warn("exporting symbols not implemented yet for L4Bender");
+ self.sess.emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
return;
}
@@ -1730,8 +1733,8 @@ impl<'a> Linker for BpfLinker<'a> {
writeln!(f, "{}", sym)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write symbols file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::SymbolFileWriteFailure { error });
} else {
self.cmd.arg("--export-symbols").arg(&path);
}
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 8d7e2c5cf..c2ecc4160 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, SymbolName, TyCtxt};
-use rustc_session::config::CrateType;
+use rustc_session::config::{CrateType, OomStrategy};
use rustc_target::spec::SanitizerSet;
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
@@ -76,7 +76,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
// let it through if it's included statically.
match tcx.hir().get_by_def_id(def_id) {
Node::ForeignItem(..) => {
- tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
+ tcx.native_library(def_id).map_or(false, |library| library.kind.is_statically_included()).then_some(def_id)
}
// Only consider nodes that actually have exported symbols.
@@ -206,6 +206,15 @@ fn exported_symbols_provider_local<'tcx>(
},
));
}
+
+ symbols.push((
+ ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)),
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Text,
+ used: false,
+ },
+ ));
}
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 68f3b19b7..d0ac016b0 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -2,11 +2,11 @@ use super::link::{self, ensure_removed};
use super::lto::{self, SerializedModule};
use super::symbol_export::symbol_name_for_instance_in_crate;
+use crate::errors;
+use crate::traits::*;
use crate::{
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
};
-
-use crate::traits::*;
use jobserver::{Acquired, Client};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::memmap::Mmap;
@@ -15,7 +15,10 @@ use rustc_data_structures::profiling::TimingGuard;
use rustc_data_structures::profiling::VerboseTimingGuard;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::Emitter;
-use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{
+ translation::{to_fluent_args, Translate},
+ DiagnosticId, FatalError, Handler, Level,
+};
use rustc_fs_util::link_or_copy;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_incremental::{
@@ -113,7 +116,6 @@ pub struct ModuleConfig {
pub vectorize_slp: bool,
pub merge_functions: bool,
pub inline_threshold: Option<u32>,
- pub new_llvm_pass_manager: Option<bool>,
pub emit_lifetime_markers: bool,
pub llvm_plugins: Vec<String>,
}
@@ -265,7 +267,6 @@ impl ModuleConfig {
},
inline_threshold: sess.opts.cg.inline_threshold,
- new_llvm_pass_manager: sess.opts.unstable_opts.new_llvm_pass_manager,
emit_lifetime_markers: sess.emit_lifetime_markers(),
llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]),
}
@@ -532,7 +533,7 @@ fn produce_final_output_artifacts(
// Produce final compile outputs.
let copy_gracefully = |from: &Path, to: &Path| {
if let Err(e) = fs::copy(from, to) {
- sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
+ sess.emit_err(errors::CopyPath::new(from, to, e));
}
};
@@ -548,7 +549,7 @@ fn produce_final_output_artifacts(
ensure_removed(sess.diagnostic(), &path);
}
} else {
- let ext = crate_output
+ let extension = crate_output
.temp_path(output_type, None)
.extension()
.unwrap()
@@ -559,19 +560,11 @@ fn produce_final_output_artifacts(
if crate_output.outputs.contains_key(&output_type) {
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
// no good solution for this case, so warn the user.
- sess.warn(&format!(
- "ignoring emit path because multiple .{} files \
- were produced",
- ext
- ));
+ sess.emit_warning(errors::IgnoringEmitPath { extension });
} else if crate_output.single_output_file.is_some() {
// 3) Multiple codegen units, with `-o some_name`. We have
// no good solution for this case, so warn the user.
- sess.warn(&format!(
- "ignoring -o because multiple .{} files \
- were produced",
- ext
- ));
+ sess.emit_warning(errors::IgnoringOutput { extension });
} else {
// 4) Multiple codegen units, but no explicit name. We
// just leave the `foo.0.x` files in place.
@@ -882,14 +875,12 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
);
match link_or_copy(&source_file, &output_path) {
Ok(_) => Some(output_path),
- Err(err) => {
- let diag_handler = cgcx.create_diag_handler();
- diag_handler.err(&format!(
- "unable to copy {} to {}: {}",
- source_file.display(),
- output_path.display(),
- err
- ));
+ Err(error) => {
+ cgcx.create_diag_handler().emit_err(errors::CopyPathBuf {
+ source_file,
+ output_path,
+ error,
+ });
None
}
}
@@ -1008,6 +999,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
let coordinator_send = tx_to_llvm_workers;
let sess = tcx.sess;
+ let mut each_linked_rlib_for_lto = Vec::new();
+ drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+ if link::ignored_for_lto(sess, crate_info, cnum) {
+ return;
+ }
+ each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
+ }));
+
// Compute the set of symbols we need to retain when doing LTO (if we need to)
let exported_symbols = {
let mut exported_symbols = FxHashMap::default();
@@ -1029,7 +1028,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
}
Lto::Fat | Lto::Thin => {
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
- for &cnum in tcx.crates(()).iter() {
+ for &(cnum, ref _path) in &each_linked_rlib_for_lto {
exported_symbols.insert(cnum, copy_symbols(cnum));
}
Some(Arc::new(exported_symbols))
@@ -1049,14 +1048,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
})
.expect("failed to spawn helper thread");
- let mut each_linked_rlib_for_lto = Vec::new();
- drop(link::each_linked_rlib(crate_info, &mut |cnum, path| {
- if link::ignored_for_lto(sess, crate_info, cnum) {
- return;
- }
- each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
- }));
-
let ol =
if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
// If we know that we won’t be doing codegen, create target machines without optimisation.
@@ -1639,7 +1630,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
) {
if config.time_module && llvm_start_time.is_none() {
- *llvm_start_time = Some(prof.extra_verbose_generic_activity("LLVM_passes", "crate"));
+ *llvm_start_time = Some(prof.verbose_generic_activity("LLVM_passes"));
}
}
}
@@ -1752,7 +1743,7 @@ impl Translate for SharedEmitter {
impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
- let fluent_args = self.to_fluent_args(diag.args());
+ let fluent_args = to_fluent_args(diag.args());
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
code: diag.code.clone(),