Skip to content

Commit d2f3cdb

Browse files
authored
Rollup merge of rust-lang#119592 - petrochenkov:unload, r=compiler-errors
resolve: Unload speculatively resolved crates before freezing cstore Name resolution sometimes loads additional crates to improve diagnostics (e.g. suggest imports). Not all of these diagnostics result in errors, sometimes they are just warnings, like in rust-lang#117772. If additional crates loaded speculatively stay and gets listed by things like `query crates` then they may produce further errors like duplicated lang items, because lang items from speculatively loaded crates are as good as from non-speculatively loaded crates. They can probably do things like adding unintended impls from speculatively loaded crates to method resolution as well. The extra crates will also get into the crate's metadata as legitimate dependencies. In this PR I remove the speculative crates from cstore when name resolution is finished and cstore is frozen. This is better than e.g. filtering away speculative crates in `query crates` because things like `DefId`s referring to these crates and leaking to later compilation stages can produce ICEs much easier, allowing to detect them. The unloading could potentially be skipped if any errors were reported (to allow using `DefId`s from speculatively loaded crates for recovery), but I didn't do it in this PR because I haven't seen such cases of recovery. We can reconsider later if any relevant ICEs are reported. Unblocks rust-lang#117772.
2 parents 8ace7ea + a2ab48c commit d2f3cdb

File tree

6 files changed

+52
-16
lines changed

6 files changed

+52
-16
lines changed

Diff for: compiler/rustc_metadata/src/creader.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
534534
) -> Option<CrateNum> {
535535
self.used_extern_options.insert(name);
536536
match self.maybe_resolve_crate(name, dep_kind, None) {
537-
Ok(cnum) => Some(cnum),
537+
Ok(cnum) => {
538+
self.cstore.set_used_recursively(cnum);
539+
Some(cnum)
540+
}
538541
Err(err) => {
539542
let missing_core =
540543
self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
@@ -1067,6 +1070,16 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
10671070
pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
10681071
self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
10691072
}
1073+
1074+
pub fn unload_unused_crates(&mut self) {
1075+
for opt_cdata in &mut self.cstore.metas {
1076+
if let Some(cdata) = opt_cdata
1077+
&& !cdata.used()
1078+
{
1079+
*opt_cdata = None;
1080+
}
1081+
}
1082+
}
10701083
}
10711084

10721085
fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {

Diff for: compiler/rustc_metadata/src/rmeta/decoder.rs

+7
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ pub(crate) struct CrateMetadata {
106106
private_dep: bool,
107107
/// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
108108
host_hash: Option<Svh>,
109+
/// The crate was used non-speculatively.
110+
used: bool,
109111

110112
/// Additional data used for decoding `HygieneData` (e.g. `SyntaxContext`
111113
/// and `ExpnId`).
@@ -1811,6 +1813,7 @@ impl CrateMetadata {
18111813
source: Lrc::new(source),
18121814
private_dep,
18131815
host_hash,
1816+
used: false,
18141817
extern_crate: None,
18151818
hygiene_context: Default::default(),
18161819
def_key_cache: Default::default(),
@@ -1860,6 +1863,10 @@ impl CrateMetadata {
18601863
self.private_dep &= private_dep;
18611864
}
18621865

1866+
pub(crate) fn used(&self) -> bool {
1867+
self.used
1868+
}
1869+
18631870
pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> {
18641871
self.root.required_panic_strategy
18651872
}

Diff for: compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_span::symbol::{kw, Symbol};
2626
use rustc_span::Span;
2727

2828
use std::any::Any;
29+
use std::mem;
2930

3031
use super::{Decodable, DecodeContext, DecodeIterator};
3132

@@ -576,12 +577,24 @@ impl CStore {
576577
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
577578
}
578579

580+
pub fn set_used_recursively(&mut self, cnum: CrateNum) {
581+
let cmeta = self.get_crate_data_mut(cnum);
582+
if !cmeta.used {
583+
cmeta.used = true;
584+
let dependencies = mem::take(&mut cmeta.dependencies);
585+
for &dep_cnum in &dependencies {
586+
self.set_used_recursively(dep_cnum);
587+
}
588+
self.get_crate_data_mut(cnum).dependencies = dependencies;
589+
}
590+
}
591+
579592
pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) {
580593
let cmeta = self.get_crate_data_mut(cnum);
581594
if cmeta.update_extern_crate(extern_crate) {
582595
// Propagate the extern crate info to dependencies if it was updated.
583596
let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
584-
let dependencies = std::mem::take(&mut cmeta.dependencies);
597+
let dependencies = mem::take(&mut cmeta.dependencies);
585598
for &dep_cnum in &dependencies {
586599
self.update_extern_crate(dep_cnum, extern_crate);
587600
}

Diff for: compiler/rustc_resolve/src/late.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_hir::def::Namespace::{self, *};
2323
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
2424
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
2525
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
26+
use rustc_metadata::creader::CStore;
2627
use rustc_middle::middle::resolve_bound_vars::Set1;
2728
use rustc_middle::{bug, span_bug};
2829
use rustc_session::config::{CrateType, ResolveDocLinks};
@@ -4547,14 +4548,20 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
45474548
if let Some(res) = res
45484549
&& let Some(def_id) = res.opt_def_id()
45494550
&& !def_id.is_local()
4550-
&& self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
4551-
&& matches!(
4552-
self.r.tcx.sess.opts.resolve_doc_links,
4553-
ResolveDocLinks::ExportedMetadata
4554-
)
45554551
{
4556-
// Encoding foreign def ids in proc macro crate metadata will ICE.
4557-
return None;
4552+
if self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
4553+
&& matches!(
4554+
self.r.tcx.sess.opts.resolve_doc_links,
4555+
ResolveDocLinks::ExportedMetadata
4556+
)
4557+
{
4558+
// Encoding foreign def ids in proc macro crate metadata will ICE.
4559+
return None;
4560+
}
4561+
// Doc paths should be resolved speculatively and should not produce any
4562+
// diagnostics, but if they are indeed resolved, then we need to keep the
4563+
// corresponding crate alive.
4564+
CStore::from_tcx_mut(self.r.tcx).set_used_recursively(def_id.krate);
45584565
}
45594566
res
45604567
});

Diff for: compiler/rustc_resolve/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16291629
self.tcx
16301630
.sess
16311631
.time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate)));
1632+
self.crate_loader(|c| c.unload_unused_crates());
16321633
});
16331634

16341635
// Make sure we don't mutate the cstore from here on.

Diff for: tests/ui/extern-flag/empty-extern-arg.stderr

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
error: extern location for std does not exist:
22

3-
error: `#[panic_handler]` function required, but not found
3+
error: requires `sized` lang_item
44

5-
error: unwinding panics are not supported without std
6-
|
7-
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
8-
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
9-
10-
error: aborting due to 3 previous errors
5+
error: aborting due to 2 previous errors
116

0 commit comments

Comments
 (0)