Skip to content

Commit dac2e3e

Browse files
committed
Fix cycles during delayed lowering
1 parent 37cfa17 commit dac2e3e

14 files changed

Lines changed: 296 additions & 60 deletions

File tree

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
437437
// also nested delegations may need to access information about this code (#154332),
438438
// so it is better to leave this code as opposed to bodies of extern functions,
439439
// which are completely erased from existence.
440+
// FIXME(fn_delegation): fix `help` in error message (see `inner-attr.stderr`)
440441
if param_count == 0
441442
&& let Some(block) = block
442443
{

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub(super) enum Owners<'a, 'hir> {
3838
}
3939

4040
impl<'hir> Owners<'_, 'hir> {
41-
fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
41+
pub(super) fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
4242
match self {
4343
Owners::IndexVec(index_vec) => {
4444
index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use std::mem;
3939
use std::sync::Arc;
4040

4141
use rustc_ast::node_id::NodeMap;
42+
use rustc_ast::visit::AssocCtxt;
4243
use rustc_ast::{self as ast, *};
4344
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
4445
use rustc_data_structures::fingerprint::Fingerprint;
@@ -633,13 +634,29 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
633634
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
634635

635636
for def_id in ast_index.indices() {
636-
match &ast_index[def_id] {
637-
AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
638-
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
639-
delayed_ids.insert(def_id);
637+
let delayed_owner_kind = match &ast_index[def_id] {
638+
AstOwner::Item(Item { kind: ItemKind::Delegation(_), .. }) => {
639+
Some(hir::DelayedOwnerKind::Item)
640640
}
641-
_ => lowerer.lower_node(def_id),
641+
AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(_), .. }, ctx) => {
642+
Some(match ctx {
643+
AssocCtxt::Trait => hir::DelayedOwnerKind::TraitItem,
644+
AssocCtxt::Impl { .. } => hir::DelayedOwnerKind::ImplItem,
645+
})
646+
}
647+
_ => None,
642648
};
649+
650+
if let Some(kind) = delayed_owner_kind {
651+
delayed_ids.insert(def_id);
652+
653+
let owner = lowerer.owners.get_or_insert_mut(def_id);
654+
if let hir::MaybeOwner::Phantom = owner {
655+
*owner = hir::MaybeOwner::Delayed(kind)
656+
}
657+
} else {
658+
lowerer.lower_node(def_id);
659+
}
643660
}
644661

645662
// Don't hash unless necessary, because it's expensive.

compiler/rustc_hir/src/hir.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,10 +1641,18 @@ impl<'tcx> OwnerInfo<'tcx> {
16411641
}
16421642
}
16431643

1644+
#[derive(Copy, Clone, Debug, HashStable_Generic)]
1645+
pub enum DelayedOwnerKind {
1646+
Item,
1647+
ImplItem,
1648+
TraitItem,
1649+
}
1650+
16441651
#[derive(Copy, Clone, Debug, HashStable_Generic)]
16451652
pub enum MaybeOwner<'tcx> {
16461653
Owner(&'tcx OwnerInfo<'tcx>),
16471654
NonOwner(HirId),
1655+
Delayed(DelayedOwnerKind),
16481656
/// Used as a placeholder for unused LocalDefId.
16491657
Phantom,
16501658
}
@@ -1653,12 +1661,19 @@ impl<'tcx> MaybeOwner<'tcx> {
16531661
pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> {
16541662
match self {
16551663
MaybeOwner::Owner(i) => Some(i),
1656-
MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None,
1664+
_ => None,
16571665
}
16581666
}
16591667

16601668
pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
1661-
self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner"))
1669+
self.as_owner().unwrap_or_else(|| panic!("not a HIR owner"))
1670+
}
1671+
1672+
pub fn expect_delayed(self) -> DelayedOwnerKind {
1673+
match self {
1674+
MaybeOwner::Delayed(delayed_owner) => delayed_owner,
1675+
_ => panic!("not a delayed owner"),
1676+
}
16621677
}
16631678
}
16641679

compiler/rustc_hir/src/intravisit.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ pub trait Visitor<'v>: Sized {
226226
/// or `ControlFlow<T>`.
227227
type Result: VisitorResult = ();
228228

229+
#[inline]
230+
fn visit_if_delayed(&self, _: LocalDefId) -> bool {
231+
true
232+
}
233+
229234
/// If `type NestedFilter` is set to visit nested items, this method
230235
/// must also be overridden to provide a map to retrieve nested items.
231236
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
@@ -244,18 +249,23 @@ pub trait Visitor<'v>: Sized {
244249
/// this method is if you want a nested pattern but cannot supply a
245250
/// `TyCtxt`; see `maybe_tcx` for advice.
246251
fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
247-
if Self::NestedFilter::INTER {
252+
if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) {
248253
let item = self.maybe_tcx().hir_item(id);
249254
try_visit!(self.visit_item(item));
250255
}
251256
Self::Result::output()
252257
}
253258

