Skip to content

Commit 6974501

Browse files
author
Lukas Markeffsky
committed
layout computation: eagerly error for unexpected unsized fields
1 parent 16be666 commit 6974501

File tree

25 files changed

+1224
-1093
lines changed

25 files changed

+1224
-1093
lines changed

Diff for: compiler/rustc_abi/src/layout.rs

+939-918
Large diffs are not rendered by default.

Diff for: compiler/rustc_abi/src/lib.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ mod layout;
2626
#[cfg(test)]
2727
mod tests;
2828

29-
pub use layout::LayoutCalculator;
29+
pub use layout::{LayoutCalculator, LayoutCalculatorError};
3030

3131
/// Requirements for a `StableHashingContext` to be used in this crate.
3232
/// This is a hack to allow using the `HashStable_Generic` derive macro
@@ -393,6 +393,14 @@ impl HasDataLayout for TargetDataLayout {
393393
}
394394
}
395395

396+
// used by rust-analyzer
397+
impl HasDataLayout for &TargetDataLayout {
398+
#[inline]
399+
fn data_layout(&self) -> &TargetDataLayout {
400+
(**self).data_layout()
401+
}
402+
}
403+
396404
/// Endianness of the target, which must match cfg(target-endian).
397405
#[derive(Copy, Clone, PartialEq, Eq)]
398406
pub enum Endian {

Diff for: compiler/rustc_const_eval/src/const_eval/valtrees.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ pub fn valtree_to_const_value<'tcx>(
319319
let branches = valtree.unwrap_branch();
320320
// Find the non-ZST field. (There can be aligned ZST!)
321321
for (i, &inner_valtree) in branches.iter().enumerate() {
322-
let field = layout.field(&LayoutCx { tcx, param_env }, i);
322+
let field = layout.field(&LayoutCx::new(tcx, param_env), i);
323323
if !field.is_zst() {
324324
return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
325325
}

Diff for: compiler/rustc_const_eval/src/interpret/validity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
940940
) -> Cow<'e, RangeSet> {
941941
assert!(layout.ty.is_union());
942942
assert!(layout.abi.is_sized(), "there are no unsized unions");
943-
let layout_cx = LayoutCx { tcx: *ecx.tcx, param_env: ecx.param_env };
943+
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
944944
return M::cached_union_data_range(ecx, layout.ty, || {
945945
let mut out = RangeSet(Vec::new());
946946
union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out);

Diff for: compiler/rustc_const_eval/src/util/check_validity_requirement.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use rustc_middle::bug;
2-
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
2+
use rustc_middle::ty::layout::{
3+
HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement,
4+
};
35
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
46
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
57

@@ -30,7 +32,7 @@ pub fn check_validity_requirement<'tcx>(
3032
return Ok(!layout.abi.is_uninhabited());
3133
}
3234

33-
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
35+
let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
3436
if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
3537
check_validity_requirement_strict(layout, &layout_cx, kind)
3638
} else {
@@ -47,7 +49,7 @@ fn check_validity_requirement_strict<'tcx>(
4749
) -> Result<bool, &'tcx LayoutError<'tcx>> {
4850
let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
4951

50-
let mut cx = InterpCx::new(cx.tcx, rustc_span::DUMMY_SP, cx.param_env, machine);
52+
let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine);
5153

5254
let allocated = cx
5355
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))

Diff for: compiler/rustc_middle/src/ty/layout.rs

+10-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::borrow::Cow;
21
use std::num::NonZero;
32
use std::ops::Bound;
43
use std::{cmp, fmt};
@@ -287,19 +286,13 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
287286

288287
#[derive(Clone, Copy)]
289288
pub struct LayoutCx<'tcx> {
290-
pub tcx: TyCtxt<'tcx>,
289+
pub calc: LayoutCalculator<TyCtxt<'tcx>>,
291290
pub param_env: ty::ParamEnv<'tcx>,
292291
}
293292

