Skip to content

Commit 76dfce2

Browse files
committed
Auto merge of #145477 - cjgillot:codegen-mode, r=oli-obk
Introduce `TypingMode::Codegen` to avoid layout cycles on coroutines Computing layout of coroutines depends on their `optimized_mir`. At the same time, MIR opts can require using layouts to work. For instance to evaluate constants. This leads to cycles and clumsy workarounds. This PR creates a new typing mode for layout computations: - when a coroutine's layout is requested with `TypingMode::PostAnalysis` or earlier, return `LayourError::TooGeneric`; - when a coroutine's layout is requested with `TypingMode::Codegen`, actually compute it. `TypingMode::Codegen` is meant be be used by codegen code, and analyses that require coroutine layout, like transmute check and coroutine recursion check. With this PR, we can remove all `is_coroutine` checks from `rustc_mir_transform` and unlock simplifying coroutine MIR. Perf is not terrific. This PR causes recomputation of a few queries, and I had to insert workarounds.
2 parents b354133 + ac71b54 commit 76dfce2

42 files changed

Lines changed: 248 additions & 121 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::mir::{self, ConstAlloc, ConstValue};
88
use rustc_middle::query::TyCtxtAt;
99
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
1010
use rustc_middle::ty::print::with_no_trimmed_paths;
11-
use rustc_middle::ty::{self, Ty, TyCtxt};
11+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
1212
use rustc_middle::{bug, throw_inval};
1313
use rustc_span::Span;
1414
use rustc_span::def_id::LocalDefId;
@@ -23,6 +23,33 @@ use crate::interpret::{
2323
};
2424
use crate::{CTRL_C_RECEIVED, errors};
2525

26+
fn retry_codegen_mode_with_postanalysis<'tcx, K: TypeVisitable<TyCtxt<'tcx>>, V>(
27+
key: ty::PseudoCanonicalInput<'tcx, K>,
28+
f: impl FnOnce(ty::PseudoCanonicalInput<'tcx, K>) -> Result<V, ErrorHandled>,
29+
) -> Option<Result<V, ErrorHandled>> {
30+
let ty::PseudoCanonicalInput { typing_env, value } = key;
31+
match typing_env.typing_mode().assert_not_erased() {
32+
// We are in codegen. It's very likely this constant has been evaluated in PostAnalysis
33+
// before. Try to reuse this evaluation, and only re-run if we hit a `TooGeneric` error.
34+
ty::TypingMode::Codegen => {
35+
let with_postanalysis =
36+
ty::TypingEnv::new(typing_env.param_env, ty::TypingMode::PostAnalysis);
37+
let with_postanalysis = f(with_postanalysis.as_query_input(value));
38+
match with_postanalysis {
39+
Ok(_) | Err(ErrorHandled::Reported(..)) => return Some(with_postanalysis),
40+
Err(ErrorHandled::TooGeneric(_)) => {}
41+
}
42+
}
43+
ty::TypingMode::Coherence
44+
| ty::TypingMode::Analysis { .. }
45+
| ty::TypingMode::Borrowck { .. }
46+
| ty::TypingMode::PostBorrowckAnalysis { .. }
47+
| ty::TypingMode::PostAnalysis => {}
48+
}
49+
50+
None
51+
}
52+
2653
fn setup_for_eval<'tcx>(
2754
ecx: &mut CompileTimeInterpCx<'tcx>,
2855
cid: GlobalId<'tcx>,
@@ -327,9 +354,18 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
327354
tcx: TyCtxt<'tcx>,
328355
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
329356
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
357+
crate::assert_typing_mode(key.typing_env.typing_mode());
358+
330359
if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) {
331360
return Ok(value);
332361
}
362+
363+
if let Some(retry) =
364+
retry_codegen_mode_with_postanalysis(key, |key| tcx.eval_to_const_value_raw(key))
365+
{
366+
return retry;
367+
}
368+
333369
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
334370
}
335371

@@ -369,23 +405,18 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
369405
tcx: TyCtxt<'tcx>,
370406
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
371407
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
408+
crate::assert_typing_mode(key.typing_env.typing_mode());
409+
if let Some(retry) =
410+
retry_codegen_mode_with_postanalysis(key, |key| tcx.eval_to_allocation_raw(key))
411+
{
412+
return retry;
413+
}
414+
372415
// This shouldn't be used for statics, since statics are conceptually places,
373416
// not values -- so what we do here could break pointer identity.
374417
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
375418

