Skip to content

Commit 41a3e06

Browse files
authored
Unrolled build for rust-lang#130201
Rollup merge of rust-lang#130201 - compiler-errors:foreign-synthetic-body, r=lcnr Encode `coroutine_by_move_body_def_id` in crate metadata We synthesize the MIR for a by-move body for the `FnOnce` implementation of async closures. It can be accessed with the `coroutine_by_move_body_def_id` query. We weren't encoding this query in the metadata though, nor were we properly recording that synthetic MIR in `mir_keys`, so the `optimized_mir` wasn't getting encoded either! Stacked on top is a fix to consider `DefKind::SyntheticCoroutineBody` to return true in several places I missed. Specifically, we should consider the def-kind in `fn DefKind::is_fn_like()`, since that's what we were using to make sure we ensure `query mir_inliner_callees` before the MIR gets stolen for the body. This led to some CI failures that were caught by miri but which I added a test for.
2 parents e9e13a6 + 4beb1cf commit 41a3e06

File tree

9 files changed

+81
-20
lines changed

9 files changed

+81
-20
lines changed

compiler/rustc_hir/src/def.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,10 @@ impl DefKind {
287287

288288
#[inline]
289289
pub fn is_fn_like(self) -> bool {
290-
matches!(self, DefKind::Fn | DefKind::AssocFn | DefKind::Closure)
290+
matches!(
291+
self,
292+
DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::SyntheticCoroutineBody
293+
)
291294
}
292295

293296
/// Whether `query get_codegen_attrs` should be used with this definition.

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ provide! { tcx, def_id, other, cdata,
290290
fn_arg_names => { table }
291291
coroutine_kind => { table_direct }
292292
coroutine_for_closure => { table }
293+
coroutine_by_move_body_def_id => { table }
293294
eval_static_initializer => {
294295
Ok(cdata
295296
.root

compiler/rustc_metadata/src/rmeta/encoder.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1488,9 +1488,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14881488
if def_kind == DefKind::Closure
14891489
&& tcx.type_of(def_id).skip_binder().is_coroutine_closure()
14901490
{
1491+
let coroutine_for_closure = self.tcx.coroutine_for_closure(def_id);
14911492
self.tables
14921493
.coroutine_for_closure
1493-
.set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into());
1494+
.set_some(def_id.index, coroutine_for_closure.into());
1495+
1496+
// If this async closure has a by-move body, record it too.
1497+
if tcx.needs_coroutine_by_move_body_def_id(coroutine_for_closure) {
1498+
self.tables.coroutine_by_move_body_def_id.set_some(
1499+
coroutine_for_closure.index,
1500+
self.tcx.coroutine_by_move_body_def_id(coroutine_for_closure).into(),
1501+
);
1502+
}
14941503
}
14951504
if let DefKind::Static { .. } = def_kind {
14961505
if !self.tcx.is_foreign_item(def_id) {

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ define_tables! {
446446
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
447447
coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
448448
coroutine_for_closure: Table<DefIndex, RawDefId>,
449+
coroutine_by_move_body_def_id: Table<DefIndex, RawDefId>,
449450
eval_static_initializer: Table<DefIndex, LazyValue<mir::interpret::ConstAllocation<'static>>>,
450451
trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
451452
trait_item_def_id: Table<DefIndex, RawDefId>,

compiler/rustc_mir_transform/src/cross_crate_inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
2424

2525
// This just reproduces the logic from Instance::requires_inline.
2626
match tcx.def_kind(def_id) {
27-
DefKind::Ctor(..) | DefKind::Closure => return true,
27+
DefKind::Ctor(..) | DefKind::Closure | DefKind::SyntheticCoroutineBody => return true,
2828
DefKind::Fn | DefKind::AssocFn => {}
2929
_ => return false,
3030
}

compiler/rustc_mir_transform/src/lib.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ use rustc_const_eval::util;
2121
use rustc_data_structures::fx::FxIndexSet;
2222
use rustc_data_structures::steal::Steal;
2323
use rustc_hir as hir;
24-
use rustc_hir::def::DefKind;
24+
use rustc_hir::def::{CtorKind, DefKind};
2525
use rustc_hir::def_id::LocalDefId;
26-
use rustc_hir::intravisit::{self, Visitor};
2726
use rustc_index::IndexVec;
2827
use rustc_middle::mir::{
2928
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
@@ -224,26 +223,31 @@ fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
224223
/// MIR associated with them.
225224
fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
226225
// All body-owners have MIR associated with them.
227-
let set: FxIndexSet<_> = tcx.hir().body_owners().collect();
226+
let mut set: FxIndexSet<_> = tcx.hir().body_owners().collect();
228227

229-
// Additionally, tuple struct/variant constructors have MIR, but
230-
// they don't have a BodyId, so we need to build them separately.
231-
struct GatherCtors {
232-
set: FxIndexSet<LocalDefId>,
228+
// Coroutine-closures (e.g. async closures) have an additional by-move MIR
229+
// body that isn't in the HIR.
230+
for body_owner in tcx.hir().body_owners() {
231+
if let DefKind::Closure = tcx.def_kind(body_owner)
232+
&& tcx.needs_coroutine_by_move_body_def_id(body_owner.to_def_id())
233+
{
234+
set.insert(tcx.coroutine_by_move_body_def_id(body_owner).expect_local());
235+
}
233236
}
234-
impl<'tcx> Visitor<'tcx> for GatherCtors {
235-
fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) {
236-
if let hir::VariantData::Tuple(_, _, def_id) = *v {
237-
self.set.insert(def_id);
237+
238+
// tuple struct/variant constructors have MIR, but they don't have a BodyId,
239+
// so we need to build them separately.
240+
for item in tcx.hir_crate_items(()).free_items() {
241+
if let DefKind::Struct | DefKind::Enum = tcx.def_kind(item.owner_id) {
242+
for variant in tcx.adt_def(item.owner_id).variants() {
243+
if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
244+
set.insert(ctor_def_id.expect_local());
245+
}
238246
}
239-
intravisit::walk_struct_def(self, v)
240247
}
241248
}
242249

243-
let mut gather_ctors = GatherCtors { set };
244-
tcx.hir().visit_all_item_likes_in_crate(&mut gather_ctors);
245-
246-
gather_ctors.set
250+
set
247251
}
248252

249253
fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {

compiler/rustc_symbol_mangling/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,11 @@ fn compute_symbol_name<'tcx>(
227227
// and we want to be sure to avoid any symbol conflicts here.
228228
let is_globally_shared_function = matches!(
229229
tcx.def_kind(instance.def_id()),
230-
DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Ctor(..)
230+
DefKind::Fn
231+
| DefKind::AssocFn
232+
| DefKind::Closure
233+
| DefKind::SyntheticCoroutineBody
234+
| DefKind::Ctor(..)
231235
) && matches!(
232236
MonoItem::Fn(instance).instantiation_mode(tcx),
233237
InstantiationMode::GloballyShared { may_conflict: true }

tests/ui/async-await/async-closures/foreign.rs

+5
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ extern crate foreign;
1212

1313
struct NoCopy;
1414

15+
async fn call_once(f: impl async FnOnce()) {
16+
f().await;
17+
}
18+
1519
fn main() {
1620
block_on::block_on(async {
1721
foreign::closure()().await;
22+
call_once(foreign::closure()).await;
1823
});
1924
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ edition: 2021
2+
//@ compile-flags: -Zinline-mir
3+
//@ build-pass
4+
5+
// Ensure that we don't hit a Steal ICE because we forgot to ensure
6+
// `mir_inliner_callees` for the synthetic by-move coroutine body since
7+
// its def-id wasn't previously being considered.
8+
9+
#![feature(async_closure, noop_waker)]
10+
11+
use std::future::Future;
12+
use std::pin::pin;
13+
use std::task::*;
14+
15+
pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
16+
let mut fut = pin!(fut);
17+
let ctx = &mut Context::from_waker(Waker::noop());
18+
19+
loop {
20+
match fut.as_mut().poll(ctx) {
21+
Poll::Pending => {}
22+
Poll::Ready(t) => break t,
23+
}
24+
}
25+
}
26+
27+
async fn call_once<T>(f: impl async FnOnce() -> T) -> T {
28+
f().await
29+
}
30+
31+
fn main() {
32+
let c = async || {};
33+
block_on(call_once(c));
34+
}

0 commit comments

Comments
 (0)