294-
impl<'tcx> LayoutCalculator for LayoutCx<'tcx> {
295-
type TargetDataLayoutRef = &'tcx TargetDataLayout;
296-
297-
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
298-
self.tcx.dcx().delayed_bug(txt);
299-
}
300-
301-
fn current_data_layout(&self) -> Self::TargetDataLayoutRef {
302-
&self.tcx.data_layout
293+
impl<'tcx> LayoutCx<'tcx> {
294+
pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
295+
Self { calc: LayoutCalculator::new(tcx), param_env }
303296
}
304297
}
305298

@@ -576,25 +569,25 @@ impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> {
576569

577570
impl<'tcx> HasDataLayout for LayoutCx<'tcx> {
578571
fn data_layout(&self) -> &TargetDataLayout {
579-
self.tcx.data_layout()
572+
self.calc.cx.data_layout()
580573
}
581574
}
582575

583576
impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
584577
fn target_spec(&self) -> &Target {
585-
self.tcx.target_spec()
578+
self.calc.cx.target_spec()
586579
}
587580
}
588581

589582
impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
590583
fn wasm_c_abi_opt(&self) -> WasmCAbi {
591-
self.tcx.wasm_c_abi_opt()
584+
self.calc.cx.wasm_c_abi_opt()
592585
}
593586
}
594587

595588
impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
596589
fn tcx(&self) -> TyCtxt<'tcx> {
597-
self.tcx.tcx()
590+
self.calc.cx
598591
}
599592
}
600593

@@ -695,7 +688,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
695688
_: Span,
696689
_: Ty<'tcx>,
697690
) -> &'tcx LayoutError<'tcx> {
698-
self.tcx.arena.alloc(err)
691+
self.tcx().arena.alloc(err)
699692
}
700693
}
701694

@@ -1323,7 +1316,7 @@ impl<'tcx> TyCtxt<'tcx> {
13231316
where
13241317
I: Iterator<Item = (VariantIdx, FieldIdx)>,
13251318
{
1326-
let cx = LayoutCx { tcx: self, param_env };
1319+
let cx = LayoutCx::new(self, param_env);
13271320
let mut offset = Size::ZERO;
13281321

13291322
for (variant, field) in indices {

Diff for: compiler/rustc_passes/src/layout_test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
128128
}
129129

130130
Err(layout_error) => {
131-
tcx.dcx().emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
131+
tcx.dcx().emit_err(Spanned { node: layout_error.into_diagnostic(), span });
132132
}
133133
}
134134
}

Diff for: compiler/rustc_transmute/src/layout/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub mod rustc {
6363
use std::fmt::{self, Write};
6464

6565
use rustc_middle::mir::Mutability;
66-
use rustc_middle::ty::layout::{LayoutCx, LayoutError};
66+
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
6767
use rustc_middle::ty::{self, Ty};
6868
use rustc_target::abi::Layout;
6969

@@ -128,7 +128,7 @@ pub mod rustc {
128128
ty: Ty<'tcx>,
129129
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
130130
use rustc_middle::ty::layout::LayoutOf;
131-
let ty = cx.tcx.erase_regions(ty);
131+
let ty = cx.tcx().erase_regions(ty);
132132
cx.layout_of(ty).map(|tl| tl.layout)
133133
}
134134
}

Diff for: compiler/rustc_transmute/src/layout/tree.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ pub(crate) mod rustc {
212212
return Err(Err::TypeError(e));
213213
}
214214

215-
let target = cx.tcx.data_layout();
215+
let target = cx.data_layout();
216216
let pointer_size = target.pointer_size;
217217

218218
match ty.kind() {
@@ -320,7 +320,7 @@ pub(crate) mod rustc {
320320

321321
// Computes the variant of a given index.
322322
let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| {
323-
let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index));
323+
let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
324324
let variant_def = Def::Variant(def.variant(index));
325325
let variant_layout = ty_variant(cx, (ty, layout), index);
326326
Self::from_variant(
@@ -417,7 +417,7 @@ pub(crate) mod rustc {
417417
}
418418
}
419419
}
420-
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx));
420+
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx()));
421421
}
422422

