diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 3522ea0115334..90520f77e3c04 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -15,6 +15,7 @@ use rustc_session::{ }; use rustc_span::symbol::Symbol; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; @@ -54,6 +55,12 @@ pub trait CodegenBackend { fn print_passes(&self) {} fn print_version(&self) {} + /// If this plugin provides additional builtin targets, provide the one enabled by the options here. + /// Be careful: this is called *before* init() is called. + fn target_override(&self, _opts: &config::Options) -> Option { + None + } + fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers); fn provide_extern(&self, _providers: &mut Providers); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index dc4fa807f7868..72e10bc4304d0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -40,6 +40,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { DiagnosticOutput::Default, Default::default(), None, + None, ); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f15eb413833ae..0eed6938c3169 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -65,6 +65,10 @@ pub fn create_session( lint_caps: FxHashMap, descriptions: Registry, ) -> (Lrc, Lrc>) { + let codegen_backend = get_codegen_backend(&sopts); + // target_override is documented to be called before init(), so this is okay + let target_override = codegen_backend.target_override(&sopts); + let mut sess = session::build_session( sopts, input_path, @@ -72,9 +76,10 @@ pub fn create_session( diagnostic_output, lint_caps, file_loader, + target_override, ); - let codegen_backend = get_codegen_backend(&sess); + codegen_backend.init(&sess); let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &mut sess, &*codegen_backend); @@ -219,13 +224,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_codegen_backend(sess: &Session) -> Box { +pub fn get_codegen_backend(sopts: &config::Options) -> Box { static INIT: Once = Once::new(); static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); + let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); let backend = match codegen_name { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), codegen_name => get_builtin_codegen_backend(codegen_name), @@ -235,9 +240,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box { LOAD = backend; } }); - let backend = unsafe { LOAD() }; - backend.init(sess); - backend + unsafe { LOAD() } } // This is used for rustdoc, but it uses similar machinery to codegen backend diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3f12596a236ab..8d004675d7f4d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -818,10 +818,11 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config { - let target = Target::search(&opts.target_triple).unwrap_or_else(|e| { +pub fn build_target_config(opts: &Options, target_override: Option) -> Config { + let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); + let target = target_result.unwrap_or_else(|e| { early_error( - error_format, + opts.error_format, &format!( "Error loading target specification: {}. \ Use `--print target-list` for a list of built-in targets", @@ -835,7 +836,7 @@ pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Con "32" => 32, "64" => 64, w => early_error( - error_format, + opts.error_format, &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 974f4c31bb6a4..ff67d3cb107d9 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1234,6 +1234,7 @@ pub fn build_session( diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap, file_loader: Option>, + target_override: Option, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1253,7 +1254,7 @@ pub fn build_session( DiagnosticOutput::Raw(write) => Some(write), }; - let target_cfg = config::build_target_config(&sopts, sopts.error_format); + let target_cfg = config::build_target_config(&sopts, target_override); let host_triple = TargetTriple::from_triple(config::host_triple()); let host = Target::search(&host_triple).unwrap_or_else(|e| { early_error(sopts.error_format, &format!("Error loading host specification: {}", e))