Skip to content

Commit 254d910

Browse files
committed
Auto merge of rust-lang#116542 - the8472:slice-ref-len-validity, r=<try>
Add range metadata to slice lengths This adds range information to the slice-len in fat pointers if we can conservatively determine that the pointee is not a ZST without having to normalize the pointee type. I only intended to pass the `!range` to llvm but apparently this also lets the length in fat pointers be used for its niches 😅. Ideally this would use the naive-layout computation from rust-lang#113166 to calculate a better approximation of the pointee size, but that PR got reverted.
2 parents 78a7751 + c0e2e89 commit 254d910

File tree

16 files changed

+308
-65
lines changed

16 files changed

+308
-65
lines changed

compiler/rustc_hir/src/hir.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -3855,14 +3855,26 @@ impl<'hir> Node<'hir> {
38553855
mod size_asserts {
38563856
use super::*;
38573857
use rustc_data_structures::static_assert_size;
3858-
// tidy-alphabetical-start
38593858
static_assert_size!(Block<'_>, 48);
38603859
static_assert_size!(Body<'_>, 24);
3860+
#[cfg(bootstrap)]
38613861
static_assert_size!(Expr<'_>, 64);
3862+
#[cfg(not(bootstrap))]
3863+
static_assert_size!(Expr<'_>, 56);
3864+
#[cfg(bootstrap)]
38623865
static_assert_size!(ExprKind<'_>, 48);
3866+
#[cfg(not(bootstrap))]
3867+
static_assert_size!(ExprKind<'_>, 40);
38633868
static_assert_size!(FnDecl<'_>, 40);
3869+
#[cfg(bootstrap)]
38643870
static_assert_size!(ForeignItem<'_>, 72);
3871+
#[cfg(not(bootstrap))]
3872+
static_assert_size!(ForeignItem<'_>, 64);
3873+
#[cfg(bootstrap)]
38653874
static_assert_size!(ForeignItemKind<'_>, 40);
3875+
#[cfg(not(bootstrap))]
3876+
static_assert_size!(ForeignItemKind<'_>, 32);
3877+
// tidy-alphabetical-start
38663878
static_assert_size!(GenericArg<'_>, 24);
38673879
static_assert_size!(GenericBound<'_>, 48);
38683880
static_assert_size!(Generics<'_>, 56);

compiler/rustc_hir_typeck/src/intrinsicck.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_hir as hir;
44
use rustc_index::Idx;
55
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
66
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
7-
use rustc_target::abi::{Pointer, VariantIdx};
7+
use rustc_target::abi::{Pointer, Size, VariantIdx};
88

99
use super::FnCtxt;
1010

@@ -84,19 +84,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8484
}
8585
}
8686

87+
fn size_to_bits(size: Size) -> u128 {
88+
let Some(bits) = u128::from(size.bytes()).checked_mul(8) else {
89+
// `u128` should definitely be able to hold the size of different architectures
90+
// larger sizes should be reported as error `are too big for the current architecture`
91+
// otherwise we have a bug somewhere
92+
bug!("{:?} overflow for u128", size)
93+
};
94+
95+
bits
96+
}
97+
8798
// Try to display a sensible error with as much information as possible.
8899
let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
89-
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
90-
Ok(SizeSkeleton::Known(size)) => {
91-
if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
92-
format!("{v} bits")
93-
} else {
94-
// `u128` should definitely be able to hold the size of different architectures
95-
// larger sizes should be reported as error `are too big for the current architecture`
96-
// otherwise we have a bug somewhere
97-
bug!("{:?} overflow for u128", size)
98-
}
100+
Ok(SizeSkeleton::Pointer { tail, known_size: Some(size), .. }) => {
101+
format!("{} bits, pointer to `{tail}`", size_to_bits(size))
99102
}
103+
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
104+
Ok(SizeSkeleton::Known(size)) => format!("{} bits", size_to_bits(size)),
100105
Ok(SizeSkeleton::Generic(size)) => {
101106
if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) {
102107
format!("{size} bytes")

compiler/rustc_middle/src/ty/layout.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
33
use crate::query::TyCtxtAt;
44
use crate::ty::normalize_erasing_regions::NormalizationError;
55
use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt};
6+
use hir::Mutability;
67
use rustc_error_messages::DiagMessage;
78
use rustc_errors::{
89
Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
@@ -319,6 +320,8 @@ pub enum SizeSkeleton<'tcx> {
319320
Pointer {
320321
/// If true, this pointer is never null.
321322
non_zero: bool,
323+
/// Available if the width of the pointer is known, i.e. whether it's 1 or 2 usizes
324+
known_size: Option<Size>,
322325
/// The type which determines the unsized metadata, if any,
323326
/// of this pointer. Either a type parameter or a projection
324327
/// depending on one, with regions erased.
@@ -372,7 +375,23 @@ impl<'tcx> SizeSkeleton<'tcx> {
372375
match tail.kind() {
373376
ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
374377
debug_assert!(tail.has_non_region_param());
375-
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
378+
Ok(SizeSkeleton::Pointer {
379+
non_zero,
380+
known_size: None,
381+
tail: tcx.erase_regions(tail),
382+
})
383+
}
384+
ty::Slice(_) => {
385+
debug_assert!(tail.has_non_region_param());
386+
// Assumption: all slice pointers have the same size. At most they differ in niches or or ptr/len ordering
387+
let simple_slice =
388+
Ty::new_ptr(tcx, Ty::new_slice(tcx, tcx.types.unit), Mutability::Not);
389+
let size = tcx.layout_of(param_env.and(simple_slice)).unwrap().size;
390+
Ok(SizeSkeleton::Pointer {
391+
non_zero,
392+
known_size: Some(size),
393+
tail: tcx.erase_regions(tail),
394+
})
376395
}
377396
ty::Error(guar) => {
378397
// Fixes ICE #124031
@@ -449,7 +468,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
449468
let v0 = zero_or_ptr_variant(0)?;
450469
// Newtype.
451470
if def.variants().len() == 1 {
452-
if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
471+
if let Some(SizeSkeleton::Pointer { non_zero, known_size, tail }) = v0 {
453472
return Ok(SizeSkeleton::Pointer {
454473
non_zero: non_zero
455474
|| match tcx.layout_scalar_valid_range(def.did()) {
@@ -459,6 +478,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
459478
}
460479
_ => false,
461480
},
481+
known_size,
462482
tail,
463483
});
464484
} else {
@@ -469,9 +489,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
469489
let v1 = zero_or_ptr_variant(1)?;
470490
// Nullable pointer enum optimization.
471491
match (v0, v1) {
472-
(Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
473-
| (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
474-
Ok(SizeSkeleton::Pointer { non_zero: false, tail })
492+
(Some(SizeSkeleton::Pointer { non_zero: true, known_size, tail }), None)
493+
| (None, Some(SizeSkeleton::Pointer { non_zero: true, known_size, tail })) => {
494+
Ok(SizeSkeleton::Pointer { non_zero: false, known_size, tail })
475495
}
476496
_ => Err(err),
477497
}
@@ -492,7 +512,10 @@ impl<'tcx> SizeSkeleton<'tcx> {
492512

493513
pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
494514
match (self, other) {
495-
(SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
515+
(
516+
SizeSkeleton::Known(a) | SizeSkeleton::Pointer { known_size: Some(a), .. },
517+
SizeSkeleton::Known(b) | SizeSkeleton::Pointer { known_size: Some(b), .. },
518+
) => a == b,
496519
(SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
497520
a == b
498521
}

0 commit comments

Comments
 (0)