Skip to content

Commit aff7f6c

Browse files
Auto merge of #145477 - cjgillot:codegen-mode, r=<try>
[EXPERIMENT] Introduce `TypingMode::Codegen` to avoid layout cycles
2 parents a41214f + 1cfa179 commit aff7f6c

File tree

57 files changed

+317
-156
lines changed

Some content is hidden

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

57 files changed

+317
-156
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::assert_matches::debug_assert_matches;
12
use std::sync::atomic::Ordering::Relaxed;
23

34
use either::{Left, Right};
@@ -292,6 +293,30 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
292293
tcx: TyCtxt<'tcx>,
293294
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
294295
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
296+
let ty::PseudoCanonicalInput { typing_env, value } = key;
297+
298+
// Const eval always happens in PostAnalysis or Codegen mode. See the comment in
299+
// `InterpCx::new` for more details.
300+
debug_assert_matches!(
301+
typing_env.typing_mode,
302+
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
303+
);
304+
305+
// We are in codegen. It's very likely this constant has been evaluated in PostAnalysis before.
306+
// Try to reuse this evaluation, and only re-run if we hit a `TooGeneric` error.
307+
if let ty::TypingMode::Codegen = typing_env.typing_mode {
308+
let with_postanalysis = ty::TypingEnv {
309+
typing_mode: ty::TypingMode::PostAnalysis,
310+
param_env: typing_env.param_env,
311+
};
312+
let with_postanalysis =
313+
tcx.eval_to_const_value_raw(with_postanalysis.as_query_input(value));
314+
match with_postanalysis {
315+
Ok(_) | Err(ErrorHandled::Reported(..)) => return with_postanalysis,
316+
Err(ErrorHandled::TooGeneric(_)) => {}
317+
}
318+
}
319+
295320
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
296321
}
297322

@@ -331,23 +356,44 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
331356
tcx: TyCtxt<'tcx>,
332357
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
333358
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
359+
let ty::PseudoCanonicalInput { typing_env, value } = key;
360+
334361
// This shouldn't be used for statics, since statics are conceptually places,
335362
// not values -- so what we do here could break pointer identity.
336-
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
337-
// Const eval always happens in PostAnalysis mode . See the comment in
363+
assert!(value.promoted.is_some() || !tcx.is_static(value.instance.def_id()));
364+
365+
// Const eval always happens in PostAnalysis or Codegen mode. See the comment in
338366
// `InterpCx::new` for more details.
339-
debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
367+
debug_assert_matches!(
368+
typing_env.typing_mode,
369+
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
370+
);
371+
340372
if cfg!(debug_assertions) {
341373
// Make sure we format the instance even if we do not print it.
342374
// This serves as a regression test against an ICE on printing.
343375
// The next two lines concatenated contain some discussion:
344376
// https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
345377
// subject/anon_const_instance_printing/near/135980032
346-
let instance = with_no_trimmed_paths!(key.value.instance.to_string());
347-
trace!("const eval: {:?} ({})", key, instance);
378+
let instance = with_no_trimmed_paths!(value.instance.to_string());
379+
trace!("const eval: {:?} ({}) inside {:?}", value, instance, typing_env);
380+
}
381+
382+
// We are in codegen. It's very likely this constant has been evaluated in PostAnalysis before.
383+
// Try to reuse this evaluation, and only re-run if we hit a `TooGeneric` error.
384+
if let ty::TypingMode::Codegen = typing_env.typing_mode {
385+
let with_postanalysis = ty::TypingEnv {
386+
typing_mode: ty::TypingMode::PostAnalysis,
387+
param_env: typing_env.param_env,
388+
};
389+
let with_postanalysis = tcx.eval_to_allocation_raw(with_postanalysis.as_query_input(value));
390+
match with_postanalysis {
391+
Ok(_) | Err(ErrorHandled::Reported(..)) => return with_postanalysis,
392+
Err(ErrorHandled::TooGeneric(_)) => {}
393+
}
348394
}
349395

350-
eval_in_interpreter(tcx, key.value, key.typing_env)
396+
eval_in_interpreter(tcx, value, typing_env)
351397
}
352398

