Skip to content

Commit e2dc1a1

Browse files
committed
Auto merge of #129970 - lukas-code:LayoutCalculator, r=compiler-errors
layout computation: gracefully handle unsized types in unexpected locations This PR reworks the layout computation to eagerly return an error when encountering an unsized field where a sized field was expected, rather than delaying a bug and attempting to recover a layout. This is required, because with trivially false where clauses like `[T]: Sized`, any field can possible be an unsized type, without causing a compile error. Since this PR removes the `delayed_bug` method from the `LayoutCalculator` trait, it essentially becomes the same as the `HasDataLayout` trait, so I've also refactored the `LayoutCalculator` to be a simple wrapper struct around a type that implements `HasDataLayout`. The majority of the diff is whitespace changes, so viewing with whitespace ignored is advised. implements #123169 (comment) r? `@compiler-errors` or compiler fixes #123134 fixes #124182 fixes #126939 fixes #127737
2 parents bde6bf2 + 20d2414 commit e2dc1a1

29 files changed

+1341
-1227
lines changed

compiler/rustc_abi/src/layout.rs

+952-920
Large diffs are not rendered by default.

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 {

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
}

compiler/rustc_const_eval/src/interpret/validity.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_middle::mir::interpret::{
2121
UnsupportedOpInfo, ValidationErrorInfo,
2222
};
2323
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
24-
use rustc_middle::ty::{self, Ty, TyCtxt};
24+
use rustc_middle::ty::{self, Ty};
2525
use rustc_span::symbol::{sym, Symbol};
2626
use rustc_target::abi::{
2727
Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
@@ -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);
@@ -949,7 +949,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
949949

950950
/// Helper for recursive traversal: add data ranges of the given type to `out`.
951951
fn union_data_range_uncached<'tcx>(
952-
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
952+
cx: &LayoutCx<'tcx>,
953953
layout: TyAndLayout<'tcx>,
954954
base_offset: Size,
955955
out: &mut RangeSet,

compiler/rustc_const_eval/src/util/check_validity_requirement.rs

+7-5
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 {
@@ -42,12 +44,12 @@ pub fn check_validity_requirement<'tcx>(
4244
/// for details.
4345
fn check_validity_requirement_strict<'tcx>(
4446
ty: TyAndLayout<'tcx>,
45-
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
47+
cx: &LayoutCx<'tcx>,
4648
kind: ValidityRequirement,
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))
@@ -80,7 +82,7 @@ fn check_validity_requirement_strict<'tcx>(
8082
/// function for details.
8183
fn check_validity_requirement_lax<'tcx>(
8284
this: TyAndLayout<'tcx>,
83-
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
85+
cx: &LayoutCx<'tcx>,
8486
init_kind: ValidityRequirement,
8587
) -> Result<bool, &'tcx LayoutError<'tcx>> {
8688
let scalar_allows_raw_init = move |s: Scalar| -> bool {

compiler/rustc_index/src/slice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct IndexSlice<I: Idx, T> {
2020

2121
impl<I: Idx, T> IndexSlice<I, T> {
2222
#[inline]
23-
pub const fn empty() -> &'static Self {
23+
pub const fn empty<'a>() -> &'a Self {
2424
Self::from_raw(&[])
2525
}
2626

compiler/rustc_middle/src/ty/layout.rs

+17-43
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};
@@ -286,20 +285,14 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
286285
}
287286

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

294-
impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'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

@@ -568,33 +561,33 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
568561
}
569562
}
570563

571-
impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
564+
impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> {
572565
fn param_env(&self) -> ty::ParamEnv<'tcx> {
573566
self.param_env
574567
}
575568
}
576569

577-
impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
570+
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

583-
impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
576+
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

