Auto merge of #132460 - lcnr:questionable-uwu, r=compiler-errors

Use `TypingMode` throughout the compiler instead of `ParamEnv`

Hopefully the biggest single PR as part of https://github.com/rust-lang/types-team/issues/128.

## `infcx.typing_env` while defining opaque types

I don't know how'll be able to correctly handle opaque types when using something taking a `TypingEnv` while defining opaque types. To correctly handle the opaques we need to be able to pass in the current `opaque_type_storage` and return constraints, i.e. we need to use a proper canonical query. We should migrate all the queries used during HIR typeck and borrowck where this matters to proper canonical queries. This is

## `layout_of` and `Reveal::All`

We convert the `ParamEnv` to `Reveal::All` right at the start of the `layout_of` query, so I've changed callers of `layout_of` to already use a post analysis `TypingEnv` when encountering it.

ca87b535a0/compiler/rustc_ty_utils/src/layout.rs (L51)

## `Ty::is_[unpin|sized|whatever]`

I haven't migrated `fn is_item_raw` to use `TypingEnv`, will do so in a followup PR, this should significantly reduce the amount of `typing_env.param_env`. At some point there will probably be zero such uses as using the type system while ignoring the `typing_mode` is incorrect.

## `MirPhase` and phase-transitions

When inside of a MIR-body, we can mostly use its `MirPhase` to figure out the right `typing_mode`. This does not work during phase transitions, most notably when transitioning from `Analysis` to `Runtime`:

dae7ac133b/compiler/rustc_mir_transform/src/lib.rs (L606-L625)

All these passes still run with `MirPhase::Analysis`, but we should only use `Reveal::All` once we're run the `RevealAll` pass. This required me to manually construct the right `TypingEnv` in all these passes. Given that it feels somewhat easy to accidentally miss this going forward, I would maybe like to change `Body::phase` to an `Option` and replace it at the start of phase transitions. This then makes it clear that the MIR is currently in a weird state.

r? `@ghost`
This commit is contained in:
bors
2024-11-18 21:07:05 +00:00
240 changed files with 1745 additions and 1341 deletions

View File