376419
if cfg!(debug_assertions) {
377-
match key.typing_env.typing_mode().assert_not_erased() {
378-
ty::TypingMode::PostAnalysis => {}
379-
ty::TypingMode::Coherence
380-
| ty::TypingMode::Analysis { .. }
381-
| ty::TypingMode::Borrowck { .. }
382-
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
383-
bug!(
384-
"Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
385-
)
386-
}
387-
}
388-
389420
// Make sure we format the instance even if we do not print it.
390421
// This serves as a regression test against an ICE on printing.
391422
// The next two lines concatenated contain some discussion:

compiler/rustc_const_eval/src/const_eval/valtrees.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,19 +241,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
241241
typing_env: ty::TypingEnv<'tcx>,
242242
cid: GlobalId<'tcx>,
243243
) -> EvalToValTreeResult<'tcx> {
244-
if cfg!(debug_assertions) {
245-
match typing_env.typing_mode().assert_not_erased() {
246-
ty::TypingMode::PostAnalysis => {}
247-
ty::TypingMode::Coherence
248-
| ty::TypingMode::Analysis { .. }
249-
| ty::TypingMode::Borrowck { .. }
250-
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
251-
bug!(
252-
"Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
253-
)
254-
}
255-
}
256-
}
244+
crate::assert_typing_mode(typing_env.typing_mode());
257245
let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
258246