589-
impl<'tcx, T: HasWasmCAbiOpt> HasWasmCAbiOpt for LayoutCx<'tcx, T> {
582+
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

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

@@ -685,7 +678,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
685678

686679
impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
687680

688-
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
681+
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
689682
type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
690683

691684
#[inline]
@@ -695,26 +688,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
695688
_: Span,
696689
_: Ty<'tcx>,
697690
) -> &'tcx LayoutError<'tcx> {
698-
self.tcx.arena.alloc(err)
699-
}
700-
}
701-
702-
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
703-
type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
704-
705-
#[inline]
706-
fn layout_tcx_at_span(&self) -> Span {
707-
self.tcx.span
708-
}
709-
710-
#[inline]
711-
fn handle_layout_err(
712-
&self,
713-
err: LayoutError<'tcx>,
714-
_: Span,
715-
_: Ty<'tcx>,
716-
) -> &'tcx LayoutError<'tcx> {
717-
self.tcx.arena.alloc(err)
691+
self.tcx().arena.alloc(err)
718692
}
719693
}
720694

@@ -1342,7 +1316,7 @@ impl<'tcx> TyCtxt<'tcx> {
13421316
where
13431317
I: Iterator<Item = (VariantIdx, FieldIdx)>,
13441318
{
1345-
let cx = LayoutCx { tcx: self, param_env };
1319+
let cx = LayoutCx::new(self, param_env);
13461320
let mut offset = Size::ZERO;
13471321

13481322
for (variant, field) in indices {

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
}

compiler/rustc_transmute/src/layout/mod.rs

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

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

7070
/// A reference in the layout.
@@ -124,11 +124,11 @@ pub mod rustc {
124124
}
125125

126126
pub(crate) fn layout_of<'tcx>(
127-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
127+
cx: LayoutCx<'tcx>,
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
}

compiler/rustc_transmute/src/layout/tree.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,15 @@ pub(crate) mod rustc {
204204
}
205205

206206
impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
207-
pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, Err> {
207+
pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
208208
use rustc_target::abi::HasDataLayout;
209209
let layout = layout_of(cx, ty)?;
210210

211211
if let Err(e) = ty.error_reported() {
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() {
@@ -274,7 +274,7 @@ pub(crate) mod rustc {
274274
fn from_tuple(
275275
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
276276
members: &'tcx List<Ty<'tcx>>,
277-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
277+
cx: LayoutCx<'tcx>,
278278
) -> Result<Self, Err> {
279279
match &layout.fields {
280280
FieldsShape::Primitive => {
@@ -299,7 +299,7 @@ pub(crate) mod rustc {
299299
fn from_struct(
300300
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
301301
def: AdtDef<'tcx>,
302-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
302+
cx: LayoutCx<'tcx>,
303303
) -> Result<Self, Err> {
304304
assert!(def.is_struct());
305305
let def = Def::Adt(def);
@@ -314,13 +314,13 @@ pub(crate) mod rustc {
314314
fn from_enum(
315315
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
316316
def: AdtDef<'tcx>,
317-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
317+
cx: LayoutCx<'tcx>,
318318
) -> Result<Self, Err> {
319319
assert!(def.is_enum());
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(
@@ -389,7 +389,7 @@ pub(crate) mod rustc {
389389
tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>,
390390
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
391391
total_size: Size,
392-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
392+
cx: LayoutCx<'tcx>,
393393
) -> Result<Self, Err> {
394394
// This constructor does not support non-`FieldsShape::Arbitrary`
395395
// layouts.
@@ -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.
@@ -470,7 +470,7 @@ pub(crate) mod rustc {
470470
fn from_union(
471471
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
472472
def: AdtDef<'tcx>,
473-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
473+
cx: LayoutCx<'tcx>,
474474
) -> Result<Self, Err> {
475475
assert!(def.is_union());
476476

@@ -500,7 +500,7 @@ pub(crate) mod rustc {
500500
}
501501

502502
fn ty_field<'tcx>(
503-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
503+
cx: LayoutCx<'tcx>,
504504
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
505505
i: FieldIdx,
506506
) -> Ty<'tcx> {
@@ -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
}
@@ -527,11 +527,11 @@ pub(crate) mod rustc {
527527
}
528528

529529
fn ty_variant<'tcx>(
530-
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
530+
cx: LayoutCx<'tcx>,
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
}

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.

0 commit comments

Comments
 (0)