423423
// Append the fields, in memory order, to the layout.
@@ -509,12 +509,12 @@ pub(crate) mod rustc {
509509
match layout.variants {
510510
Variants::Single { index } => {
511511
let field = &def.variant(index).fields[i];
512-
field.ty(cx.tcx, args)
512+
field.ty(cx.tcx(), args)
513513
}
514514
// Discriminant field for enums (where applicable).
515515
Variants::Multiple { tag, .. } => {
516516
assert_eq!(i.as_usize(), 0);
517-
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx)
517+
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx())
518518
}
519519
}
520520
}
@@ -531,7 +531,7 @@ pub(crate) mod rustc {
531531
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
532532
i: VariantIdx,
533533
) -> Layout<'tcx> {
534-
let ty = cx.tcx.erase_regions(ty);
534+
let ty = cx.tcx().erase_regions(ty);
535535
TyAndLayout { ty, layout }.for_variant(&cx, i).layout
536536
}
537537
}

Diff for: compiler/rustc_transmute/src/maybe_transmutable/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mod rustc {
4343
pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
4444
let Self { src, dst, assume, context } = self;
4545

46-
let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() };
46+
let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all());
4747

4848
// Convert `src` and `dst` from their rustc representations, to `Tree`-based
4949
// representations.

Diff for: compiler/rustc_ty_utils/src/abi.rs

+26-22
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ fn fn_abi_of_fn_ptr<'tcx>(
331331
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
332332
let (param_env, (sig, extra_args)) = query.into_parts();
333333

334-
let cx = LayoutCx { tcx, param_env };
334+
let cx = LayoutCx::new(tcx, param_env);
335335
fn_abi_new_uncached(&cx, sig, extra_args, None, None, false)
336336
}
337337

@@ -347,7 +347,7 @@ fn fn_abi_of_instance<'tcx>(
347347
instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty());
348348

349349
fn_abi_new_uncached(
350-
&LayoutCx { tcx, param_env },
350+
&LayoutCx::new(tcx, param_env),
351351
sig,
352352
extra_args,
353353
caller_location,
@@ -386,12 +386,14 @@ fn adjust_for_rust_scalar<'tcx>(
386386
attrs.set(ArgAttribute::NonNull);
387387
}
388388

389+
let tcx = cx.tcx();
390+
389391
if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
390392
let kind = if let Some(kind) = pointee.safe {
391393
Some(kind)
392394
} else if let Some(pointee) = drop_target_pointee {
393395
// The argument to `drop_in_place` is semantically equivalent to a mutable reference.
394-
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) })
396+
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.param_env()) })
395397
} else {
396398
None
397399
};
@@ -415,12 +417,12 @@ fn adjust_for_rust_scalar<'tcx>(
415417
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
416418
// `noalias` for it. This can be turned off using an unstable flag.
417419
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
418-
let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias;
420+
let noalias_for_box = tcx.sess.opts.unstable_opts.box_noalias;
419421

420422
// LLVM prior to version 12 had known miscompiles in the presence of noalias attributes
421423
// (see #54878), so it was conditionally disabled, but we don't support earlier
422424
// versions at all anymore. We still support turning it off using -Zmutable-noalias.
423-
let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
425+
let noalias_mut_ref = tcx.sess.opts.unstable_opts.mutable_noalias;
424426

