From 812f2d75e11a1acd52a4bfb201247c34a76c8e49 Mon Sep 17 00:00:00 2001 From: Matt Hammerly Date: Mon, 13 Mar 2023 20:55:43 -0700 Subject: [PATCH] add "force" option to --extern --- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_metadata/src/creader.rs | 14 +++++++++++++- compiler/rustc_session/src/config.rs | 18 +++++++++++++++++- .../ui/extern-flag/auxiliary/panic_handler.rs | 17 +++++++++++++++++ tests/ui/extern-flag/force-extern.rs | 9 +++++++++ tests/ui/extern-flag/no-force-extern.rs | 10 ++++++++++ tests/ui/extern-flag/redundant-force-extern.rs | 11 +++++++++++ 7 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/ui/extern-flag/auxiliary/panic_handler.rs create mode 100644 tests/ui/extern-flag/force-extern.rs create mode 100644 tests/ui/extern-flag/no-force-extern.rs create mode 100644 tests/ui/extern-flag/redundant-force-extern.rs diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a0c576234f96b..854d974d87f34 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -69,6 +69,7 @@ where is_private_dep: false, add_prelude: true, nounused_dep: false, + force: false, } } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 01b69966ca92c..e6e7d25773e67 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -865,6 +865,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } + fn inject_forced_externs(&mut self) { + for (name, entry) in self.sess.opts.externs.iter() { + if entry.force { + let name_interned = Symbol::intern(name); + if !self.used_extern_options.contains(&name_interned) { + self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit); + } + } + } + } + fn inject_dependency_if( &self, krate: CrateNum, @@ -913,7 +924,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Don't worry about pathless `--extern foo` sysroot references continue; } - if entry.nounused_dep { + if entry.nounused_dep || entry.force { // We're not worried about this one continue; } @@ -942,6 +953,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } pub fn postprocess(&mut self, krate: &ast::Crate) { + self.inject_forced_externs(); self.inject_profiler_runtime(krate); self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 18917120256e0..d80cc0aa04374 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -518,6 +518,12 @@ pub struct ExternEntry { /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to /// suppress `unused-crate-dependencies` warnings. pub nounused_dep: bool, + /// If the extern entry is not referenced in the crate, force it to be resolved anyway. + /// + /// Allows a dependency satisfying, for instance, a missing panic handler to be injected + /// without modifying source: + /// `--extern force:extras=/path/to/lib/libstd.rlib` + pub force: bool, } #[derive(Clone, Debug)] @@ -556,7 +562,13 @@ impl Externs { impl ExternEntry { fn new(location: ExternLocation) -> ExternEntry { - ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false } + ExternEntry { + location, + is_private_dep: false, + add_prelude: false, + nounused_dep: false, + force: false, + } } pub fn files(&self) -> Option> { @@ -2261,6 +2273,7 @@ pub fn parse_externs( let mut is_private_dep = false; let mut add_prelude = true; let mut nounused_dep = false; + let mut force = false; if let Some(opts) = options { if !is_unstable_enabled { early_error( @@ -2283,6 +2296,7 @@ pub fn parse_externs( } } "nounused" => nounused_dep = true, + "force" => force = true, _ => early_error(error_format, &format!("unknown --extern option `{opt}`")), } } @@ -2293,6 +2307,8 @@ pub fn parse_externs( entry.is_private_dep |= is_private_dep; // likewise `nounused` entry.nounused_dep |= nounused_dep; + // and `force` + entry.force |= force; // If any flag is missing `noprelude`, then add to the prelude. entry.add_prelude |= add_prelude; } diff --git a/tests/ui/extern-flag/auxiliary/panic_handler.rs b/tests/ui/extern-flag/auxiliary/panic_handler.rs new file mode 100644 index 0000000000000..a625761a838a8 --- /dev/null +++ b/tests/ui/extern-flag/auxiliary/panic_handler.rs @@ -0,0 +1,17 @@ +#![feature(lang_items)] +#![no_std] + +// Since `rustc` generally passes `-nodefaultlibs` to the linker, +// Rust programs link necessary system libraries via `#[link()]` +// attributes in the `libc` crate. `libc` is a dependency of `std`, +// but as we are `#![no_std]`, we need to include it manually. +#![feature(rustc_private)] +extern crate libc; + +#[panic_handler] +pub fn begin_panic_handler(_info: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} diff --git a/tests/ui/extern-flag/force-extern.rs b/tests/ui/extern-flag/force-extern.rs new file mode 100644 index 0000000000000..f56b5378223f2 --- /dev/null +++ b/tests/ui/extern-flag/force-extern.rs @@ -0,0 +1,9 @@ +// check-pass +// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header) +// aux-crate:force:panic_handler=panic_handler.rs +// compile-flags: -Zunstable-options --crate-type dylib +// edition:2018 + +#![no_std] + +fn foo() {} diff --git a/tests/ui/extern-flag/no-force-extern.rs b/tests/ui/extern-flag/no-force-extern.rs new file mode 100644 index 0000000000000..ce9cbfe1cd27a --- /dev/null +++ b/tests/ui/extern-flag/no-force-extern.rs @@ -0,0 +1,10 @@ +// aux-crate:panic_handler=panic_handler.rs +// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header) +// compile_flags: -Zunstable-options --crate-type dylib +// error-pattern: `#[panic_handler]` function required, but not found +// dont-check-compiler-stderr +// edition: 2018 + +#![no_std] + +fn foo() {} diff --git a/tests/ui/extern-flag/redundant-force-extern.rs b/tests/ui/extern-flag/redundant-force-extern.rs new file mode 100644 index 0000000000000..a4091616dd569 --- /dev/null +++ b/tests/ui/extern-flag/redundant-force-extern.rs @@ -0,0 +1,11 @@ +// check-pass +// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header) +// aux-crate:force:panic_handler=panic_handler.rs +// compile-flags: -Zunstable-options --crate-type dylib +// edition:2018 + +#![no_std] + +extern crate panic_handler; + +fn foo() {}