353399
fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(

compiler/rustc_const_eval/src/const_eval/valtrees.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::assert_matches::debug_assert_matches;
2+
13
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
24
use rustc_data_structures::stack::ensure_sufficient_stack;
35
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
@@ -232,9 +234,12 @@ pub(crate) fn eval_to_valtree<'tcx>(
232234
typing_env: ty::TypingEnv<'tcx>,
233235
cid: GlobalId<'tcx>,
234236
) -> EvalToValTreeResult<'tcx> {
235-
// Const eval always happens in PostAnalysis mode . See the comment in
237+
// Const eval always happens in PostAnalysis or Codegen mode . See the comment in
236238
// `InterpCx::new` for more details.
237-
debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
239+
debug_assert_matches!(
240+
typing_env.typing_mode,
241+
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
242+
);
238243
let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
239244

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

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
226226
typing_env: ty::TypingEnv<'tcx>,
227227
machine: M,
228228
) -> Self {
229-
// Const eval always happens in post analysis mode in order to be able to use the hidden types of
230-
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
231-
// types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
232-
// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
233-
debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
229+
// Const eval always happens in post analysis or codegen mode in order to be able to use
230+
// the hidden types of opaque types. This is needed for trivial things like `size_of`, but
231+
// also for using associated types that are not specified in the opaque type. We also use
232+
// MIR bodies whose opaque types have already been revealed, so we'd be able to at least
233+
// partially observe the hidden types anyways.
234+
debug_assert_matches!(
235+
typing_env.typing_mode,
236+
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
237+
);
234238
InterpCx {
235239
machine,
236240
tcx: tcx.at(root_span),

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) {
147147
let typeck_results = tcx.typeck(owner);
148148
let None = typeck_results.tainted_by_errors else { return };
149149

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

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,8 @@ impl<'tcx> InferCtxt<'tcx> {
10561056
// to support PostBorrowckAnalysis in the old solver as well.
10571057
TypingMode::Coherence
10581058
| TypingMode::PostBorrowckAnalysis { .. }
1059-
| TypingMode::PostAnalysis => false,
1059+
| TypingMode::PostAnalysis
1060+
| TypingMode::Codegen => false,
10601061
}
10611062
}
10621063

@@ -1379,7 +1380,8 @@ impl<'tcx> InferCtxt<'tcx> {
13791380
}
13801381
mode @ (ty::TypingMode::Coherence
13811382
| ty::TypingMode::PostBorrowckAnalysis { .. }
1382-
| ty::TypingMode::PostAnalysis) => mode,
1383+
| ty::TypingMode::PostAnalysis
1384+
| ty::TypingMode::Codegen) => mode,
13831385
};
13841386
ty::TypingEnv { typing_mode, param_env }
13851387
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,9 @@ impl<'tcx> InferCtxt<'tcx> {
276276
.map(|obligation| obligation.as_goal()),
277277
);
278278
}
279-
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
279+
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. }
280+
| ty::TypingMode::PostAnalysis
281+
| ty::TypingMode::Codegen) => {
280282
bug!("insert hidden type in {mode:?}")
281283
}
282284
}

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
11131113
if !tcx.is_async_drop_in_place_coroutine(def_id.to_def_id()) {
11141114
// Eagerly check the unsubstituted layout for cycles.
11151115
tcx.ensure_ok().layout_of(
1116-
ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
1116+
ty::TypingEnv::codegen(tcx, def_id.to_def_id())
11171117
.as_query_input(tcx.type_of(def_id).instantiate_identity()),
11181118
);
11191119
}

