From d366471e58b4387aa1d644c33c469e268abf7160 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Oct 2022 15:38:00 +0200 Subject: [PATCH] interpret: fix align_of_val on packed types --- .../src/interpret/eval_context.rs | 9 ++++++++- library/core/tests/lib.rs | 2 ++ library/core/tests/mem.rs | 20 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index d2e0a0dd240e8..51cfcdb833196 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -598,7 +598,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // the last field). Can't have foreign types here, how would we // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1); - let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else { + let Some((unsized_size, mut unsized_align)) = self.size_and_align_of(metadata, &field)? else { // A field with an extern type. We don't know the actual dynamic size // or the alignment. return Ok(None); @@ -614,6 +614,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Return the sum of sizes and max of aligns. let size = sized_size + unsized_size; // `Size` addition + // Packed types ignore the alignment of their fields. + if let ty::Adt(def, _) = layout.ty.kind() { + if def.repr().packed() { + unsized_align = sized_align; + } + } + // Choose max of two known alignments (combined value must // be aligned according to more restrictive of the two). let align = sized_align.max(unsized_align); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 51f858adee167..eda176d9fcbe6 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -5,6 +5,7 @@ #![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_assume)] +#![feature(const_align_of_val_raw)] #![feature(const_black_box)] #![feature(const_bool_to_option)] #![feature(const_caller_location)] @@ -42,6 +43,7 @@ #![feature(try_find)] #![feature(inline_const)] #![feature(is_sorted)] +#![feature(layout_for_ptr)] #![feature(pattern)] #![feature(pin_macro)] #![feature(sort_internals)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 0362e1c8afb5e..1cfb4fd9fd186 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -1,4 +1,5 @@ use core::mem::*; +use core::ptr; #[cfg(panic = "unwind")] use std::rc::Rc; @@ -75,6 +76,25 @@ fn align_of_val_basic() { assert_eq!(align_of_val(&1u32), 4); } +#[test] +#[cfg(not(bootstrap))] // stage 0 doesn't have the fix yet, so the test fails +fn align_of_val_raw_packed() { + #[repr(C, packed)] + struct B { + f: [u32], + } + let storage = [0u8; 4]; + let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1); + assert_eq!(unsafe { align_of_val_raw(b) }, 1); + + const ALIGN_OF_VAL_RAW: usize = { + let storage = [0u8; 4]; + let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1); + unsafe { align_of_val_raw(b) } + }; + assert_eq!(ALIGN_OF_VAL_RAW, 1); +} + #[test] fn test_swap() { let mut x = 31337;