Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interpret: fix align_of_val on packed types #103729

Merged
merged 1 commit into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down
20 changes: 20 additions & 0 deletions library/core/tests/mem.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::mem::*;
use core::ptr;

#[cfg(panic = "unwind")]
use std::rc::Rc;
Expand Down Expand Up @@ -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;
Expand Down