Skip to content
Draft
71 changes: 59 additions & 12 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,40 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) {
let ty::PseudoCanonicalInput { typing_env, value } = key;

if let Some((value, _ty)) = tcx.trivial_const(value.instance.def_id()) {
return Ok(value);
}

match typing_env.typing_mode() {
ty::TypingMode::PostAnalysis => {}
// We are in codegen. It's very likely this constant has been evaluated in PostAnalysis before.
// Try to reuse this evaluation, and only re-run if we hit a `TooGeneric` error.
ty::TypingMode::Codegen => {
let with_postanalysis =
ty::TypingEnv::new(typing_env.param_env, ty::TypingMode::PostAnalysis);
let with_postanalysis =
tcx.eval_to_const_value_raw(with_postanalysis.as_query_input(value));
match with_postanalysis {
Ok(_) | Err(ErrorHandled::Reported(..)) => return with_postanalysis,
Err(ErrorHandled::TooGeneric(_)) => {}
}
}
// Const eval always happens in PostAnalysis or Codegen mode. See the comment in
// `InterpCx::new` for more details.
ty::TypingMode::Coherence
| ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
if cfg!(debug_assertions) {
bug!(
"Const eval should always happens in PostAnalysis or Codegen mode. See the comment in `InterpCx::new` for more details."
)
}
}
}

tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
}

Expand Down Expand Up @@ -369,33 +400,49 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
let ty::PseudoCanonicalInput { typing_env, value } = key;

// This shouldn't be used for statics, since statics are conceptually places,
// not values -- so what we do here could break pointer identity.
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));

if cfg!(debug_assertions) {
match key.typing_env.typing_mode() {
ty::TypingMode::PostAnalysis => {}
ty::TypingMode::Coherence
| ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
match key.typing_env.typing_mode() {
ty::TypingMode::PostAnalysis => {}
// We are in codegen. It's very likely this constant has been evaluated in PostAnalysis before.
// Try to reuse this evaluation, and only re-run if we hit a `TooGeneric` error.
ty::TypingMode::Codegen => {
let with_postanalysis =
ty::TypingEnv::new(typing_env.param_env, ty::TypingMode::PostAnalysis);
let with_postanalysis =
tcx.eval_to_allocation_raw(with_postanalysis.as_query_input(value));
match with_postanalysis {
Ok(_) | Err(ErrorHandled::Reported(..)) => return with_postanalysis,
Err(ErrorHandled::TooGeneric(_)) => {}
}
}
ty::TypingMode::Coherence
| ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
if cfg!(debug_assertions) {
bug!(
"Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
"Const eval should always happens in PostAnalysis or Codegen mode. See the comment in `InterpCx::new` for more details."
)
}
}
}

if cfg!(debug_assertions) {
// Make sure we format the instance even if we do not print it.
// This serves as a regression test against an ICE on printing.
// The next two lines concatenated contain some discussion:
// https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
// subject/anon_const_instance_printing/near/135980032
let instance = with_no_trimmed_paths!(key.value.instance.to_string());
trace!("const eval: {:?} ({})", key, instance);
let instance = with_no_trimmed_paths!(value.instance.to_string());
trace!("const eval: {:?} ({}) inside {:?}", value, instance, typing_env);
}

eval_in_interpreter(tcx, key.value, key.typing_env)
eval_in_interpreter(tcx, value, typing_env)
}

fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,13 @@ pub(crate) fn eval_to_valtree<'tcx>(
) -> EvalToValTreeResult<'tcx> {
if cfg!(debug_assertions) {
match typing_env.typing_mode() {
ty::TypingMode::PostAnalysis => {}
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => {}
ty::TypingMode::Coherence
| ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
bug!(
"Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
"Const eval should always happens in PostAnalysis or Codegen mode. See the comment in `InterpCx::new` for more details."
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
if cfg!(debug_assertions) {
match typing_env.typing_mode() {
TypingMode::PostAnalysis => {}
TypingMode::PostAnalysis | TypingMode::Codegen => {}
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => {
bug!("Const eval should always happens in PostAnalysis mode.");
bug!("Const eval should always happens in PostAnalysis or Codegen mode.");
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::TypingMode::Coherence
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
| ty::TypingMode::PostAnalysis
| ty::TypingMode::Codegen => {
bug!()
}
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) {
let typeck_results = tcx.typeck(owner);
let None = typeck_results.tainted_by_errors else { return };

let typing_env = ty::TypingEnv::post_analysis(tcx, owner);
let typing_env = ty::TypingEnv::codegen(tcx, owner);
for &(from, to, hir_id) in &typeck_results.transmutes_to_check {
check_transmute(tcx, typing_env, from, to, hir_id);
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
ty::TypingMode::Coherence
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
| ty::TypingMode::PostAnalysis
| ty::TypingMode::Codegen => {
bug!()
}
};
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,8 @@ impl<'tcx> InferCtxt<'tcx> {
// to support PostBorrowckAnalysis in the old solver as well.
TypingMode::Coherence
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => false,
| TypingMode::PostAnalysis
| TypingMode::Codegen => false,
}
}

Expand Down Expand Up @@ -1408,7 +1409,8 @@ impl<'tcx> InferCtxt<'tcx> {
}
mode @ (ty::TypingMode::Coherence
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis) => mode,
| ty::TypingMode::PostAnalysis
| ty::TypingMode::Codegen) => mode,
};
ty::TypingEnv::new(param_env, typing_mode)
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_infer/src/infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,9 @@ impl<'tcx> InferCtxt<'tcx> {
.map(|obligation| obligation.as_goal()),
);
}
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
mode @ (ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis
| ty::TypingMode::Codegen) => {
bug!("insert hidden type in {mode:?}")
}
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,10 +1180,10 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
&& (!tcx.is_async_drop_in_place_coroutine(def_id.to_def_id()))
{
// Eagerly check the unsubstituted layout for cycles.
tcx.ensure_ok().layout_of(
ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
.as_query_input(tcx.type_of(def_id).instantiate_identity().skip_norm_wip()),
);
tcx.ensure_ok()
.layout_of(ty::TypingEnv::codegen(tcx, def_id.to_def_id()).as_query_input(
tcx.type_of(def_id).instantiate_identity().skip_norm_wip(),
));
}
});
});
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_middle/src/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,18 +378,20 @@ impl<'tcx> GlobalAlloc<'tcx> {
.type_of(def_id)
.no_bound_vars()
.expect("statics should not have generic parameters");
let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
assert!(layout.is_sized());
let layout = tcx.layout_of(typing_env.as_query_input(ty));
let (size, mut align) = if let Ok(layout) = layout {
assert!(layout.is_sized());
(layout.size, layout.align.abi)
} else {
(Size::ZERO, Align::ONE)
};

// Take over-alignment from attributes into account.
let align = match tcx.codegen_fn_attrs(def_id).alignment {
Some(align_from_attribute) => {
Ord::max(align_from_attribute, layout.align.abi)
}
None => layout.align.abi,
};
if let Some(align_from_attribute) = tcx.codegen_fn_attrs(def_id).alignment {
align = Ord::max(align_from_attribute, align);
}

(layout.size, align)
(size, align)
}
}
GlobalAlloc::Memory(alloc) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1652,7 +1652,7 @@ rustc_queries! {
/// Like `param_env`, but returns the `ParamEnv` after all opaque types have been
/// replaced with their hidden type. This is used in the old trait solver
/// when in `PostAnalysis` mode and should not be called directly.
query typing_env_normalized_for_post_analysis(def_id: DefId) -> ty::TypingEnv<'tcx> {
query param_env_normalized_for_post_analysis(def_id: DefId) -> ty::ParamEnv<'tcx> {
desc { "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
}

Expand Down
53 changes: 39 additions & 14 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,17 @@ impl<'tcx> ParamEnv<'tcx> {
pub fn and<T: TypeVisitable<TyCtxt<'tcx>>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
ParamEnvAnd { param_env: self, value }
}

/// Eagerly reveal all opaque types in the `param_env`.
pub fn with_normalized(self, tcx: TyCtxt<'tcx>) -> ParamEnv<'tcx> {
// No need to reveal opaques with the new solver enabled,
// since we have lazy norm.
if tcx.next_trait_solver_globally() {
self
} else {
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds))
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
Expand Down Expand Up @@ -1050,7 +1061,7 @@ impl<'tcx> TypingEnv<'tcx> {
/// use `TypingMode::PostAnalysis`, they may still have where-clauses
/// in scope.
pub fn fully_monomorphized() -> TypingEnv<'tcx> {
Self::new(ParamEnv::empty(), TypingMode::PostAnalysis)
Self::new(ParamEnv::empty(), TypingMode::Codegen)
}

/// Create a typing environment for use during analysis outside of a body.
Expand All @@ -1067,30 +1078,44 @@ impl<'tcx> TypingEnv<'tcx> {
}

pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> TypingEnv<'tcx> {
let def_id = def_id.into_query_key();
tcx.typing_env_normalized_for_post_analysis(def_id)
TypingEnv::new(tcx.param_env_normalized_for_post_analysis(def_id), TypingMode::PostAnalysis)
}

pub fn codegen(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> TypingEnv<'tcx> {
TypingEnv::new(tcx.param_env_normalized_for_post_analysis(def_id), TypingMode::Codegen)
}

/// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all
/// opaque types in the `param_env`.
/// Modify the `typing_mode` to `PostAnalysis` or `Codegen` and eagerly reveal all opaque types
/// in the `param_env`.
pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
let TypingEnv { typing_mode, param_env } = self;
match typing_mode.0 {
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. } => {}
TypingMode::PostAnalysis => return self,
TypingMode::PostAnalysis | TypingMode::Codegen => return self,
}