259247
// FIXME Need to provide a span to `eval_to_valtree`

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ use rustc_middle::ty::layout::{
99
LayoutOfHelpers, TyAndLayout,
1010
};
1111
use rustc_middle::ty::{
12-
self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, TypingMode,
13-
Variance,
12+
self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, Variance,
1413
};
15-
use rustc_middle::{bug, mir, span_bug};
14+
use rustc_middle::{mir, span_bug};
1615
use rustc_span::Span;
1716
use rustc_target::callconv::FnAbi;
1817
use tracing::{debug, trace};
@@ -243,21 +242,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
243242
typing_env: ty::TypingEnv<'tcx>,
244243
machine: M,
245244
) -> Self {
246-
// Const eval always happens in post analysis mode in order to be able to use the hidden types of
247-
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
248-
// types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
249-
// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
250-
if cfg!(debug_assertions) {
251-
match typing_env.typing_mode().assert_not_erased() {
252-
TypingMode::PostAnalysis => {}
253-
TypingMode::Coherence
254-
| TypingMode::Analysis { .. }
255-
| TypingMode::Borrowck { .. }
256-
| TypingMode::PostBorrowckAnalysis { .. } => {
257-
bug!("Const eval should always happens in PostAnalysis mode.");
258-
}
259-
}
260-
}
245+
crate::assert_typing_mode(typing_env.typing_mode());
261246

262247
InterpCx {
263248
machine,

compiler/rustc_const_eval/src/lib.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,28 @@ pub mod util;
1818

1919
use std::sync::atomic::AtomicBool;
2020

21-
use rustc_middle::ty;
2221
use rustc_middle::util::Providers;
22+
use rustc_middle::{bug, ty};
23+
24+
/// Const eval always happens in post analysis mode in order to be able to use the hidden types of
25+
/// opaque types. This is needed for trivial things like `size_of`, but also for using associated
26+
/// types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
27+
/// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
28+
fn assert_typing_mode(typing_mode: ty::TypingMode<'_>) {
29+
if cfg!(debug_assertions) {
30+
match typing_mode.assert_not_erased() {
31+
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => {}
32+
// Const eval always happens in PostAnalysis or Codegen mode. See the comment in
33+
// `InterpCx::new` for more details.
34+
ty::TypingMode::Coherence
35+
| ty::TypingMode::Analysis { .. }
36+
| ty::TypingMode::Borrowck { .. }
37+
| ty::TypingMode::PostBorrowckAnalysis { .. } => bug!(
38+
"Const eval should always happens in PostAnalysis or Codegen mode. See the comment on `assert_typing_mode` for more details."
39+
),
40+
}
41+
}
42+
}
2343

2444
pub fn provide(providers: &mut Providers) {
2545
const_eval::provide(&mut providers.queries);

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
663663
ty::TypingMode::Coherence
664664
| ty::TypingMode::Borrowck { .. }
665665
| ty::TypingMode::PostBorrowckAnalysis { .. }
666-
| ty::TypingMode::PostAnalysis => {
666+
| ty::TypingMode::PostAnalysis
667+
| ty::TypingMode::Codegen => {
667668
bug!()
668669
}
669670
};

compiler/rustc_hir_typeck/src/intrinsicck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(),
147147
return Err(e);
148148
};
149149

150-
let typing_env = ty::TypingEnv::post_analysis(tcx, owner);
150+
let typing_env = ty::TypingEnv::codegen(tcx, owner);
151151
let mut result = Ok(());
152152
for &(from, to, hir_id) in &typeck_results.transmutes_to_check {
153153
result = result.and(check_transmute(tcx, typing_env, from, to, hir_id));

compiler/rustc_hir_typeck/src/opaque_types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
105105
ty::TypingMode::Coherence
106106
| ty::TypingMode::Borrowck { .. }
107107
| ty::TypingMode::PostBorrowckAnalysis { .. }
108-
| ty::TypingMode::PostAnalysis => {
108+
| ty::TypingMode::PostAnalysis
109+
| ty::TypingMode::Codegen => {
109110
bug!()
110111
}
111112
};

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ impl<'tcx> Drop for InferCtxt<'tcx> {
350350
TypingMode::Coherence
351351
| TypingMode::Analysis { .. }
352352
| TypingMode::PostBorrowckAnalysis { .. }
353-
| TypingMode::PostAnalysis => {}
353+
| TypingMode::PostAnalysis
354+
| TypingMode::Codegen => {}
354355
// In erased mode, the opaque type storage is always empty
355356
TypingMode::ErasedNotCoherence(..) => {}
356357
TypingMode::Borrowck { .. } => {
@@ -1156,7 +1157,8 @@ impl<'tcx> InferCtxt<'tcx> {
11561157
// to support PostBorrowckAnalysis in the old solver as well.
11571158
TypingMode::Coherence
11581159
| TypingMode::PostBorrowckAnalysis { .. }
1159-
| TypingMode::PostAnalysis => false,
1160+
| TypingMode::PostAnalysis
1161+
| TypingMode::Codegen => false,
11601162
}
11611163
}
11621164

@@ -1486,7 +1488,8 @@ impl<'tcx> InferCtxt<'tcx> {
14861488
}
14871489
mode @ (ty::TypingMode::Coherence
14881490
| ty::TypingMode::PostBorrowckAnalysis { .. }
1489-
| ty::TypingMode::PostAnalysis) => mode,
1491+
| ty::TypingMode::PostAnalysis
1492+
| ty::TypingMode::Codegen) => mode,
14901493
ty::TypingMode::ErasedNotCoherence(MayBeErased) => unreachable!(),
14911494
};
14921495
ty::TypingEnv::new(param_env, typing_mode)

compiler/rustc_infer/src/infer/opaque_types/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,9 @@ impl<'tcx> InferCtxt<'tcx> {
283283
.map(|obligation| obligation.as_goal()),
284284
);
285285
}
286-
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
286+
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. }
287+
| ty::TypingMode::PostAnalysis
288+
| ty::TypingMode::Codegen) => {
287289
bug!("insert hidden type in {mode:?}")
288290
}
289291
}

compiler/rustc_interface/src/passes.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,10 +1180,10 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
11801180
&& (!tcx.is_async_drop_in_place_coroutine(def_id.to_def_id()))
11811181
{
11821182
// Eagerly check the unsubstituted layout for cycles.
1183-
tcx.ensure_ok().layout_of(
1184-
ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
1185-
.as_query_input(tcx.type_of(def_id).instantiate_identity().skip_norm_wip()),
1186-
);
1183+
tcx.ensure_ok()
1184+
.layout_of(ty::TypingEnv::codegen(tcx, def_id.to_def_id()).as_query_input(
1185+
tcx.type_of(def_id).instantiate_identity().skip_norm_wip(),
1186+
));
11871187
}
11881188
});
11891189
});

0 commit comments

Comments
 (0)