259+
// Now delayed owners are only delegations, which are either item, trait item or impl item.
260+
fn should_visit_maybe_delayed_inter(&mut self, id: LocalDefId) -> bool {
261+
Self::NestedFilter::INTER && self.visit_if_delayed(id)
262+
}
263+
254264
/// Like `visit_nested_item()`, but for trait items. See
255265
/// `visit_nested_item()` for advice on when to override this
256266
/// method.
257267
fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result {
258-
if Self::NestedFilter::INTER {
268+
if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) {
259269
let item = self.maybe_tcx().hir_trait_item(id);
260270
try_visit!(self.visit_trait_item(item));
261271
}
@@ -266,7 +276,7 @@ pub trait Visitor<'v>: Sized {
266276
/// `visit_nested_item()` for advice on when to override this
267277
/// method.
268278
fn visit_nested_impl_item(&mut self, id: ImplItemId) -> Self::Result {
269-
if Self::NestedFilter::INTER {
279+
if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) {
270280
let item = self.maybe_tcx().hir_impl_item(id);
271281
try_visit!(self.visit_impl_item(item));
272282
}

compiler/rustc_interface/src/passes.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,10 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
10541054
/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
10551055
/// This function never fails.
10561056
fn run_required_analyses(tcx: TyCtxt<'_>) {
1057+
// Forces all delayed owners to be lowered and drops AST crate after it.
1058+
// Also refetches hir_crate_items to prevent multiple threads from blocking on it later.
1059+
tcx.force_delayed_owners_lowering();
1060+
10571061
if tcx.sess.opts.unstable_opts.input_stats {
10581062
rustc_passes::input_stats::print_hir_stats(tcx);
10591063
}
@@ -1062,11 +1066,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
10621066
#[cfg(all(not(doc), debug_assertions))]
10631067
rustc_passes::hir_id_validator::check_crate(tcx);
10641068

1065-
// Prefetch this to prevent multiple threads from blocking on it later.
1066-
// This is needed since the `hir_id_validator::check_crate` call above is not guaranteed
1067-
// to use `hir_crate_items`.
1068-
tcx.ensure_done().hir_crate_items(());
1069-
10701069
let sess = tcx.sess;
10711070
sess.time("misc_checking_1", || {
10721071
par_fns(&mut [

compiler/rustc_middle/src/hir/map.rs

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
use rustc_abi::ExternAbi;
66
use rustc_ast::visit::{VisitorResult, walk_list};
77
use rustc_data_structures::fingerprint::Fingerprint;
8+
use rustc_data_structures::fx::FxIndexSet;
89
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
910
use rustc_data_structures::svh::Svh;
10-
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in};
11+
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
1112
use rustc_hir::def::{DefKind, Res};
1213
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
1314
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -1245,25 +1246,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
12451246
}
12461247
}
12471248

1248-
fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
1249-
let krate = tcx.hir_crate(());
1250-
for &id in &krate.delayed_ids {
1251-
tcx.ensure_done().lower_delayed_owner(id);
1252-
}
1253-
1254-
let (_, krate) = krate.delayed_resolver.steal();
1255-
let prof = tcx.sess.prof.clone();
1256-
1257-
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
1258-
spawn(move || {
1259-
let _timer = prof.verbose_generic_activity("drop_ast");
1260-
drop(krate);
1261-
});
1262-
}
1263-
12641249
pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
1265-
force_delayed_owners_lowering(tcx);
1266-
12671250
let mut collector = ItemCollector::new(tcx, true);
12681251

12691252
// A "crate collector" and "module collector" start at a
@@ -1324,11 +1307,12 @@ struct ItemCollector<'tcx> {
13241307
nested_bodies: Vec<LocalDefId>,
13251308
delayed_lint_items: Vec<OwnerId>,
13261309
eiis: Vec<LocalDefId>,
1310+
delayed_ids: Option<&'tcx FxIndexSet<LocalDefId>>,
13271311
}
13281312

13291313
impl<'tcx> ItemCollector<'tcx> {
13301314
fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> {
1331-
ItemCollector {
1315+
let mut collector = ItemCollector {
13321316
crate_collector,
13331317
tcx,
13341318
submodules: Vec::default(),
@@ -1341,13 +1325,46 @@ impl<'tcx> ItemCollector<'tcx> {
13411325
nested_bodies: Vec::default(),
13421326
delayed_lint_items: Vec::default(),
13431327
eiis: Vec::default(),
1328+
delayed_ids: None,
1329+
};
1330+
1331+
if crate_collector {
1332+
let krate = tcx.hir_crate(());
1333+
collector.delayed_ids = Some(&krate.delayed_ids);
1334+
1335+
let delayed_kinds =
1336+
krate.delayed_ids.iter().copied().map(|id| (id, krate.owners[id].expect_delayed()));
1337+
1338+
// FIXME(fn_delegation): need to add delayed lints, eiis
1339+
for (def_id, kind) in delayed_kinds {
1340+
let owner_id = OwnerId { def_id };
1341+
1342+
match kind {
1343+
DelayedOwnerKind::Item => collector.items.push(ItemId { owner_id }),
1344+
DelayedOwnerKind::ImplItem => {
1345+
collector.impl_items.push(ImplItemId { owner_id })
1346+
}
1347+
DelayedOwnerKind::TraitItem => {
1348+
collector.trait_items.push(TraitItemId { owner_id })
1349+
}
1350+
};
1351+
1352+
collector.body_owners.push(def_id);
1353+
}
13441354
}
1355+
1356+
collector
13451357
}
13461358
}
13471359

13481360
impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
13491361
type NestedFilter = nested_filter::All;
13501362

1363+
#[inline]
1364+
fn visit_if_delayed(&self, def_id: LocalDefId) -> bool {
1365+
!self.crate_collector || self.delayed_ids.is_none_or(|ids| !ids.contains(&def_id))
1366+
}
1367+
13511368
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
13521369
self.tcx
13531370
}

compiler/rustc_middle/src/hir/mod.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxIndexSet;
1414
use rustc_data_structures::sorted_map::SortedMap;
1515
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1616
use rustc_data_structures::steal::Steal;
17-
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
17+
use rustc_data_structures::sync::{DynSend, DynSync, spawn, try_par_for_each_in};
1818
use rustc_hir::def::{DefKind, Res};
1919
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
2020
use rustc_hir::lints::DelayedLint;
@@ -64,7 +64,8 @@ impl<'hir> Crate<'hir> {
6464
// which is greater than delayed LocalDefId, we use IndexVec for owners,
6565
// so we will call ensure_contains_elem which will grow it.
6666
if let Some(owner) = self.owners.get(def_id)
67-
&& (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom))
67+
&& (self.delayed_ids.is_empty()
68+
|| !matches!(owner, MaybeOwner::Phantom | MaybeOwner::Delayed(_)))
6869
{
6970
return *owner;
7071
}
@@ -207,6 +208,24 @@ impl ModuleItems {
207208
}
208209

209210
impl<'tcx> TyCtxt<'tcx> {
211+
pub fn force_delayed_owners_lowering(self) {
212+
let krate = self.hir_crate(());
213+
self.ensure_done().hir_crate_items(());
214+
215+
for &id in &krate.delayed_ids {
216+
self.ensure_done().lower_delayed_owner(id);
217+
}
218+
219+
let (_, krate) = krate.delayed_resolver.steal();
220+
let prof = self.sess.prof.clone();
221+
222+
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
223+
spawn(move || {
224+
let _timer = prof.verbose_generic_activity("drop_ast");
225+
drop(krate);
226+
});
227+
}
228+
210229
pub fn parent_module(self, id: HirId) -> LocalModDefId {
211230
if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
212231
LocalModDefId::new_unchecked(id.owner.def_id)
@@ -475,7 +494,8 @@ pub fn provide(providers: &mut Providers) {
475494
providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) {
476495
MaybeOwner::Owner(_) => HirId::make_owner(def_id),
477496
MaybeOwner::NonOwner(hir_id) => hir_id,
478-
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
497+
MaybeOwner::Phantom => bug!("no HirId for {:?}", def_id),
498+
MaybeOwner::Delayed(_) => bug!("delayed owner should be lowered {:?}", def_id),
479499
};
480500
providers.opt_hir_owner_nodes =
481501
|tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes);

src/librustdoc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
904904
return;
905905
}
906906

907+
tcx.force_delayed_owners_lowering();
907908
rustc_interface::passes::emit_delayed_lints(tcx);
908909

909910
if render_opts.dep_info().is_some() {

tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,6 @@ help: consider introducing lifetime `'a` here
4343
LL | impl<'a> Trait for Z {
4444
| ++++
4545

46-
error[E0599]: no associated function or constant named `new` found for struct `InvariantRef<'a, T>` in the current scope
47-
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
48-
|
49-
LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
50-
| -------------------------------------- associated function or constant `new` not found for this struct
51-
...
52-
LL | pub const NEW: Self = InvariantRef::new(&());
53-
| ^^^ associated function or constant not found in `InvariantRef<'_, _>`
54-
5546
error[E0277]: the trait bound `u8: Trait` is not satisfied
5647
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
5748
|
@@ -119,6 +110,15 @@ LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW
119110
found struct `InvariantRef<'_, ()>`
120111
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
121112

113+
error[E0599]: no associated function or constant named `new` found for struct `InvariantRef<'a, T>` in the current scope
114+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
115+
|
116+
LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
117+
| -------------------------------------- associated function or constant `new` not found for this struct
118+
...
119+
LL | pub const NEW: Self = InvariantRef::new(&());
120+
| ^^^ associated function or constant not found in `InvariantRef<'_, _>`
121+
122122
error: aborting due to 10 previous errors
123123

124124
Some errors have detailed explanations: E0261, E0277, E0308, E0599.

0 commit comments

Comments
 (0)