// No need to reveal opaques with the new solver enabled,
// since we have lazy norm.
let param_env = if tcx.next_trait_solver_globally() {
param_env
} else {
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
};
TypingEnv { typing_mode: TypingModeEqWrapper(TypingMode::PostAnalysis), param_env }
let param_env = param_env.with_normalized(tcx);
TypingEnv::new(param_env, TypingMode::PostAnalysis)
}

/// Modify the `typing_mode` to `PostAnalysis` or `Codegen` and eagerly reveal all opaque types
/// in the `param_env`.
pub fn with_codegen_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
let TypingEnv { typing_mode, param_env } = self;
match typing_mode.0 {
TypingMode::Coherence
| TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => {}
TypingMode::Codegen => return self,
}

let param_env = param_env.with_normalized(tcx);
TypingEnv::new(param_env, TypingMode::Codegen)
}

/// Combine this typing environment with the given `value` to be used by
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,8 @@ impl<'tcx> ConstToPat<'tcx> {
//
// FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
// instead of having this logic here
let typing_env = self
.tcx
.erase_and_anonymize_regions(self.typing_env)
.with_post_analysis_normalized(self.tcx);
let typing_env =
self.tcx.erase_and_anonymize_regions(self.typing_env).with_codegen_normalized(self.tcx);
let uv = self.tcx.erase_and_anonymize_regions(uv);

// try to resolve e.g. associated constants to their definition on an impl, and then
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/elaborate_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ where
let tcx = self.tcx();

match self.elaborator.typing_env().typing_mode() {
ty::TypingMode::PostAnalysis => {}
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => {}
ty::TypingMode::Coherence
| ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,6 @@ struct VnState<'body, 'a, 'tcx> {
tcx: TyCtxt<'tcx>,
ecx: InterpCx<'tcx, DummyMachine>,
local_decls: &'body LocalDecls<'tcx>,
is_coroutine: bool,
/// Value stored in each local.
locals: IndexVec<Local, Option<VnIndex>>,
/// Locals that are assigned that value.
Expand Down Expand Up @@ -425,7 +424,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
tcx,
ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine),
local_decls,
is_coroutine: body.coroutine.is_some(),
locals: IndexVec::from_elem(None, local_decls),
rev_locals: IndexVec::with_capacity(num_values),
values: ValueSet::new(num_values),
Expand Down Expand Up @@ -577,11 +575,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
use Value::*;
let ty = self.ty(value);
// Avoid computing layouts inside a coroutine, as that can cause cycles.
let ty = if !self.is_coroutine || ty.is_scalar() {
self.ecx.layout_of(ty).ok()?
} else {
return None;
};
let ty = self.ecx.layout_of(ty).ok()?;
let op = match self.get(value) {
_ if ty.is_zst() => ImmTy::uninit(ty).into(),

Expand Down
Loading
Loading