Skip to content

Add force option for --extern flag #109421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 6, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
@@ -69,6 +69,7 @@ where
is_private_dep: false,
add_prelude: true,
nounused_dep: false,
force: false,
}
}

14 changes: 13 additions & 1 deletion compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
@@ -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);
18 changes: 17 additions & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
@@ -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<impl Iterator<Item = &CanonicalizedPath>> {
@@ -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;
}
17 changes: 17 additions & 0 deletions tests/ui/extern-flag/auxiliary/panic_handler.rs
Original file line number Diff line number Diff line change
@@ -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() {}
9 changes: 9 additions & 0 deletions tests/ui/extern-flag/force-extern.rs
Original file line number Diff line number Diff line change
@@ -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() {}
10 changes: 10 additions & 0 deletions tests/ui/extern-flag/no-force-extern.rs
Original file line number Diff line number Diff line change
@@ -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() {}
11 changes: 11 additions & 0 deletions tests/ui/extern-flag/redundant-force-extern.rs
Original file line number Diff line number Diff line change
@@ -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() {}