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;
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,
pub fn each_linked_rlib(
info: &CrateInfo,
f: &mut dyn FnMut(CrateNum, &Path),
-) -> Result<(), String> {
+) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
let mut fmts = None;
for (ty, list) in info.dependency_formats.iter() {
}
}
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 });
}
}
}
// -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), .. }
));
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.to_string_lossy(),
+ error,
+ });
});
}
}
tmpdir.as_ref(),
);
- 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.display().to_string(),
+ error,
+ });
});
}
// 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,
+ });
}
}
}
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);
}) {
Ok(()) => {}
Err(e) => {
- sess.struct_err("linking dwarf objects with thorin failed")
- .note(&format!("{:?}", e))
- .emit();
+ let thorin_error = errors::ThorinErrorWrapper(e);
+ sess.emit_err(errors::ThorinDwarfLinking { thorin_error });
sess.abort_if_errors();
}
}
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.
//! Errors emitted by codegen_ssa
-use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
+use crate::back::command::Command;
+use rustc_errors::{
+ fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+ IntoDiagnosticArg,
+};
use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
use std::borrow::Cow;
use std::io::Error;
use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
#[derive(Diagnostic)]
#[diag(codegen_ssa::lib_def_write_failure)]
impl<'a> CopyPath<'a> {
pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
- CopyPath { from: DebugArgPath { path: from }, to: DebugArgPath { path: to }, error }
+ CopyPath { from: DebugArgPath(from), to: DebugArgPath(to), error }
}
}
-struct DebugArgPath<'a> {
- pub path: &'a Path,
-}
+struct DebugArgPath<'a>(pub &'a Path);
impl IntoDiagnosticArg for DebugArgPath<'_> {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.path)))
+ DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
}
}
pub struct IgnoringOutput {
pub extension: String,
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::create_temp_dir)]
+pub struct CreateTempDir {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::incompatible_linking_modifiers)]
+pub struct IncompatibleLinkingModifiers;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::add_native_library)]
+pub struct AddNativeLibrary<'a> {
+ pub library_path: &'a str,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::multiple_external_func_decl)]
+pub struct MultipleExternalFuncDecl<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub function: Symbol,
+ pub library_name: &'a str,
+}
+
+pub enum LinkRlibError {
+ MissingFormat,
+ OnlyRmetaFound { crate_name: Symbol },
+ NotFound { crate_name: Symbol },
+}
+
+impl IntoDiagnostic<'_, !> for LinkRlibError {
+ fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
+ match self {
+ LinkRlibError::MissingFormat => {
+ handler.struct_fatal(fluent::codegen_ssa::rlib_missing_format)
+ }
+ LinkRlibError::OnlyRmetaFound { crate_name } => {
+ let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_only_rmeta_found);
+ diag.set_arg("crate_name", crate_name);
+ diag
+ }
+ LinkRlibError::NotFound { crate_name } => {
+ let mut diag = handler.struct_fatal(fluent::codegen_ssa::rlib_not_found);
+ diag.set_arg("crate_name", crate_name);
+ diag
+ }
+ }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa::thorin_dwarf_linking)]
+#[note]
+pub struct ThorinDwarfLinking {
+ pub thorin_error: ThorinErrorWrapper,
+}
+pub struct ThorinErrorWrapper(pub thorin::Error);
+
+// FIXME: How should we support translations for external crate errors?
+impl IntoDiagnosticArg for ThorinErrorWrapper {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
+ }
+}
+
+pub struct LinkingFailed<'a> {
+ pub linker_path: &'a PathBuf,
+ pub exit_status: ExitStatus,
+ pub command: &'a Command,
+ pub escaped_output: &'a str,
+}
+
+impl IntoDiagnostic<'_> for LinkingFailed<'_> {
+ fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
+ diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
+ diag.set_arg("exit_status", format!("{}", self.exit_status));
+
+ diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+
+ // Trying to match an error from OS linkers
+ // which by now we have no way to translate.
+ if self.escaped_output.contains("undefined reference to") {
+ diag.note(fluent::codegen_ssa::extern_funcs_not_found)
+ .note(fluent::codegen_ssa::specify_libraries_to_link)
+ .note(fluent::codegen_ssa::use_cargo_directive);
+ }
+ diag
+ }
+}