mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
layout computation: eagerly error for unexpected unsized fields
This commit is contained in:
parent
16be6666d4
commit
697450151c
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@ mod layout;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use layout::LayoutCalculator;
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
@ -393,6 +393,14 @@ impl HasDataLayout for TargetDataLayout {
|
||||
}
|
||||
}
|
||||
|
||||
// used by rust-analyzer
|
||||
impl HasDataLayout for &TargetDataLayout {
|
||||
#[inline]
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
(**self).data_layout()
|
||||
}
|
||||
}
|
||||
|
||||
/// Endianness of the target, which must match cfg(target-endian).
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Endian {
|
||||
|
@ -319,7 +319,7 @@ pub fn valtree_to_const_value<'tcx>(
|
||||
let branches = valtree.unwrap_branch();
|
||||
// Find the non-ZST field. (There can be aligned ZST!)
|
||||
for (i, &inner_valtree) in branches.iter().enumerate() {
|
||||
let field = layout.field(&LayoutCx { tcx, param_env }, i);
|
||||
let field = layout.field(&LayoutCx::new(tcx, param_env), i);
|
||||
if !field.is_zst() {
|
||||
return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
|
||||
}
|
||||
|
@ -940,7 +940,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
||||
) -> Cow<'e, RangeSet> {
|
||||
assert!(layout.ty.is_union());
|
||||
assert!(layout.abi.is_sized(), "there are no unsized unions");
|
||||
let layout_cx = LayoutCx { tcx: *ecx.tcx, param_env: ecx.param_env };
|
||||
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_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);
|
||||
|
@ -1,5 +1,7 @@
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::layout::{
|
||||
HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement,
|
||||
};
|
||||
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
||||
@ -30,7 +32,7 @@ pub fn check_validity_requirement<'tcx>(
|
||||
return Ok(!layout.abi.is_uninhabited());
|
||||
}
|
||||
|
||||
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
|
||||
let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
|
||||
if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
check_validity_requirement_strict(layout, &layout_cx, kind)
|
||||
} else {
|
||||
@ -47,7 +49,7 @@ fn check_validity_requirement_strict<'tcx>(
|
||||
) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
|
||||
|
||||
let mut cx = InterpCx::new(cx.tcx, rustc_span::DUMMY_SP, cx.param_env, machine);
|
||||
let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine);
|
||||
|
||||
let allocated = cx
|
||||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::borrow::Cow;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Bound;
|
||||
use std::{cmp, fmt};
|
||||
@ -287,19 +286,13 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LayoutCx<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
pub calc: LayoutCalculator<TyCtxt<'tcx>>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutCalculator for LayoutCx<'tcx> {
|
||||
type TargetDataLayoutRef = &'tcx TargetDataLayout;
|
||||
|
||||
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
|
||||
self.tcx.dcx().delayed_bug(txt);
|
||||
}
|
||||
|
||||
fn current_data_layout(&self) -> Self::TargetDataLayoutRef {
|
||||
&self.tcx.data_layout
|
||||
impl<'tcx> LayoutCx<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
Self { calc: LayoutCalculator::new(tcx), param_env }
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,25 +569,25 @@ impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> {
|
||||
|
||||
impl<'tcx> HasDataLayout for LayoutCx<'tcx> {
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
self.tcx.data_layout()
|
||||
self.calc.cx.data_layout()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
|
||||
fn target_spec(&self) -> &Target {
|
||||
self.tcx.target_spec()
|
||||
self.calc.cx.target_spec()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.tcx.wasm_c_abi_opt()
|
||||
self.calc.cx.wasm_c_abi_opt()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx.tcx()
|
||||
self.calc.cx
|
||||
}
|
||||
}
|
||||
|
||||
@ -695,7 +688,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
|
||||
_: Span,
|
||||
_: Ty<'tcx>,
|
||||
) -> &'tcx LayoutError<'tcx> {
|
||||
self.tcx.arena.alloc(err)
|
||||
self.tcx().arena.alloc(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1323,7 +1316,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
where
|
||||
I: Iterator<Item = (VariantIdx, FieldIdx)>,
|
||||
{
|
||||
let cx = LayoutCx { tcx: self, param_env };
|
||||
let cx = LayoutCx::new(self, param_env);
|
||||
let mut offset = Size::ZERO;
|
||||
|
||||
for (variant, field) in indices {
|
||||
|
@ -128,7 +128,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
|
||||
}
|
||||
|
||||
Err(layout_error) => {
|
||||
tcx.dcx().emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
|
||||
tcx.dcx().emit_err(Spanned { node: layout_error.into_diagnostic(), span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ pub mod rustc {
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_target::abi::Layout;
|
||||
|
||||
@ -128,7 +128,7 @@ pub mod rustc {
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
let ty = cx.tcx.erase_regions(ty);
|
||||
let ty = cx.tcx().erase_regions(ty);
|
||||
cx.layout_of(ty).map(|tl| tl.layout)
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ pub(crate) mod rustc {
|
||||
return Err(Err::TypeError(e));
|
||||
}
|
||||
|
||||
let target = cx.tcx.data_layout();
|
||||
let target = cx.data_layout();
|
||||
let pointer_size = target.pointer_size;
|
||||
|
||||
match ty.kind() {
|
||||
@ -320,7 +320,7 @@ pub(crate) mod rustc {
|
||||
|
||||
// Computes the variant of a given index.
|
||||
let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| {
|
||||
let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index));
|
||||
let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
|
||||
let variant_def = Def::Variant(def.variant(index));
|
||||
let variant_layout = ty_variant(cx, (ty, layout), index);
|
||||
Self::from_variant(
|
||||
@ -417,7 +417,7 @@ pub(crate) mod rustc {
|
||||
}
|
||||
}
|
||||
}
|
||||
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx));
|
||||
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx()));
|
||||
}
|
||||
|
||||
// Append the fields, in memory order, to the layout.
|
||||
@ -509,12 +509,12 @@ pub(crate) mod rustc {
|
||||
match layout.variants {
|
||||
Variants::Single { index } => {
|
||||
let field = &def.variant(index).fields[i];
|
||||
field.ty(cx.tcx, args)
|
||||
field.ty(cx.tcx(), args)
|
||||
}
|
||||
// Discriminant field for enums (where applicable).
|
||||
Variants::Multiple { tag, .. } => {
|
||||
assert_eq!(i.as_usize(), 0);
|
||||
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx)
|
||||
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -531,7 +531,7 @@ pub(crate) mod rustc {
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
i: VariantIdx,
|
||||
) -> Layout<'tcx> {
|
||||
let ty = cx.tcx.erase_regions(ty);
|
||||
let ty = cx.tcx().erase_regions(ty);
|
||||
TyAndLayout { ty, layout }.for_variant(&cx, i).layout
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ mod rustc {
|
||||
pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
|
||||
let Self { src, dst, assume, context } = self;
|
||||
|
||||
let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() };
|
||||
let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all());
|
||||
|
||||
// Convert `src` and `dst` from their rustc representations, to `Tree`-based
|
||||
// representations.
|
||||
|
@ -331,7 +331,7 @@ fn fn_abi_of_fn_ptr<'tcx>(
|
||||
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
|
||||
let (param_env, (sig, extra_args)) = query.into_parts();
|
||||
|
||||
let cx = LayoutCx { tcx, param_env };
|
||||
let cx = LayoutCx::new(tcx, param_env);
|
||||
fn_abi_new_uncached(&cx, sig, extra_args, None, None, false)
|
||||
}
|
||||
|
||||
@ -347,7 +347,7 @@ fn fn_abi_of_instance<'tcx>(
|
||||
instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty());
|
||||
|
||||
fn_abi_new_uncached(
|
||||
&LayoutCx { tcx, param_env },
|
||||
&LayoutCx::new(tcx, param_env),
|
||||
sig,
|
||||
extra_args,
|
||||
caller_location,
|
||||
@ -386,12 +386,14 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||
attrs.set(ArgAttribute::NonNull);
|
||||
}
|
||||
|
||||
let tcx = cx.tcx();
|
||||
|
||||
if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
|
||||
let kind = if let Some(kind) = pointee.safe {
|
||||
Some(kind)
|
||||
} else if let Some(pointee) = drop_target_pointee {
|
||||
// The argument to `drop_in_place` is semantically equivalent to a mutable reference.
|
||||
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) })
|
||||
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.param_env()) })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -415,12 +417,12 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
|
||||
// `noalias` for it. This can be turned off using an unstable flag.
|
||||
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
|
||||
let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias;
|
||||
let noalias_for_box = tcx.sess.opts.unstable_opts.box_noalias;
|
||||
|
||||
// LLVM prior to version 12 had known miscompiles in the presence of noalias attributes
|
||||
// (see #54878), so it was conditionally disabled, but we don't support earlier
|
||||
// versions at all anymore. We still support turning it off using -Zmutable-noalias.
|
||||
let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
|
||||
let noalias_mut_ref = tcx.sess.opts.unstable_opts.mutable_noalias;
|
||||
|
||||
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
|
||||
// `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
|
||||
@ -458,6 +460,7 @@ fn fn_abi_sanity_check<'tcx>(
|
||||
spec_abi: SpecAbi,
|
||||
arg: &ArgAbi<'tcx, Ty<'tcx>>,
|
||||
) {
|
||||
let tcx = cx.tcx();
|
||||
match &arg.mode {
|
||||
PassMode::Ignore => {}
|
||||
PassMode::Direct(_) => {
|
||||
@ -484,7 +487,7 @@ fn fn_abi_sanity_check<'tcx>(
|
||||
// It needs to switch to something else before stabilization can happen.
|
||||
// (See issue: https://github.com/rust-lang/rust/issues/117271)
|
||||
assert!(
|
||||
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64")
|
||||
matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64")
|
||||
|| matches!(spec_abi, SpecAbi::PtxKernel | SpecAbi::Unadjusted),
|
||||
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\
|
||||
Problematic type: {:#?}",
|
||||
@ -516,7 +519,7 @@ fn fn_abi_sanity_check<'tcx>(
|
||||
// With metadata. Must be unsized and not on the stack.
|
||||
assert!(arg.layout.is_unsized() && !on_stack);
|
||||
// Also, must not be `extern` type.
|
||||
let tail = cx.tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
|
||||
let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
|
||||
if matches!(tail.kind(), ty::Foreign(..)) {
|
||||
// These types do not have metadata, so having `meta_attrs` is bogus.
|
||||
// Conceptually, unsized arguments must be copied around, which requires dynamically
|
||||
@ -546,7 +549,8 @@ fn fn_abi_new_uncached<'tcx>(
|
||||
// FIXME(eddyb) replace this with something typed, like an `enum`.
|
||||
force_thin_self_ptr: bool,
|
||||
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
|
||||
let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
|
||||
let tcx = cx.tcx();
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
|
||||
|
||||
let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
|
||||
|
||||
@ -576,7 +580,7 @@ fn fn_abi_new_uncached<'tcx>(
|
||||
};
|
||||
|
||||
let is_drop_in_place =
|
||||
fn_def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::DropInPlace));
|
||||
fn_def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::DropInPlace));
|
||||
|
||||
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, &'tcx FnAbiError<'tcx>> {
|
||||
let span = tracing::debug_span!("arg_of");
|
||||
@ -588,8 +592,7 @@ fn fn_abi_new_uncached<'tcx>(
|
||||
_ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
|
||||
});
|
||||
|
||||
let layout =
|
||||
cx.layout_of(ty).map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::Layout(*err)))?;
|
||||
let layout = cx.layout_of(ty).map_err(|err| &*tcx.arena.alloc(FnAbiError::Layout(*err)))?;
|
||||
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
|
||||
// Don't pass the vtable, it's not an argument of the virtual fn.
|
||||
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
|
||||
@ -638,7 +641,7 @@ fn fn_abi_new_uncached<'tcx>(
|
||||
fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?;
|
||||
debug!("fn_abi_new_uncached = {:?}", fn_abi);
|
||||
fn_abi_sanity_check(cx, &fn_abi, sig.abi);
|
||||
Ok(cx.tcx.arena.alloc(fn_abi))
|
||||
Ok(tcx.arena.alloc(fn_abi))
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(cx))]
|
||||
@ -670,17 +673,18 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tcx = cx.tcx();
|
||||
|
||||
if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic {
|
||||
// Look up the deduced parameter attributes for this function, if we have its def ID and
|
||||
// we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
|
||||
// as appropriate.
|
||||
let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No
|
||||
&& cx.tcx.sess.opts.incremental.is_none()
|
||||
{
|
||||
fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
let deduced_param_attrs =
|
||||
if tcx.sess.opts.optimize != OptLevel::No && tcx.sess.opts.incremental.is_none() {
|
||||
fn_def_id.map(|fn_def_id| tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
|
||||
let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
|
||||
if arg.is_ignore() {
|
||||
@ -689,7 +693,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
||||
|
||||
// Avoid returning floats in x87 registers on x86 as loading and storing from x87
|
||||
// registers will quiet signalling NaNs.
|
||||
if cx.tcx.sess.target.arch == "x86"
|
||||
if tcx.sess.target.arch == "x86"
|
||||
&& arg_idx.is_none()
|
||||
// Intrinsics themselves are not actual "real" functions, so theres no need to
|
||||
// change their ABIs.
|
||||
@ -744,7 +748,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
||||
// that's how we connect up to LLVM and it's unstable
|
||||
// anyway, we control all calls to it in libstd.
|
||||
Abi::Vector { .. }
|
||||
if abi != SpecAbi::RustIntrinsic && cx.tcx.sess.target.simd_types_indirect =>
|
||||
if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect =>
|
||||
{
|
||||
arg.make_indirect();
|
||||
return;
|
||||
@ -793,7 +797,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
||||
} else {
|
||||
fn_abi
|
||||
.adjust_for_foreign_abi(cx, abi)
|
||||
.map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
|
||||
.map_err(|err| &*tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -9,7 +9,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::layout::{
|
||||
FloatExt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
|
||||
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
|
||||
};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{
|
||||
@ -63,14 +63,14 @@ fn layout_of<'tcx>(
|
||||
return tcx.layout_of(param_env.and(ty));
|
||||
}
|
||||
|
||||
let cx = LayoutCx { tcx, param_env };
|
||||
let cx = LayoutCx::new(tcx, param_env);
|
||||
|
||||
let layout = layout_of_uncached(&cx, ty)?;
|
||||
let layout = TyAndLayout { ty, layout };
|
||||
|
||||
// If we are running with `-Zprint-type-sizes`, maybe record layouts
|
||||
// for dumping later.
|
||||
if cx.tcx.sess.opts.unstable_opts.print_type_sizes {
|
||||
if cx.tcx().sess.opts.unstable_opts.print_type_sizes {
|
||||
record_layout_for_printing(&cx, layout);
|
||||
}
|
||||
|
||||
@ -80,7 +80,36 @@ fn layout_of<'tcx>(
|
||||
}
|
||||
|
||||
fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
|
||||
cx.tcx.arena.alloc(err)
|
||||
cx.tcx().arena.alloc(err)
|
||||
}
|
||||
|
||||
fn map_error<'tcx>(
|
||||
cx: &LayoutCx<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
err: LayoutCalculatorError,
|
||||
) -> &'tcx LayoutError<'tcx> {
|
||||
let err = match err {
|
||||
LayoutCalculatorError::SizeOverflow => {
|
||||
// This is sometimes not a compile error in `check` builds.
|
||||
LayoutError::SizeOverflow(ty)
|
||||
}
|
||||
LayoutCalculatorError::UnexpectedUnsized => {
|
||||
// This is sometimes not a compile error if there are trivially false where
|
||||
// clauses, but it is always a compiler error in the empty environment.
|
||||
if cx.param_env.caller_bounds().is_empty() {
|
||||
cx.tcx().dcx().delayed_bug(format!(
|
||||
"encountered unexpected unsized field in layout of {ty:?}"
|
||||
));
|
||||
}
|
||||
LayoutError::Unknown(ty)
|
||||
}
|
||||
LayoutCalculatorError::EmptyUnion => {
|
||||
// This is always a compile error.
|
||||
cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}"));
|
||||
LayoutError::Unknown(ty)
|
||||
}
|
||||
};
|
||||
error(cx, err)
|
||||
}
|
||||
|
||||
fn univariant_uninterned<'tcx>(
|
||||
@ -90,13 +119,12 @@ fn univariant_uninterned<'tcx>(
|
||||
repr: &ReprOptions,
|
||||
kind: StructKind,
|
||||
) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
|
||||
let dl = cx.data_layout();
|
||||
let pack = repr.pack;
|
||||
if pack.is_some() && repr.align.is_some() {
|
||||
cx.tcx.dcx().bug("struct cannot be packed and aligned");
|
||||
cx.tcx().dcx().bug("struct cannot be packed and aligned");
|
||||
}
|
||||
|
||||
cx.univariant(dl, fields, repr, kind).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))
|
||||
cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
|
||||
}
|
||||
|
||||
fn layout_of_uncached<'tcx>(
|
||||
@ -110,7 +138,7 @@ fn layout_of_uncached<'tcx>(
|
||||
return Err(error(cx, LayoutError::ReferencesError(guar)));
|
||||
}
|
||||
|
||||
let tcx = cx.tcx;
|
||||
let tcx = cx.tcx();
|
||||
let param_env = cx.param_env;
|
||||
let dl = cx.data_layout();
|
||||
let scalar_unit = |value: Primitive| {
|
||||
@ -188,7 +216,7 @@ fn layout_of_uncached<'tcx>(
|
||||
}
|
||||
|
||||
// The never type.
|
||||
ty::Never => tcx.mk_layout(cx.layout_of_never_type()),
|
||||
ty::Never => tcx.mk_layout(cx.calc.layout_of_never_type()),
|
||||
|
||||
// Potentially-wide pointers.
|
||||
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
|
||||
@ -264,7 +292,7 @@ fn layout_of_uncached<'tcx>(
|
||||
};
|
||||
|
||||
// Effectively a (ptr, meta) tuple.
|
||||
tcx.mk_layout(cx.scalar_pair(data_ptr, metadata))
|
||||
tcx.mk_layout(cx.calc.scalar_pair(data_ptr, metadata))
|
||||
}
|
||||
|
||||
ty::Dynamic(_, _, ty::DynStar) => {
|
||||
@ -272,7 +300,7 @@ fn layout_of_uncached<'tcx>(
|
||||
data.valid_range_mut().start = 0;
|
||||
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
||||
vtable.valid_range_mut().start = 1;
|
||||
tcx.mk_layout(cx.scalar_pair(data, vtable))
|
||||
tcx.mk_layout(cx.calc.scalar_pair(data, vtable))
|
||||
}
|
||||
|
||||
// Arrays and slices.
|
||||
@ -531,7 +559,7 @@ fn layout_of_uncached<'tcx>(
|
||||
|
||||
if def.is_union() {
|
||||
if def.repr().pack.is_some() && def.repr().align.is_some() {
|
||||
cx.tcx.dcx().span_delayed_bug(
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(def.did()),
|
||||
"union cannot be packed and aligned",
|
||||
);
|
||||
@ -539,8 +567,9 @@ fn layout_of_uncached<'tcx>(
|
||||
}
|
||||
|
||||
return Ok(tcx.mk_layout(
|
||||
cx.layout_of_union(&def.repr(), &variants)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
|
||||
cx.calc
|
||||
.layout_of_union(&def.repr(), &variants)
|
||||
.map_err(|err| map_error(cx, ty, err))?,
|
||||
));
|
||||
}
|
||||
|
||||
@ -557,7 +586,7 @@ fn layout_of_uncached<'tcx>(
|
||||
})?;
|
||||
|
||||
if is_unsized {
|
||||
cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
|
||||
tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
|
||||
Err(error(cx, LayoutError::Unknown(ty)))
|
||||
} else {
|
||||
Ok(())
|
||||
@ -600,19 +629,20 @@ fn layout_of_uncached<'tcx>(
|
||||
!tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, param_env)
|
||||
});
|
||||
|
||||
let Some(layout) = cx.layout_of_struct_or_enum(
|
||||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
def.is_unsafe_cell(),
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
dont_niche_optimize_enum,
|
||||
!maybe_unsized,
|
||||
) else {
|
||||
return Err(error(cx, LayoutError::SizeOverflow(ty)));
|
||||
};
|
||||
let layout = cx
|
||||
.calc
|
||||
.layout_of_struct_or_enum(
|
||||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
def.is_unsafe_cell(),
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
dont_niche_optimize_enum,
|
||||
!maybe_unsized,
|
||||
)
|
||||
.map_err(|err| map_error(cx, ty, err))?;
|
||||
|
||||
// If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
|
||||
if cfg!(debug_assertions)
|
||||
@ -623,7 +653,7 @@ fn layout_of_uncached<'tcx>(
|
||||
let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
|
||||
*variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement.layout;
|
||||
|
||||
let Some(unsized_layout) = cx.layout_of_struct_or_enum(
|
||||
let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
|
||||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
@ -812,7 +842,7 @@ fn coroutine_layout<'tcx>(
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
use SavedLocalEligibility::*;
|
||||
let tcx = cx.tcx;
|
||||
let tcx = cx.tcx();
|
||||
let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args);
|
||||
|
||||
let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else {
|
||||
@ -832,7 +862,7 @@ fn coroutine_layout<'tcx>(
|
||||
value: Primitive::Int(discr_int, false),
|
||||
valid_range: WrappingRange { start: 0, end: max_discr },
|
||||
};
|
||||
let tag_layout = cx.tcx.mk_layout(LayoutS::scalar(cx, tag));
|
||||
let tag_layout = tcx.mk_layout(LayoutS::scalar(cx, tag));
|
||||
|
||||
let promoted_layouts = ineligible_locals.iter().map(|local| {
|
||||
let field_ty = instantiate_field(info.field_tys[local].ty);
|
||||
@ -1025,7 +1055,7 @@ fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tc
|
||||
// (delay format until we actually need it)
|
||||
let record = |kind, packed, opt_discr_size, variants| {
|
||||
let type_desc = with_no_trimmed_paths!(format!("{}", layout.ty));
|
||||
cx.tcx.sess.code_stats.record_type_size(
|
||||
cx.tcx().sess.code_stats.record_type_size(
|
||||
kind,
|
||||
type_desc,
|
||||
layout.align.abi,
|
||||
@ -1148,8 +1178,8 @@ fn variant_info_for_coroutine<'tcx>(
|
||||
return (vec![], None);
|
||||
};
|
||||
|
||||
let coroutine = cx.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()).unwrap();
|
||||
let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
|
||||
let coroutine = cx.tcx().coroutine_layout(def_id, args.as_coroutine().kind_ty()).unwrap();
|
||||
let upvar_names = cx.tcx().closure_saved_names_of_captured_variables(def_id);
|
||||
|
||||
let mut upvars_size = Size::ZERO;
|
||||
let upvar_fields: Vec<_> = args
|
||||
|
@ -1,20 +1,22 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout};
|
||||
use rustc_target::abi::*;
|
||||
|
||||
/// Enforce some basic invariants on layouts.
|
||||
pub(super) fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
|
||||
let tcx = cx.tcx();
|
||||
|
||||
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
||||
if layout.ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
|
||||
if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
|
||||
assert!(layout.abi.is_uninhabited());
|
||||
}
|
||||
|
||||
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
|
||||
bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
|
||||
}
|
||||
if layout.size.bytes() >= cx.tcx.data_layout.obj_size_bound() {
|
||||
if layout.size.bytes() >= tcx.data_layout.obj_size_bound() {
|
||||
bug!("size is too large, in the following layout:\n{layout:#?}");
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@ pub fn create_ecx<'tcx>(
|
||||
config: &MiriConfig,
|
||||
) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let layout_cx = LayoutCx { tcx, param_env };
|
||||
let layout_cx = LayoutCx::new(tcx, param_env);
|
||||
let mut ecx =
|
||||
InterpCx::new(tcx, rustc_span::DUMMY_SP, param_env, MiriMachine::new(config, layout_cx));
|
||||
|
||||
|
@ -21,7 +21,7 @@ use rustc_middle::{
|
||||
query::TyCtxtAt,
|
||||
ty::{
|
||||
self,
|
||||
layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
|
||||
layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout},
|
||||
Instance, Ty, TyCtxt,
|
||||
},
|
||||
};
|
||||
@ -382,7 +382,7 @@ pub struct PrimitiveLayouts<'tcx> {
|
||||
|
||||
impl<'tcx> PrimitiveLayouts<'tcx> {
|
||||
fn new(layout_cx: LayoutCx<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> {
|
||||
let tcx = layout_cx.tcx;
|
||||
let tcx = layout_cx.tcx();
|
||||
let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit);
|
||||
let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
|
||||
Ok(Self {
|
||||
@ -597,13 +597,12 @@ pub struct MiriMachine<'tcx> {
|
||||
|
||||
impl<'tcx> MiriMachine<'tcx> {
|
||||
pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self {
|
||||
let tcx = layout_cx.tcx;
|
||||
let tcx = layout_cx.tcx();
|
||||
let local_crates = helpers::get_local_crates(tcx);
|
||||
let layouts =
|
||||
PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
|
||||
let profiler = config.measureme_out.as_ref().map(|out| {
|
||||
let crate_name = layout_cx
|
||||
.tcx
|
||||
let crate_name = tcx
|
||||
.sess
|
||||
.opts
|
||||
.crate_name
|
||||
@ -701,7 +700,7 @@ impl<'tcx> MiriMachine<'tcx> {
|
||||
clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
|
||||
#[cfg(unix)]
|
||||
native_lib: config.native_lib.as_ref().map(|lib_file_path| {
|
||||
let target_triple = layout_cx.tcx.sess.opts.target_triple.triple();
|
||||
let target_triple = tcx.sess.opts.target_triple.triple();
|
||||
// Check if host target == the session target.
|
||||
if env!("TARGET") != target_triple {
|
||||
panic!(
|
||||
|
@ -1,13 +1,13 @@
|
||||
//! Compute the binary representation of a type
|
||||
|
||||
use std::{borrow::Cow, fmt};
|
||||
use std::fmt;
|
||||
|
||||
use base_db::salsa::Cycle;
|
||||
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
|
||||
use hir_def::{
|
||||
layout::{
|
||||
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions,
|
||||
Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
|
||||
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
|
||||
Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
|
||||
},
|
||||
LocalFieldId, StructId,
|
||||
};
|
||||
@ -15,7 +15,6 @@ use la_arena::{Idx, RawIdx};
|
||||
use rustc_abi::AddressSpace;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
@ -107,19 +106,24 @@ impl fmt::Display for LayoutError {
|
||||
}
|
||||
}
|
||||
|
||||
struct LayoutCx<'a> {
|
||||
target: &'a TargetDataLayout,
|
||||
impl From<LayoutCalculatorError> for LayoutError {
|
||||
fn from(err: LayoutCalculatorError) -> Self {
|
||||
match err {
|
||||
LayoutCalculatorError::UnexpectedUnsized | LayoutCalculatorError::EmptyUnion => {
|
||||
LayoutError::Unknown
|
||||
}
|
||||
LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LayoutCalculator for LayoutCx<'a> {
|
||||
type TargetDataLayoutRef = &'a TargetDataLayout;
|
||||
struct LayoutCx<'a> {
|
||||
calc: LayoutCalculator<&'a TargetDataLayout>,
|
||||
}
|
||||
|
||||
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
|
||||
never!("{}", txt.into());
|
||||
}
|
||||
|
||||
fn current_data_layout(&self) -> &'a TargetDataLayout {
|
||||
self.target
|
||||
impl<'a> LayoutCx<'a> {
|
||||
fn new(target: &'a TargetDataLayout) -> Self {
|
||||
Self { calc: LayoutCalculator::new(target) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,8 +209,8 @@ pub fn layout_of_ty_query(
|
||||
let Ok(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let dl = &*target;
|
||||
let cx = LayoutCx::new(dl);
|
||||
let ty = normalize(db, trait_env.clone(), ty);
|
||||
let result = match ty.kind(Interner) {
|
||||
TyKind::Adt(AdtId(def), subst) => {
|
||||
@ -281,7 +285,7 @@ pub fn layout_of_ty_query(
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
|
||||
let fields = fields.iter().collect::<IndexVec<_, _>>();
|
||||
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
|
||||
cx.calc.univariant(&fields, &ReprOptions::default(), kind)?
|
||||
}
|
||||
TyKind::Array(element, count) => {
|
||||
let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
|
||||
@ -367,12 +371,12 @@ pub fn layout_of_ty_query(
|
||||
};
|
||||
|
||||
// Effectively a (ptr, meta) tuple.
|
||||
cx.scalar_pair(data_ptr, metadata)
|
||||
cx.calc.scalar_pair(data_ptr, metadata)
|
||||
}
|
||||
TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?,
|
||||
TyKind::Never => cx.layout_of_never_type(),
|
||||
TyKind::FnDef(_, _) => layout_of_unit(&cx)?,
|
||||
TyKind::Never => cx.calc.layout_of_never_type(),
|
||||
TyKind::Dyn(_) | TyKind::Foreign(_) => {
|
||||
let mut unit = layout_of_unit(&cx, dl)?;
|
||||
let mut unit = layout_of_unit(&cx)?;
|
||||
match &mut unit.abi {
|
||||
Abi::Aggregate { sized } => *sized = false,
|
||||
_ => return Err(LayoutError::Unknown),
|
||||
@ -414,8 +418,7 @@ pub fn layout_of_ty_query(
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
|
||||
let fields = fields.iter().collect::<IndexVec<_, _>>();
|
||||
cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized)
|
||||
.ok_or(LayoutError::Unknown)?
|
||||
cx.calc.univariant(&fields, &ReprOptions::default(), StructKind::AlwaysSized)?
|
||||
}
|
||||
TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) => {
|
||||
return Err(LayoutError::NotImplemented)
|
||||
@ -447,14 +450,14 @@ pub fn layout_of_ty_recover(
|
||||
Err(LayoutError::RecursiveTypeWithoutIndirection)
|
||||
}
|
||||
|
||||
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
|
||||
cx.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
|
||||
dl,
|
||||
IndexSlice::empty(),
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)
|
||||
.ok_or(LayoutError::Unknown)
|
||||
fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> {
|
||||
cx.calc
|
||||
.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
|
||||
IndexSlice::empty(),
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
|
||||
|
@ -5,7 +5,7 @@ use std::{cmp, ops::Bound};
|
||||
use base_db::salsa::Cycle;
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
|
||||
layout::{Integer, ReprOptions, TargetDataLayout},
|
||||
AdtId, VariantId,
|
||||
};
|
||||
use intern::sym;
|
||||
@ -36,8 +36,8 @@ pub fn layout_of_adt_query(
|
||||
let Ok(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let dl = &*target;
|
||||
let cx = LayoutCx::new(dl);
|
||||
let handle_variant = |def: VariantId, var: &VariantData| {
|
||||
var.fields()
|
||||
.iter()
|
||||
@ -73,9 +73,9 @@ pub fn layout_of_adt_query(
|
||||
.collect::<SmallVec<[_; 1]>>();
|
||||
let variants = variants.iter().map(|it| it.iter().collect()).collect::<IndexVec<_, _>>();
|
||||
let result = if matches!(def, AdtId::UnionId(..)) {
|
||||
cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)?
|
||||
cx.calc.layout_of_union(&repr, &variants)?
|
||||
} else {
|
||||
cx.layout_of_struct_or_enum(
|
||||
cx.calc.layout_of_struct_or_enum(
|
||||
&repr,
|
||||
&variants,
|
||||
matches!(def, AdtId::EnumId(..)),
|
||||
@ -103,8 +103,7 @@ pub fn layout_of_adt_query(
|
||||
.next()
|
||||
.and_then(|it| it.iter().last().map(|it| !it.is_unsized()))
|
||||
.unwrap_or(true),
|
||||
)
|
||||
.ok_or(LayoutError::SizeOverflow)?
|
||||
)?
|
||||
};
|
||||
Ok(Arc::new(result))
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
//@ known-bug: #124182
|
||||
struct LazyLock<T> {
|
||||
data: (Copy, fn() -> T),
|
||||
}
|
||||
|
||||
impl<T> LazyLock<T> {
|
||||
pub const fn new(f: fn() -> T) -> LazyLock<T> {
|
||||
LazyLock { data: (None, f) }
|
||||
}
|
||||
}
|
||||
|
||||
struct A<T = i32>(Option<T>);
|
||||
|
||||
impl<T> Default for A<T> {
|
||||
fn default() -> Self {
|
||||
A(None)
|
||||
}
|
||||
}
|
||||
|
||||
static EMPTY_SET: LazyLock<A<i32>> = LazyLock::new(A::default);
|
||||
|
||||
fn main() {}
|
@ -1,21 +1,12 @@
|
||||
//@ known-bug: rust-lang/rust#126939
|
||||
|
||||
struct MySlice<T: Copy>(bool, T);
|
||||
struct MySlice<T>(T);
|
||||
type MySliceBool = MySlice<[bool]>;
|
||||
|
||||
use std::mem;
|
||||
|
||||
struct P2<T> {
|
||||
a: T,
|
||||
struct P2 {
|
||||
b: MySliceBool,
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($t:ty, $align:expr) => ({
|
||||
assert_eq!(mem::align_of::<$t>(), $align);
|
||||
});
|
||||
}
|
||||
static CHECK: () = assert!(align_of::<P2>() == 1);
|
||||
|
||||
pub fn main() {
|
||||
check!(P2<u8>, 1);
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -76,3 +76,8 @@ impl S {
|
||||
|
||||
#[rustc_layout(debug)]
|
||||
type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
|
||||
|
||||
// Test that computing the layout of an empty union doesn't ICE.
|
||||
#[rustc_layout(debug)]
|
||||
union EmptyUnion {} //~ ERROR: has an unknown layout
|
||||
//~^ ERROR: unions cannot have zero fields
|
||||
|
@ -1,3 +1,9 @@
|
||||
error: unions cannot have zero fields
|
||||
--> $DIR/debug.rs:82:1
|
||||
|
|
||||
LL | union EmptyUnion {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: layout_of(E) = Layout {
|
||||
size: Size(12 bytes),
|
||||
align: AbiAndPrefAlign {
|
||||
@ -566,12 +572,18 @@ LL | type Impossible = (str, str);
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: only the last element of a tuple may have a dynamically sized type
|
||||
|
||||
error: the type `EmptyUnion` has an unknown layout
|
||||
--> $DIR/debug.rs:82:1
|
||||
|
|
||||
LL | union EmptyUnion {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
|
||||
--> $DIR/debug.rs:74:5
|
||||
|
|
||||
LL | const C: () = ();
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
14
tests/ui/layout/invalid-unsized-const-eval.rs
Normal file
14
tests/ui/layout/invalid-unsized-const-eval.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// issue: #124182
|
||||
|
||||
//! This test used to trip an assertion in const eval, because `layout_of(LazyLock)`
|
||||
//! returned `Ok` with an unsized layout when a sized layout was expected.
|
||||
//! It was fixed by making `layout_of` always return `Err` for types that
|
||||
//! contain unsized fields in unexpected locations.
|
||||
|
||||
struct LazyLock {
|
||||
data: (dyn Sync, ()), //~ ERROR the size for values of type
|
||||
}
|
||||
|
||||
static EMPTY_SET: LazyLock = todo!();
|
||||
|
||||
fn main() {}
|
12
tests/ui/layout/invalid-unsized-const-eval.stderr
Normal file
12
tests/ui/layout/invalid-unsized-const-eval.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time
|
||||
--> $DIR/invalid-unsized-const-eval.rs:9:11
|
||||
|
|
||||
LL | data: (dyn Sync, ()),
|
||||
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn Sync + 'static)`
|
||||
= note: only the last element of a tuple may have a dynamically sized type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
51
tests/ui/layout/trivial-bounds-sized.rs
Normal file
51
tests/ui/layout/trivial-bounds-sized.rs
Normal file
@ -0,0 +1,51 @@
|
||||
//@ check-pass
|
||||
|
||||
//! With trivial bounds, it is possible to have ADTs with unsized fields
|
||||
//! in arbitrary places. Test that we do not ICE for such types.
|
||||
|
||||
#![feature(trivial_bounds)]
|
||||
#![expect(trivial_bounds)]
|
||||
|
||||
struct Struct
|
||||
where
|
||||
[u8]: Sized,
|
||||
[i16]: Sized,
|
||||
{
|
||||
a: [u8],
|
||||
b: [i16],
|
||||
c: f32,
|
||||
}
|
||||
|
||||
union Union
|
||||
where
|
||||
[u8]: Copy,
|
||||
[i16]: Copy,
|
||||
{
|
||||
a: [u8],
|
||||
b: [i16],
|
||||
c: f32,
|
||||
}
|
||||
|
||||
enum Enum
|
||||
where
|
||||
[u8]: Sized,
|
||||
[i16]: Sized,
|
||||
{
|
||||
V1([u8], [i16]),
|
||||
V2([i16], f32),
|
||||
}
|
||||
|
||||
// This forces layout computation via the `variant_size_differences` lint.
|
||||
// FIXME: This could be made more robust, possibly with a variant of `rustc_layout`
|
||||
// that doesn't error.
|
||||
enum Check
|
||||
where
|
||||
[u8]: Copy,
|
||||
[i16]: Copy,
|
||||
{
|
||||
Struct(Struct),
|
||||
Union(Union),
|
||||
Enum(Enum),
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,4 +1,9 @@
|
||||
//@ known-bug: #123134
|
||||
//@ check-pass
|
||||
// issue: #123134
|
||||
|
||||
//! This is a variant of `trivial-bounds-sized.rs` that compiles without any
|
||||
//! feature gates and used to trigger a delayed bug.
|
||||
|
||||
trait Api: Sized {
|
||||
type Device: ?Sized;
|
||||
}
|
||||
@ -7,7 +12,7 @@ struct OpenDevice<A: Api>
|
||||
where
|
||||
A::Device: Sized,
|
||||
{
|
||||
device: A::Device,
|
||||
device: A::Device, // <- this is the type that ends up being unsized.
|
||||
queue: (),
|
||||
}
|
||||
|
||||
@ -31,6 +36,8 @@ impl<T> Adapter for T {
|
||||
fn open() -> OpenDevice<Self::A>
|
||||
where
|
||||
<Self::A as Api>::Device: Sized,
|
||||
// ^ the bound expands to `<<T as Adapter>::A as Api>::Device: Sized`, which
|
||||
// is not considered trivial due to containing the type parameter `T`
|
||||
{
|
||||
unreachable!()
|
||||
}
|
Loading…
Reference in New Issue
Block a user