@@ -215,7 +215,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Even if `ty` is normalized, the search for the unsized tail will project
// to fields, which can yield non-normalized types. So we need to provide a
// normalization function.
let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
let normalize = |ty| self.tcx.normalize_erasing_regions(self.typing_env(), ty);
ty.ptr_metadata_ty(*self.tcx, normalize)
};
return interp_ok(meta_ty(caller) == meta_ty(callee));
@@ -652,35 +652,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
};
// Obtain the underlying trait we are working on, and the adjusted receiver argument.
let (trait_, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
receiver_place.layout.ty.kind()
{
let recv = self.unpack_dyn_star(&receiver_place, data)?;
let (trait_, dyn_ty, adjusted_recv) =
if let ty::Dynamic(data, _, ty::DynStar) = receiver_place.layout.ty.kind() {
let recv = self.unpack_dyn_star(&receiver_place, data)?;
(data.principal(), recv.layout.ty, recv.ptr())
} else {
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail =
self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env);
let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
span_bug!(
self.cur_span(),
"dynamic call on non-`dyn` type {}",
receiver_tail
)
(data.principal(), recv.layout.ty, recv.ptr())
} else {
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail = self
.tcx
.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env());
let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
span_bug!(
self.cur_span(),
"dynamic call on non-`dyn` type {}",
receiver_tail
)
};
assert!(receiver_place.layout.is_unsized());
// Get the required information from the vtable.
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
// It might be surprising that we use a pointer as the receiver even if this
// is a by-val case; this works because by-val passing of an unsized `dyn
// Trait` to a function is actually desugared to a pointer.
(receiver_trait.principal(), dyn_ty, receiver_place.ptr())
};
assert!(receiver_place.layout.is_unsized());
// Get the required information from the vtable.
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
// It might be surprising that we use a pointer as the receiver even if this
// is a by-val case; this works because by-val passing of an unsized `dyn
// Trait` to a function is actually desugared to a pointer.
(receiver_trait.principal(), dyn_ty, receiver_place.ptr())
};
// Now determine the actual method to call. Usually we use the easy way of just
// looking up the method at index `idx`.
@@ -704,7 +704,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let concrete_method = Instance::expect_resolve_for_vtable(
tcx,
self.param_env,
self.typing_env(),
def_id,
instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
self.cur_span(),

View File

@@ -83,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ty::FnDef(def_id, args) => {
let instance = ty::Instance::resolve_for_fn_ptr(
*self.tcx,
self.param_env,
self.typing_env(),
def_id,
args,
)
@@ -384,7 +384,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx> {
// A<Struct> -> A<Trait> conversion
let (src_pointee_ty, dest_pointee_ty) =
self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env());
match (src_pointee_ty.kind(), dest_pointee_ty.kind()) {
(&ty::Array(_, length), &ty::Slice(_)) => {

View File

@@ -10,9 +10,7 @@ use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
};
use rustc_middle::ty::{
self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance,
};
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
use rustc_middle::{mir, span_bug};
use rustc_session::Limit;
use rustc_span::Span;
@@ -65,12 +63,12 @@ where
}
}
impl<'tcx, M> layout::HasParamEnv<'tcx> for InterpCx<'tcx, M>
impl<'tcx, M> layout::HasTypingEnv<'tcx> for InterpCx<'tcx, M>
where
M: Machine<'tcx>,
{
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
self.typing_env()
}
}
@@ -116,8 +114,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
/// This test should be symmetric, as it is primarily about layout compatibility.
pub(super) fn mir_assign_valid_types<'tcx>(
tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>,
typing_env: TypingEnv<'tcx>,
src: TyAndLayout<'tcx>,
dest: TyAndLayout<'tcx>,
) -> bool {
@@ -125,7 +122,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences.
if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, src.ty, dest.ty) {
if util::relate_types(tcx, typing_env, Variance::Covariant, src.ty, dest.ty) {
// Make sure the layout is equal, too -- just to be safe. Miri really
// needs layout equality. For performance reason we skip this check when
// the types are equal. Equal types *can* have different layouts when
@@ -145,8 +142,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
#[cfg_attr(not(debug_assertions), inline(always))]
pub(super) fn from_known_layout<'tcx>(
tcx: TyCtxtAt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>,
typing_env: TypingEnv<'tcx>,
known_layout: Option<TyAndLayout<'tcx>>,
compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -155,13 +151,7 @@ pub(super) fn from_known_layout<'tcx>(
Some(known_layout) => {
if cfg!(debug_assertions) {
let check_layout = compute()?;
if !mir_assign_valid_types(
tcx.tcx,
typing_mode,
param_env,
check_layout,
known_layout,
) {
if !mir_assign_valid_types(tcx.tcx, typing_env, check_layout, known_layout) {
span_bug!(
tcx.span,
"expected type differs from actual type.\nexpected: {}\nactual: {}",
@@ -211,9 +201,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}
pub fn typing_mode(&self) -> TypingMode<'tcx> {
/// During CTFE we're always in `PostAnalysis` mode.
#[inline(always)]
pub fn typing_env(&self) -> ty::TypingEnv<'tcx> {
debug_assert_eq!(self.param_env.reveal(), Reveal::All);
TypingMode::PostAnalysis
ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env }
}
/// Returns the span of the currently executed statement/terminator.
@@ -304,13 +296,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
.instance
.try_instantiate_mir_and_normalize_erasing_regions(
*self.tcx,
self.param_env,
self.typing_env(),
ty::EarlyBinder::bind(value),
)
.map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
}
/// The `args` are assumed to already be in our interpreter "universe" (param_env).
/// The `args` are assumed to already be in our interpreter "universe".
pub(super) fn resolve(
&self,
def: DefId,
@@ -319,7 +311,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
trace!("resolve: {:?}, {:#?}", def, args);
trace!("param_env: {:#?}", self.param_env);
trace!("args: {:#?}", args);
match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) {
match ty::Instance::try_resolve(*self.tcx, self.typing_env(), def, args) {
Ok(Some(instance)) => interp_ok(instance),
Ok(None) => throw_inval!(TooGeneric),
@@ -328,7 +320,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}
/// Check if the two things are equal in the current param_env, using an infctx to get proper
/// Check if the two things are equal in the current param_env, using an infcx to get proper
/// equality checks.
#[instrument(level = "trace", skip(self), ret)]
pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool
@@ -340,14 +332,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return true;
}
// Slow path: spin up an inference context to check if these traits are sufficiently equal.
let infcx = self.tcx.infer_ctxt().build(self.typing_mode());
let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env());
let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy_with_span(self.cur_span());
// equate the two trait refs after normalization
let a = ocx.normalize(&cause, self.param_env, a);
let b = ocx.normalize(&cause, self.param_env, b);
let a = ocx.normalize(&cause, param_env, a);
let b = ocx.normalize(&cause, param_env, b);
if let Err(terr) = ocx.eq(&cause, self.param_env, a, b) {
if let Err(terr) = ocx.eq(&cause, param_env, a, b) {
trace!(?terr);
return false;
}
@@ -572,7 +564,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let val = if self.tcx.is_static(gid.instance.def_id()) {
let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id());
let ty = instance.ty(self.tcx.tcx, self.param_env);
let ty = instance.ty(self.tcx.tcx, self.typing_env());
mir::ConstAlloc { alloc_id, ty }
} else {
self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))?
@@ -587,7 +579,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
let const_val = val.eval(*ecx.tcx, ecx.typing_env(), span).map_err(|err| {
if M::ALL_CONSTS_ARE_PRECHECKED {
match err {
ErrorHandled::TooGeneric(..) => {},

View File

@@ -40,6 +40,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
) -> InterpResult<'tcx, ConstValue<'tcx>> {
let tp_ty = args.type_at(0);
let name = tcx.item_name(def_id);
let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env };
interp_ok(match name {
sym::type_name => {
ensure_monomorphic_enough(tcx, tp_ty)?;
@@ -48,11 +49,13 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
}
sym::needs_drop => {
ensure_monomorphic_enough(tcx, tp_ty)?;
ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env))
ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env))
}
sym::pref_align_of => {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?;
let layout = tcx
.layout_of(typing_env.as_query_input(tp_ty))
.map_err(|e| err_inval!(Layout(*e)))?;
ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
}
sym::type_id => {
@@ -355,7 +358,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let should_panic = !self
.tcx
.check_validity_requirement((requirement, self.param_env.and(ty)))
.check_validity_requirement((requirement, self.typing_env().as_query_input(ty)))
.map_err(|_| err_inval!(TooGeneric))?;
if should_panic {

View File

@@ -859,7 +859,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// # Global allocations
if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);
let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env());
let mutbl = global_alloc.mutability(*self.tcx, self.param_env);
let kind = match global_alloc {
GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,

View File

@@ -8,7 +8,7 @@ use rustc_abi as abi;
use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_hir::def::Namespace;
use rustc_middle::mir::interpret::ScalarSizeMismatch;
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, mir, span_bug, ty};
@@ -297,21 +297,25 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline]
pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap();
let layout = tcx
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
.unwrap();
Self::from_scalar(Scalar::from_bool(b), layout)
}
#[inline]
pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
let ty = tcx.ty_ordering_enum(None);
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
let layout =
tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
Self::from_scalar(Scalar::from_i8(c as i8), layout)
}
pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
let layout = tcx
.layout_of(
ty::ParamEnv::reveal_all().and(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
ty::TypingEnv::fully_monomorphized()
.as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
)
.unwrap();
Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
@@ -341,7 +345,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline]
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>)) -> (Self, Self) {
pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>)) -> (Self, Self) {
let layout = self.layout;
let (val0, val1) = self.to_scalar_pair();
(
@@ -773,8 +777,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
)?;
if !mir_assign_valid_types(
*self.tcx,
self.typing_mode(),
self.param_env,
self.typing_env(),
self.layout_of(normalized_place_ty)?,
op.layout,
) {
@@ -833,9 +836,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
})
};
let layout =
from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
self.layout_of(ty).into()
})?;
from_known_layout(self.tcx, self.typing_env(), layout, || self.layout_of(ty).into())?;
let imm = match val_val {
mir::ConstValue::Indirect { alloc_id, offset } => {
// This is const data, no mutation allowed.

View File

@@ -533,7 +533,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
OffsetOf(fields) => {
let val =
self.tcx.offset_of_subfield(self.param_env, layout, fields.iter()).bytes();
self.tcx.offset_of_subfield(self.typing_env(), layout, fields.iter()).bytes();
ImmTy::from_uint(val, usize_layout())
}
UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx),

View File

@@ -540,8 +540,7 @@ where
)?;
if !mir_assign_valid_types(
*self.tcx,
self.typing_mode(),
self.param_env,
self.typing_env(),
self.layout_of(normalized_place_ty)?,
place.layout,
) {
@@ -871,13 +870,8 @@ where
) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
let layout_compat = mir_assign_valid_types(
*self.tcx,
self.typing_mode(),
self.param_env,
src.layout(),
dest.layout(),
);
let layout_compat =
mir_assign_valid_types(*self.tcx, self.typing_env(), src.layout(), dest.layout());
if !allow_transmute && !layout_compat {
span_bug!(
self.cur_span(),

View File

@@ -379,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
for &const_ in body.required_consts() {
let c =
self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {
c.eval(*self.tcx, self.typing_env(), const_.span).map_err(|err| {
err.emit_note(*self.tcx);
err
})?;
@@ -596,13 +596,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return interp_ok(layout);
}
let layout =
from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty).into()
})?;
let layout = from_known_layout(self.tcx, self.typing_env(), layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty).into()
})?;
// Layouts of locals are requested a lot, so we cache them.
state.layout.set(Some(layout));

View File

@@ -418,7 +418,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
.collect::<InterpResult<'tcx, Vec<_>>>()?;
let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
let fn_sig =
self.tcx.normalize_erasing_late_bound_regions(self.typing_env(), fn_sig_binder);
let extra_args = &args[fn_sig.inputs().len()..];
let extra_args =
self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));

View File

@@ -448,7 +448,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
meta: MemPlaceMeta<M::Provenance>,
pointee: TyAndLayout<'tcx>,
) -> InterpResult<'tcx> {
let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env);
let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env());
match tail.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
@@ -568,7 +568,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
};
let (size, _align) =
global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env);
global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env());
if let GlobalAlloc::Static(did) = global_alloc {
let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
@@ -955,7 +955,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
) -> Cow<'e, RangeSet> {
assert!(layout.ty.is_union());
assert!(layout.is_sized(), "there are no unsized unions");
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env());
return M::cached_union_data_range(ecx, layout.ty, || {
let mut out = RangeSet(Vec::new());
union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out);