compiler/rustc_middle/src/mir/interpret/mod.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -384,18 +384,20 @@ impl<'tcx> GlobalAlloc<'tcx> {
384384
.type_of(def_id)
385385
.no_bound_vars()
386386
.expect("statics should not have generic parameters");
387-
let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
388-
assert!(layout.is_sized());
387+
let layout = tcx.layout_of(typing_env.as_query_input(ty));
388+
let (size, mut align) = if let Ok(layout) = layout {
389+
assert!(layout.is_sized());
390+
(layout.size, layout.align.abi)
391+
} else {
392+
(Size::ZERO, Align::ONE)
393+
};
389394

390395
// Take over-alignment from attributes into account.
391-
let align = match tcx.codegen_fn_attrs(def_id).alignment {
392-
Some(align_from_attribute) => {
393-
Ord::max(align_from_attribute, layout.align.abi)
394-
}
395-
None => layout.align.abi,
396-
};
396+
if let Some(align_from_attribute) = tcx.codegen_fn_attrs(def_id).alignment {
397+
align = Ord::max(align_from_attribute, align);
398+
}
397399

398-
(layout.size, align)
400+
(size, align)
399401
}
400402
}
401403
GlobalAlloc::Memory(alloc) => {

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,7 +1663,7 @@ rustc_queries! {
16631663
/// Like `param_env`, but returns the `ParamEnv` after all opaque types have been
16641664
/// replaced with their hidden type. This is used in the old trait solver
16651665
/// when in `PostAnalysis` mode and should not be called directly.
1666-
query typing_env_normalized_for_post_analysis(def_id: DefId) -> ty::TypingEnv<'tcx> {
1666+
query param_env_normalized_for_post_analysis(def_id: DefId) -> ty::ParamEnv<'tcx> {
16671667
desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
16681668
}
16691669

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,17 @@ impl<'tcx> ParamEnv<'tcx> {
10031003
pub fn and<T: TypeVisitable<TyCtxt<'tcx>>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
10041004
ParamEnvAnd { param_env: self, value }
10051005
}
1006+
1007+
/// Eagerly reveal all opaque types in the `param_env`.
1008+
pub fn with_normalized(self, tcx: TyCtxt<'tcx>) -> ParamEnv<'tcx> {
1009+
// No need to reveal opaques with the new solver enabled,
1010+
// since we have lazy norm.
1011+
if tcx.next_trait_solver_globally() {
1012+
self
1013+
} else {
1014+
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds))
1015+
}
1016+
}
10061017
}
10071018

10081019
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
@@ -1040,7 +1051,7 @@ impl<'tcx> TypingEnv<'tcx> {
10401051
/// use `TypingMode::PostAnalysis`, they may still have where-clauses
10411052
/// in scope.
10421053
pub fn fully_monomorphized() -> TypingEnv<'tcx> {
1043-
TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::empty() }
1054+
TypingEnv { typing_mode: TypingMode::Codegen, param_env: ParamEnv::empty() }
10441055
}
10451056

10461057
/// Create a typing environment for use during analysis outside of a body.
@@ -1056,27 +1067,43 @@ impl<'tcx> TypingEnv<'tcx> {
10561067
}
10571068

10581069
pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
1059-
tcx.typing_env_normalized_for_post_analysis(def_id)
1070+
TypingEnv {
1071+
typing_mode: TypingMode::PostAnalysis,
1072+
param_env: tcx.param_env_normalized_for_post_analysis(def_id),
1073+
}
1074+
}
1075+
1076+
pub fn codegen(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
1077+
TypingEnv {
1078+
typing_mode: TypingMode::Codegen,
1079+
param_env: tcx.param_env_normalized_for_post_analysis(def_id),
1080+
}
10601081
}
10611082

1062-
/// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all
1063-
/// opaque types in the `param_env`.
1083+
/// Modify the `typing_mode` to `PostAnalysis` or `Codegen` and eagerly reveal all opaque types
1084+
/// in the `param_env`.
10641085
pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
10651086
let TypingEnv { typing_mode, param_env } = self;
1066-
if let TypingMode::PostAnalysis = typing_mode {
1087+
if let TypingMode::PostAnalysis | TypingMode::Codegen = typing_mode {
10671088
return self;
10681089
}
10691090

1070-
// No need to reveal opaques with the new solver enabled,
1071-
// since we have lazy norm.
1072-
let param_env = if tcx.next_trait_solver_globally() {
1073-
param_env
1074-
} else {
1075-
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
1076-
};
1091+
let param_env = param_env.with_normalized(tcx);
10771092
TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
10781093
}
10791094

1095+
/// Modify the `typing_mode` to `PostAnalysis` or `Codegen` and eagerly reveal all opaque types
1096+
/// in the `param_env`.
1097+
pub fn with_codegen_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
1098+
let TypingEnv { typing_mode, param_env } = self;
1099+
if let TypingMode::Codegen = typing_mode {
1100+
return self;
1101+
}
1102+
1103+
let param_env = param_env.with_normalized(tcx);
1104+
TypingEnv { typing_mode: TypingMode::Codegen, param_env }
1105+
}
1106+
10801107
/// Combine this typing environment with the given `value` to be used by
10811108
/// not (yet) canonicalized queries. This only works if the value does not
10821109
/// contain anything local to some `InferCtxt`, i.e. inference variables or

0 commit comments

Comments
 (0)