425427
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
426428
// `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
@@ -458,6 +460,7 @@ fn fn_abi_sanity_check<'tcx>(
458460
spec_abi: SpecAbi,
459461
arg: &ArgAbi<'tcx, Ty<'tcx>>,
460462
) {
463+
let tcx = cx.tcx();
461464
match &arg.mode {
462465
PassMode::Ignore => {}
463466
PassMode::Direct(_) => {
@@ -484,7 +487,7 @@ fn fn_abi_sanity_check<'tcx>(
484487
// It needs to switch to something else before stabilization can happen.
485488
// (See issue: https://github.com/rust-lang/rust/issues/117271)
486489
assert!(
487-
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64")
490+
matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64")
488491
|| matches!(spec_abi, SpecAbi::PtxKernel | SpecAbi::Unadjusted),
489492
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\
490493
Problematic type: {:#?}",
@@ -516,7 +519,7 @@ fn fn_abi_sanity_check<'tcx>(
516519
// With metadata. Must be unsized and not on the stack.
517520
assert!(arg.layout.is_unsized() && !on_stack);
518521
// Also, must not be `extern` type.
519-
let tail = cx.tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
522+
let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
520523
if matches!(tail.kind(), ty::Foreign(..)) {
521524
// These types do not have metadata, so having `meta_attrs` is bogus.
522525
// Conceptually, unsized arguments must be copied around, which requires dynamically
@@ -546,7 +549,8 @@ fn fn_abi_new_uncached<'tcx>(
546549
// FIXME(eddyb) replace this with something typed, like an `enum`.
547550
force_thin_self_ptr: bool,
548551
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
549-
let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
552+
let tcx = cx.tcx();
553+
let sig = tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
550554

551555
let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
552556

@@ -576,7 +580,7 @@ fn fn_abi_new_uncached<'tcx>(
576580
};
577581

578582
let is_drop_in_place =
579-
fn_def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::DropInPlace));
583+
fn_def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::DropInPlace));
580584

581585
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, &'tcx FnAbiError<'tcx>> {
582586
let span = tracing::debug_span!("arg_of");
@@ -588,8 +592,7 @@ fn fn_abi_new_uncached<'tcx>(
588592
_ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
589593
});
590594

591-
let layout =
592-
cx.layout_of(ty).map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::Layout(*err)))?;
595+
let layout = cx.layout_of(ty).map_err(|err| &*tcx.arena.alloc(FnAbiError::Layout(*err)))?;
593596
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
594597
// Don't pass the vtable, it's not an argument of the virtual fn.
595598
// 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>(
638641
fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?;
639642
debug!("fn_abi_new_uncached = {:?}", fn_abi);
640643
fn_abi_sanity_check(cx, &fn_abi, sig.abi);
641-
Ok(cx.tcx.arena.alloc(fn_abi))
644+
Ok(tcx.arena.alloc(fn_abi))
642645
}
643646

644647
#[tracing::instrument(level = "trace", skip(cx))]
@@ -670,17 +673,18 @@ fn fn_abi_adjust_for_abi<'tcx>(
670673
return Ok(());
671674
}
672675

676+
let tcx = cx.tcx();
677+
673678
if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic {
674679
// Look up the deduced parameter attributes for this function, if we have its def ID and
675680
// we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
676681
// as appropriate.
677-
let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No
678-
&& cx.tcx.sess.opts.incremental.is_none()
679-
{
680-
fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
681-
} else {
682-
&[]
683-
};
682+
let deduced_param_attrs =
683+
if tcx.sess.opts.optimize != OptLevel::No && tcx.sess.opts.incremental.is_none() {
684+
fn_def_id.map(|fn_def_id| tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
685+
} else {
686+
&[]
687+
};
684688

685689
let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
686690
if arg.is_ignore() {
@@ -689,7 +693,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
689693

690694
// Avoid returning floats in x87 registers on x86 as loading and storing from x87
691695
// registers will quiet signalling NaNs.
692-
if cx.tcx.sess.target.arch == "x86"
696+
if tcx.sess.target.arch == "x86"
693697
&& arg_idx.is_none()
694698
// Intrinsics themselves are not actual "real" functions, so theres no need to
695699
// change their ABIs.
@@ -744,7 +748,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
744748
// that's how we connect up to LLVM and it's unstable
745749
// anyway, we control all calls to it in libstd.
746750
Abi::Vector { .. }
747-
if abi != SpecAbi::RustIntrinsic && cx.tcx.sess.target.simd_types_indirect =>
751+
if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect =>
748752
{
749753
arg.make_indirect();
750754
return;
@@ -793,7 +797,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
793797
} else {
794798
fn_abi
795799
.adjust_for_foreign_abi(cx, abi)
796-
.map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
800+
.map_err(|err| &*tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
797801
}
798802

799803
Ok(())

0 commit comments

Comments
 (0)