diff options
| author | bors <bors@rust-lang.org> | 2024-06-25 07:21:17 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-06-25 07:21:17 +0000 |
| commit | bda221a0eb5019a939e34e0f4583f1c4b6e5b862 (patch) | |
| tree | c13a3c138206e7a48137622356f26346d52fabbd /compiler | |
| parent | 164e1297e1bce47a241e4d93a9f044452b288715 (diff) | |
| parent | 9f0c7f00d1d705435fef309576e0522cb0c25497 (diff) | |
| download | rust-bda221a0eb5019a939e34e0f4583f1c4b6e5b862.tar.gz rust-bda221a0eb5019a939e34e0f4583f1c4b6e5b862.zip | |
Auto merge of #125740 - RalfJung:transmute-size-check, r=oli-obk
transmute size check: properly account for alignment Fixes another place where ZST alignment was ignored when checking whether something is a newtype. I wonder how many more of these there are... Fixes https://github.com/rust-lang/rust/issues/101084
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_hir_typeck/src/intrinsicck.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/layout.rs | 25 |
2 files changed, 19 insertions, 10 deletions
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index fb8863c143f..5eafc60a04e 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Special-case transmuting from `typeof(function)` and // `Option<typeof(function)>` to present a clearer error. let from = unpack_option_like(tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to, _)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) { struct_span_code_err!(tcx.dcx(), span, E0591, "can't transmute zero-sized type") @@ -88,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Try to display a sensible error with as much information as possible. let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk { Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), - Ok(SizeSkeleton::Known(size)) => { + Ok(SizeSkeleton::Known(size, _)) => { if let Some(v) = u128::from(size.bytes()).checked_mul(8) { format!("{v} bits") } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f608b02f42c..eb25aecd9ce 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -309,7 +309,8 @@ impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { #[derive(Copy, Clone, Debug)] pub enum SizeSkeleton<'tcx> { /// Any statically computable Layout. - Known(Size), + /// Alignment can be `None` if unknown. + Known(Size, Option<Align>), /// This is a generic const expression (i.e. N * 2), which may contain some parameters. /// It must be of type usize, and represents the size of a type in bytes. @@ -339,7 +340,12 @@ impl<'tcx> SizeSkeleton<'tcx> { // First try computing a static layout. let err = match tcx.layout_of(param_env.and(ty)) { Ok(layout) => { - return Ok(SizeSkeleton::Known(layout.size)); + if layout.abi.is_sized() { + return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi))); + } else { + // Just to be safe, don't claim a known layout for unsized types. + return Err(tcx.arena.alloc(LayoutError::Unknown(ty))); + } } Err(err @ LayoutError::Unknown(_)) => err, // We can't extract SizeSkeleton info from other layout errors @@ -389,19 +395,20 @@ impl<'tcx> SizeSkeleton<'tcx> { ty::Array(inner, len) if tcx.features().transmute_generic_consts => { let len_eval = len.try_eval_target_usize(tcx, param_env); if len_eval == Some(0) { - return Ok(SizeSkeleton::Known(Size::from_bytes(0))); + return Ok(SizeSkeleton::Known(Size::from_bytes(0), None)); } match SizeSkeleton::compute(inner, tcx, param_env)? { // This may succeed because the multiplication of two types may overflow // but a single size of a nested array will not. - SizeSkeleton::Known(s) => { + SizeSkeleton::Known(s, a) => { if let Some(c) = len_eval { let size = s .bytes() .checked_mul(c) .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?; - return Ok(SizeSkeleton::Known(Size::from_bytes(size))); + // Alignment is unchanged by arrays. + return Ok(SizeSkeleton::Known(Size::from_bytes(size), a)); } Err(tcx.arena.alloc(LayoutError::Unknown(ty))) } @@ -427,8 +434,10 @@ impl<'tcx> SizeSkeleton<'tcx> { for field in fields { let field = field?; match field { - SizeSkeleton::Known(size) => { - if size.bytes() > 0 { + SizeSkeleton::Known(size, align) => { + let is_1zst = size.bytes() == 0 + && align.is_some_and(|align| align.bytes() == 1); + if !is_1zst { return Err(err); } } @@ -492,7 +501,7 @@ impl<'tcx> SizeSkeleton<'tcx> { pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool { match (self, other) { - (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b, + (SizeSkeleton::Known(a, _), SizeSkeleton::Known(b, _)) => a == b, (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => { a == b } |
