Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 52 additions & 6 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::assert_matches::debug_assert_matches;
use std::sync::atomic::Ordering::Relaxed;

use either::{Left, Right};
Expand Down Expand Up @@ -292,6 +293,30 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
let ty::PseudoCanonicalInput { typing_env, value } = key;

// Const eval always happens in PostAnalysis or Codegen mode. See the comment in
// `InterpCx::new` for more details.
debug_assert_matches!(
typing_env.typing_mode,
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
);

// 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.
if let ty::TypingMode::Codegen = typing_env.typing_mode {
let with_postanalysis = ty::TypingEnv {
typing_mode: ty::TypingMode::PostAnalysis,
param_env: typing_env.param_env,
};
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(_)) => {}
}
}

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

Expand Down Expand Up @@ -331,23 +356,44 @@ 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()));
// Const eval always happens in PostAnalysis mode . See the comment in
assert!(value.promoted.is_some() || !tcx.is_static(value.instance.def_id()));

// Const eval always happens in PostAnalysis or Codegen mode. See the comment in
// `InterpCx::new` for more details.
debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
debug_assert_matches!(
typing_env.typing_mode,
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
);

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);
}

// 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.
if let ty::TypingMode::Codegen = typing_env.typing_mode {
let with_postanalysis = ty::TypingEnv {
typing_mode: ty::TypingMode::PostAnalysis,
param_env: typing_env.param_env,
};
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(_)) => {}
}
}

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
9 changes: 7 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::assert_matches::debug_assert_matches;

use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
Expand Down Expand Up @@ -230,9 +232,12 @@ pub(crate) fn eval_to_valtree<'tcx>(
typing_env: ty::TypingEnv<'tcx>,
cid: GlobalId<'tcx>,
) -> EvalToValTreeResult<'tcx> {
// Const eval always happens in PostAnalysis mode . See the comment in
// Const eval always happens in PostAnalysis or Codegen mode . See the comment in
// `InterpCx::new` for more details.
debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
debug_assert_matches!(
typing_env.typing_mode,
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
);
let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;

// FIXME Need to provide a span to `eval_to_valtree`
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
typing_env: ty::TypingEnv<'tcx>,
machine: M,
) -> Self {
// Const eval always happens in post analysis mode in order to be able to use the hidden types of
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
// types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
// Const eval always happens in post analysis or codegen mode in order to be able to use
// the hidden types of opaque types. This is needed for trivial things like `size_of`, but
// also for using associated types that are not specified in the opaque type. We also use
// MIR bodies whose opaque types have already been revealed, so we'd be able to at least
// partially observe the hidden types anyways.
debug_assert_matches!(
typing_env.typing_mode,
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
);
InterpCx {
machine,
tcx: tcx.at(root_span),
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 @@ -147,7 +147,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
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 @@ -1013,7 +1013,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 @@ -1328,7 +1329,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 { typing_mode, param_env }
}
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 @@ -276,7 +276,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
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
if !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())
ty::TypingEnv::codegen(tcx, def_id.to_def_id())
.as_query_input(tcx.type_of(def_id).instantiate_identity()),
);
}
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_middle/src/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,9 +384,12 @@ 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());
(layout.size, layout.align.abi)
if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) {
assert!(layout.is_sized());
(layout.size, layout.align.abi)
} else {
(Size::ZERO, Align::ONE)
}
}
}
GlobalAlloc::Memory(alloc) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,7 +1645,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 { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
}

Expand Down
51 changes: 39 additions & 12 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,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 @@ -1045,7 +1056,7 @@ impl<'tcx> TypingEnv<'tcx> {
/// use `TypingMode::PostAnalysis`, they may still have where-clauses
/// in scope.
pub fn fully_monomorphized() -> TypingEnv<'tcx> {
TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::empty() }
TypingEnv { typing_mode: TypingMode::Codegen, param_env: ParamEnv::empty() }
}

/// Create a typing environment for use during analysis outside of a body.
Expand All @@ -1061,27 +1072,43 @@ impl<'tcx> TypingEnv<'tcx> {
}

pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
tcx.typing_env_normalized_for_post_analysis(def_id)
TypingEnv {
typing_mode: TypingMode::PostAnalysis,
param_env: tcx.param_env_normalized_for_post_analysis(def_id),
}
}

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

/// 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;
if let TypingMode::PostAnalysis = typing_mode {
if let TypingMode::PostAnalysis | TypingMode::Codegen = typing_mode {
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()))
};
let param_env = param_env.with_normalized(tcx);
TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
}

/// 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;
if let TypingMode::Codegen = typing_mode {
return self;
}

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

/// Combine this typing environment with the given `value` to be used by
/// not (yet) canonicalized queries. This only works if the value does not
/// contain anything local to some `InferCtxt`, i.e. inference variables or
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ 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_regions(self.typing_env).with_post_analysis_normalized(self.tcx);
let typing_env = self.tcx.erase_regions(self.typing_env).with_codegen_normalized(self.tcx);
let uv = self.tcx.erase_regions(uv);

// try to resolve e.g. associated constants to their definition on an impl, and then
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_mir_transform/src/elaborate_drop.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::assert_matches::debug_assert_matches;
use std::{fmt, iter, mem};

use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
Expand Down Expand Up @@ -510,7 +511,10 @@ where
let subpath = self.elaborator.field_subpath(variant_path, field_idx);
let tcx = self.tcx();

assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
debug_assert_matches!(
self.elaborator.typing_env().typing_mode,
ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen
);
let field_ty = match tcx.try_normalize_erasing_regions(
self.elaborator.typing_env(),
field.ty(tcx, args),
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 @@ -216,7 +216,6 @@ struct VnState<'body, '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 @@ -254,7 +253,6 @@ impl<'body, 'tcx> VnState<'body, '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: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
Expand Down Expand Up @@ -383,11 +381,7 @@ impl<'body, 'tcx> VnState<'body, '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