1
Fork 0

Rollup merge of #134514 - bjorn3:more_driver_refactors, r=jieyouxu

Improve dependency_format a bit

* Make `DependencyList` an `IndexVec` rather than emulating one using a `Vec` (which was off-by-one as LOCAL_CRATE was intentionally skipped)
* Update some comments for the fact that we now use `#[global_allocator]` rather than `extern crate alloc_system;`/`extern crate alloc_jemalloc;` for specifying which allocator to use. We still use a similar mechanism for the panic runtime, so refer to the panic runtime in those comments instead.
* An unrelated refactor to `create_and_enter_global_ctxt` I forgot to include in https://github.com/rust-lang/rust/pull/134302. This refactor is too small to be worth it's own PR.
This commit is contained in:
DianQK 2024-12-20 21:47:00 +08:00 committed by GitHub
commit 350e7f858e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 100 additions and 86 deletions

View file

@ -294,7 +294,7 @@ fn dep_symbol_lookup_fn(
// search path.
for &cnum in crate_info.used_crates.iter().rev() {
let src = &crate_info.used_crate_source[&cnum];
match data[cnum.as_usize() - 1] {
match data[cnum] {
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
Linkage::Static => {
let name = crate_info.crate_name[&cnum];

View file

@ -234,8 +234,6 @@ pub fn each_linked_rlib(
crate_type: Option<CrateType>,
f: &mut dyn FnMut(CrateNum, &Path),
) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
let fmts = if let Some(crate_type) = crate_type {
let Some(fmts) = info.dependency_formats.get(&crate_type) else {
return Err(errors::LinkRlibError::MissingFormat);
@ -261,8 +259,9 @@ pub fn each_linked_rlib(
info.dependency_formats.first().unwrap().1
};
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
let used_dep_crates = info.used_crates.iter();
for &cnum in used_dep_crates {
match fmts.get(cnum) {
Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
Some(_) => {}
None => return Err(errors::LinkRlibError::MissingFormat),
@ -624,7 +623,7 @@ fn link_staticlib(
let mut all_rust_dylibs = vec![];
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
match fmts.get(cnum) {
Some(&Linkage::Dynamic) => {}
_ => continue,
}
@ -2361,8 +2360,8 @@ fn linker_with_args(
.crate_info
.native_libraries
.iter()
.filter_map(|(cnum, libraries)| {
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then_some(libraries)
.filter_map(|(&cnum, libraries)| {
(dependency_linkage[cnum] != Linkage::Static).then_some(libraries)
})
.flatten()
.collect::<Vec<_>>();
@ -2754,7 +2753,7 @@ fn add_upstream_rust_crates(
// (e.g. `libstd` when `-C prefer-dynamic` is used).
// FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some
// reason, it shouldn't do that because `profiler_builtins` should indeed be linked.
let linkage = data[cnum.as_usize() - 1];
let linkage = data[cnum];
let link_static_crate = linkage == Linkage::Static
|| (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked)
&& (codegen_results.crate_info.compiler_builtins == Some(cnum)

View file

@ -1744,15 +1744,10 @@ fn for_each_exported_symbols_include_dep<'tcx>(
crate_type: CrateType,
mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
) {
for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() {
callback(symbol, info, LOCAL_CRATE);
}
let formats = tcx.dependency_formats(());
let deps = &formats[&crate_type];
for (index, dep_format) in deps.iter().enumerate() {
let cnum = CrateNum::new(index + 1);
for (cnum, dep_format) in deps.iter_enumerated() {
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
for &(symbol, info) in tcx.exported_symbols(cnum).iter() {

View file

@ -19,7 +19,7 @@ use rustc_incremental::setup_dep_graph;
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_middle::util::Providers;
use rustc_parse::{
new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
@ -770,15 +770,14 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
// subtyping for GlobalCtxt::enter to be allowed.
let inner: Box<
dyn for<'tcx> FnOnce(
&'tcx Compiler,
&'tcx Session,
CurrentGcx,
&'tcx OnceLock<GlobalCtxt<'tcx>>,
&'tcx WorkerLocal<Arena<'tcx>>,
&'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
F,
) -> T,
> = Box::new(move |compiler, gcx_cell, arena, hir_arena, f| {
let sess = &compiler.sess;
> = Box::new(move |sess, current_gcx, gcx_cell, arena, hir_arena, f| {
TyCtxt::create_global_ctxt(
gcx_cell,
sess,
@ -796,7 +795,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
incremental,
),
providers.hooks,
compiler.current_gcx.clone(),
current_gcx,
|tcx| {
let feed = tcx.create_crate_num(stable_crate_id).unwrap();
assert_eq!(feed.key(), LOCAL_CRATE);
@ -804,7 +803,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
let feed = tcx.feed_unit_query();
feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
sess,
tcx.sess,
&pre_configured_attrs,
crate_name,
)));
@ -819,7 +818,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
)
});
inner(compiler, &gcx_cell, &arena, &hir_arena, f)
inner(&compiler.sess, compiler.current_gcx.clone(), &gcx_cell, &arena, &hir_arena, f)
}
/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.

View file

@ -52,7 +52,8 @@
//! than finding a number of solutions (there are normally quite a few).
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::CrateNum;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
use rustc_middle::ty::TyCtxt;
@ -84,7 +85,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
let sess = &tcx.sess;
if !sess.opts.output_types.should_codegen() {
return Vec::new();
return IndexVec::new();
}
let preferred_linkage = match ty {
@ -131,7 +132,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
match preferred_linkage {
// If the crate is not linked, there are no link-time dependencies.
Linkage::NotLinked => return Vec::new(),
Linkage::NotLinked => return IndexVec::new(),
Linkage::Static => {
// Attempt static linkage first. For dylibs and executables, we may be
// able to retry below with dynamic linkage.
@ -156,7 +157,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
}
sess.dcx().emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) });
}
return Vec::new();
return IndexVec::new();
}
}
Linkage::Dynamic | Linkage::IncludedFromDylib => {}
@ -210,19 +211,32 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
// Collect what we've got so far in the return vector.
let last_crate = tcx.crates(()).len();
let mut ret = (1..last_crate + 1)
.map(|cnum| match formats.get(&CrateNum::new(cnum)) {
let mut ret = IndexVec::new();
// We need to fill in something for LOCAL_CRATE as IndexVec is a dense map.
// Linkage::Static semantically the most correct thing to use as the local
// crate is always statically linked into the linker output, even when
// linking a dylib. Using Linkage::Static also allow avoiding special cases
// for LOCAL_CRATE in some places.
assert_eq!(ret.push(Linkage::Static), LOCAL_CRATE);
for cnum in 1..last_crate + 1 {
let cnum = CrateNum::new(cnum);
assert_eq!(
ret.push(match formats.get(&cnum) {
Some(&RequireDynamic) => Linkage::Dynamic,
Some(&RequireStatic) => Linkage::IncludedFromDylib,
None => Linkage::NotLinked,
})
.collect::<Vec<_>>();
}),
cnum
);
}
// Run through the dependency list again, and add any missing libraries as
// static libraries.
//
// If the crate hasn't been included yet and it's not actually required
// (e.g., it's an allocator) then we skip it here as well.
// (e.g., it's a panic runtime) then we skip it here as well.
for &cnum in tcx.crates(()).iter() {
let src = tcx.used_crate_source(cnum);
if src.dylib.is_none()
@ -232,7 +246,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
assert!(src.rlib.is_some() || src.rmeta.is_some());
info!("adding staticlib: {}", tcx.crate_name(cnum));
add_library(tcx, cnum, RequireStatic, &mut formats, &mut unavailable_as_static);
ret[cnum.as_usize() - 1] = Linkage::Static;
ret[cnum] = Linkage::Static;
}
}
@ -240,8 +254,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
// artifact which means that we may need to inject dependencies of some
// form.
//
// Things like allocators and panic runtimes may not have been activated
// quite yet, so do so here.
// Things like panic runtimes may not have been activated quite yet, so do so here.
activate_injected_dep(CStore::from_tcx(tcx).injected_panic_runtime(), &mut ret, &|cnum| {
tcx.is_panic_runtime(cnum)
});
@ -252,8 +265,10 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
//
// For situations like this, we perform one last pass over the dependencies,
// making sure that everything is available in the requested format.
for (cnum, kind) in ret.iter().enumerate() {
let cnum = CrateNum::new(cnum + 1);
for (cnum, kind) in ret.iter_enumerated() {
if cnum == LOCAL_CRATE {
continue;
}
let src = tcx.used_crate_source(cnum);
match *kind {
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
@ -334,18 +349,21 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De
// All crates are available in an rlib format, so we're just going to link
// everything in explicitly so long as it's actually required.
let mut ret = tcx
.crates(())
.iter()
.map(|&cnum| match tcx.dep_kind(cnum) {
let mut ret = IndexVec::new();
assert_eq!(ret.push(Linkage::Static), LOCAL_CRATE);
for &cnum in tcx.crates(()) {
assert_eq!(
ret.push(match tcx.dep_kind(cnum) {
CrateDepKind::Explicit => Linkage::Static,
CrateDepKind::MacrosOnly | CrateDepKind::Implicit => Linkage::NotLinked,
})
.collect::<Vec<_>>();
}),
cnum
);
}
// Our allocator/panic runtime may not have been linked above if it wasn't
// explicitly linked, which is the case for any injected dependency. Handle
// that here and activate them.
// Our panic runtime may not have been linked above if it wasn't explicitly
// linked, which is the case for any injected dependency. Handle that here
// and activate it.
activate_injected_dep(CStore::from_tcx(tcx).injected_panic_runtime(), &mut ret, &|cnum| {
tcx.is_panic_runtime(cnum)
});
@ -367,8 +385,7 @@ fn activate_injected_dep(
list: &mut DependencyList,
replaces_injected: &dyn Fn(CrateNum) -> bool,
) {
for (i, slot) in list.iter().enumerate() {
let cnum = CrateNum::new(i + 1);
for (cnum, slot) in list.iter_enumerated() {
if !replaces_injected(cnum) {
continue;
}
@ -377,25 +394,23 @@ fn activate_injected_dep(
}
}
if let Some(injected) = injected {
let idx = injected.as_usize() - 1;
assert_eq!(list[idx], Linkage::NotLinked);
list[idx] = Linkage::Static;
assert_eq!(list[injected], Linkage::NotLinked);
list[injected] = Linkage::Static;
}
}
// After the linkage for a crate has been determined we need to verify that
// there's only going to be one allocator in the output.
fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
/// After the linkage for a crate has been determined we need to verify that
/// there's only going to be one panic runtime in the output.
fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
let sess = &tcx.sess;
if list.is_empty() {
return;
}
let mut panic_runtime = None;
for (i, linkage) in list.iter().enumerate() {
for (cnum, linkage) in list.iter_enumerated() {
if let Linkage::NotLinked = *linkage {
continue;
}
let cnum = CrateNum::new(i + 1);
if tcx.is_panic_runtime(cnum) {
if let Some((prev, _)) = panic_runtime {
@ -431,11 +446,10 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
// strategy. If the dep isn't linked, we ignore it, and if our strategy
// is abort then it's compatible with everything. Otherwise all crates'
// panic strategy must match our own.
for (i, linkage) in list.iter().enumerate() {
for (cnum, linkage) in list.iter_enumerated() {
if let Linkage::NotLinked = *linkage {
continue;
}
let cnum = CrateNum::new(i + 1);
if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
continue;
}
@ -450,6 +464,8 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
});
}
// panic_in_drop_strategy isn't allowed for LOCAL_CRATE
if cnum != LOCAL_CRATE {
let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy {
sess.dcx().emit_err(IncompatiblePanicInDropStrategy {
@ -461,3 +477,4 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
}
}
}
}

View file

@ -1474,7 +1474,7 @@ impl<'a> CrateMetadataRef<'a> {
) -> &'tcx [(CrateNum, LinkagePreference)] {
tcx.arena.alloc_from_iter(
self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| {
let cnum = CrateNum::new(i + 1);
let cnum = CrateNum::new(i + 1); // We skipped LOCAL_CRATE when encoding
link.map(|link| (self.cnum_map[cnum], link))
}),
)

View file

@ -2165,12 +2165,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
empty_proc_macro!(self);
let formats = self.tcx.dependency_formats(());
if let Some(arr) = formats.get(&CrateType::Dylib) {
return self.lazy_array(arr.iter().map(|slot| match *slot {
return self.lazy_array(arr.iter().skip(1 /* skip LOCAL_CRATE */).map(
|slot| match *slot {
Linkage::NotLinked | Linkage::IncludedFromDylib => None,
Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
Linkage::Static => Some(LinkagePreference::RequireStatic),
}));
},
));
}
LazyArray::default()
}

View file

@ -8,13 +8,13 @@
// this will introduce circular dependency between rustc_metadata and rustc_middle
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::CrateNum;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_session::config::CrateType;
/// A list of dependencies for a certain crate type.
///
/// The length of this vector is the same as the number of external crates used.
pub type DependencyList = Vec<Linkage>;
pub type DependencyList = IndexVec<CrateNum, Linkage>;
/// A mapping of all required dependencies for a particular flavor of output.
///

View file

@ -42,7 +42,7 @@ pub enum CrateDepKind {
/// A dependency that is only used for its macros.
MacrosOnly,
/// A dependency that is always injected into the dependency list and so
/// doesn't need to be linked to an rlib, e.g., the injected allocator.
/// doesn't need to be linked to an rlib, e.g., the injected panic runtime.
Implicit,
/// A dependency that is required by an rlib version of this crate.
/// Ordinary `extern crate`s result in `Explicit` dependencies.

View file

@ -152,12 +152,14 @@ pub fn iter_exported_symbols<'tcx>(
let dependency_format = dependency_formats
.get(&CrateType::Executable)
.expect("interpreting a non-executable crate");
for cnum in dependency_format.iter().enumerate().filter_map(|(num, &linkage)| {
// We add 1 to the number because that's what rustc also does everywhere it
// calls `CrateNum::new`...
#[expect(clippy::arithmetic_side_effects)]
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
}) {
for cnum in dependency_format
.iter_enumerated()
.filter_map(|(num, &linkage)| (linkage != Linkage::NotLinked).then_some(num))
{
if cnum == LOCAL_CRATE {
continue; // Already handled above
}
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
// from a Rust crate.
for &(symbol, _export_info) in tcx.exported_symbols(cnum) {