Skip to content

Commit 858f2a3

Browse files
committed
Auto merge of rust-lang#118932 - matthiaskrgr:rollup-fi7xzqa, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - rust-lang#118375 (Add -Zunpretty=stable-mir output test) - rust-lang#118538 (fix dynamic size/align computation logic for packed types with dyn trait tail) - rust-lang#118789 (fix --dry-run when the change-id warning is printed) r? `@ghost` `@rustbot` modify labels: rollup
2 parents d23e1a6 + 7b0b2d0 commit 858f2a3

File tree

10 files changed

+376
-64
lines changed

10 files changed

+376
-64
lines changed

compiler/rustc_codegen_ssa/src/size_of_val.rs

+39-23
Original file line numberDiff line numberDiff line change
@@ -84,37 +84,40 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
8484
debug!("DST {} layout: {:?}", t, layout);
8585

8686
let i = layout.fields.count() - 1;
87-
let sized_size = layout.fields.offset(i).bytes();
87+
let unsized_offset_unadjusted = layout.fields.offset(i).bytes();
8888
let sized_align = layout.align.abi.bytes();
89-
debug!("DST {} statically sized prefix size: {} align: {}", t, sized_size, sized_align);
90-
let sized_size = bx.const_usize(sized_size);
89+
debug!(
90+
"DST {} offset of dyn field: {}, statically sized align: {}",
91+
t, unsized_offset_unadjusted, sized_align
92+
);
93+
let unsized_offset_unadjusted = bx.const_usize(unsized_offset_unadjusted);
9194
let sized_align = bx.const_usize(sized_align);
9295

9396
// Recurse to get the size of the dynamically sized field (must be
9497
// the last field).
9598
let field_ty = layout.field(bx, i).ty;
9699
let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info);
97100

98-
// FIXME (#26403, #27023): We should be adding padding
99-
// to `sized_size` (to accommodate the `unsized_align`
100-
// required of the unsized field that follows) before
101-
// summing it with `sized_size`. (Note that since #26403
102-
// is unfixed, we do not yet add the necessary padding
103-
// here. But this is where the add would go.)
104-
105-
// Return the sum of sizes and max of aligns.
106-
let size = bx.add(sized_size, unsized_size);
107-
108-
// Packed types ignore the alignment of their fields.
109-
if let ty::Adt(def, _) = t.kind() {
110-
if def.repr().packed() {
111-
unsized_align = sized_align;
101+
// # First compute the dynamic alignment
102+
103+
// For packed types, we need to cap the alignment.
104+
if let ty::Adt(def, _) = t.kind()
105+
&& let Some(packed) = def.repr().pack
106+
{
107+
if packed.bytes() == 1 {
108+
// We know this will be capped to 1.
109+
unsized_align = bx.const_usize(1);
110+
} else {
111+
// We have to dynamically compute `min(unsized_align, packed)`.
112+
let packed = bx.const_usize(packed.bytes());
113+
let cmp = bx.icmp(IntPredicate::IntULT, unsized_align, packed);
114+
unsized_align = bx.select(cmp, unsized_align, packed);
112115
}
113116
}
114117

115118
// Choose max of two known alignments (combined value must
116119
// be aligned according to more restrictive of the two).
117-
let align = match (
120+
let full_align = match (
118121
bx.const_to_opt_u128(sized_align, false),
119122
bx.const_to_opt_u128(unsized_align, false),
120123
) {
@@ -129,6 +132,19 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
129132
}
130133
};
131134

135+
// # Then compute the dynamic size
136+
137+
// The full formula for the size would be:
138+
// let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
139+
// let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
140+
// However, `unsized_size` is a multiple of `unsized_align`.
141+
// Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`:
142+
// let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align);
143+
// Furthermore, `align >= unsized_align`, and therefore we only need to do:
144+
// let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align);
145+
146+
let full_size = bx.add(unsized_offset_unadjusted, unsized_size);
147+
132148
// Issue #27023: must add any necessary padding to `size`
133149
// (to make it a multiple of `align`) before returning it.
134150
//
@@ -140,12 +156,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
140156
//
141157
// `(size + (align-1)) & -align`
142158
let one = bx.const_usize(1);
143-
let addend = bx.sub(align, one);
144-
let add = bx.add(size, addend);
145-
let neg = bx.neg(align);
146-
let size = bx.and(add, neg);
159+
let addend = bx.sub(full_align, one);
160+
let add = bx.add(full_size, addend);
161+
let neg = bx.neg(full_align);
162+
let full_size = bx.and(add, neg);
147163

148-
(size, align)
164+
(full_size, full_align)
149165
}
150166
_ => bug!("size_and_align_of_dst: {t} not supported"),
151167
}

compiler/rustc_const_eval/src/interpret/eval_context.rs

+18-25
Original file line numberDiff line numberDiff line change
@@ -686,14 +686,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
686686
assert!(layout.fields.count() > 0);
687687
trace!("DST layout: {:?}", layout);
688688

689-
let sized_size = layout.fields.offset(layout.fields.count() - 1);
689+
let unsized_offset_unadjusted = layout.fields.offset(layout.fields.count() - 1);
690690
let sized_align = layout.align.abi;
691-
trace!(
692-
"DST {} statically sized prefix size: {:?} align: {:?}",
693-
layout.ty,
694-
sized_size,
695-
sized_align
696-
);
697691

698692
// Recurse to get the size of the dynamically sized field (must be
699693
// the last field). Can't have foreign types here, how would we
@@ -707,36 +701,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
707701
return Ok(None);
708702
};
709703

710-
// FIXME (#26403, #27023): We should be adding padding
711-
// to `sized_size` (to accommodate the `unsized_align`
712-
// required of the unsized field that follows) before
713-
// summing it with `sized_size`. (Note that since #26403
714-
// is unfixed, we do not yet add the necessary padding
715-
// here. But this is where the add would go.)
716-
717-
// Return the sum of sizes and max of aligns.
718-
let size = sized_size + unsized_size; // `Size` addition
704+
// # First compute the dynamic alignment
719705

720-
// Packed types ignore the alignment of their fields.
706+
// Packed type alignment needs to be capped.
721707
if let ty::Adt(def, _) = layout.ty.kind() {
722-
if def.repr().packed() {
723-
unsized_align = sized_align;
708+
if let Some(packed) = def.repr().pack {
709+
unsized_align = unsized_align.min(packed);
724710
}
725711
}
726712

727713
// Choose max of two known alignments (combined value must
728714
// be aligned according to more restrictive of the two).
729-
let align = sized_align.max(unsized_align);
715+
let full_align = sized_align.max(unsized_align);
716+
717+
// # Then compute the dynamic size
730718

731-
// Issue #27023: must add any necessary padding to `size`
732-
// (to make it a multiple of `align`) before returning it.
733-
let size = size.align_to(align);
719+
let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
720+
let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
721+
722+
// Just for our sanitiy's sake, assert that this is equal to what codegen would compute.
723+
assert_eq!(
724+
full_size,
725+
(unsized_offset_unadjusted + unsized_size).align_to(full_align)
726+
);
734727

735728
// Check if this brought us over the size limit.
736-
if size > self.max_size_of_val() {
729+
if full_size > self.max_size_of_val() {
737730
throw_ub!(InvalidMeta(InvalidMetaKind::TooBig));
738731
}
739-
Ok(Some((size, align)))
732+
Ok(Some((full_size, full_align)))
740733
}
741734
ty::Dynamic(_, _, ty::Dyn) => {
742735
let vtable = metadata.unwrap_meta().to_pointer(self)?;

compiler/stable_mir/src/mir/pretty.rs

+26-13
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,31 @@ pub fn pretty_statement(statement: &StatementKind) -> String {
5858
pretty.push_str(format!(" _{} = ", place.local).as_str());
5959
pretty.push_str(format!("{}", &pretty_rvalue(rval)).as_str());
6060
}
61-
StatementKind::FakeRead(_, _) => todo!(),
62-
StatementKind::SetDiscriminant { .. } => todo!(),
63-
StatementKind::Deinit(_) => todo!(),
64-
StatementKind::StorageLive(_) => todo!(),
65-
StatementKind::StorageDead(_) => todo!(),
66-
StatementKind::Retag(_, _) => todo!(),
67-
StatementKind::PlaceMention(_) => todo!(),
68-
StatementKind::AscribeUserType { .. } => todo!(),
69-
StatementKind::Coverage(_) => todo!(),
70-
StatementKind::Intrinsic(_) => todo!(),
71-
StatementKind::ConstEvalCounter => (),
72-
StatementKind::Nop => (),
61+
// FIXME: Add rest of the statements
62+
StatementKind::FakeRead(_, _) => return format!("StatementKind::FakeRead:Unimplemented"),
63+
StatementKind::SetDiscriminant { .. } => {
64+
return format!("StatementKind::SetDiscriminant:Unimplemented");
65+
}
66+
StatementKind::Deinit(_) => return format!("StatementKind::Deinit:Unimplemented"),
67+
StatementKind::StorageLive(_) => {
68+
return format!("StatementKind::StorageLive:Unimplemented");
69+
}
70+
StatementKind::StorageDead(_) => {
71+
return format!("StatementKind::StorageDead:Unimplemented");
72+
}
73+
StatementKind::Retag(_, _) => return format!("StatementKind::Retag:Unimplemented"),
74+
StatementKind::PlaceMention(_) => {
75+
return format!("StatementKind::PlaceMention:Unimplemented");
76+
}
77+
StatementKind::AscribeUserType { .. } => {
78+
return format!("StatementKind::AscribeUserType:Unimplemented");
79+
}
80+
StatementKind::Coverage(_) => return format!("StatementKind::Coverage:Unimplemented"),
81+
StatementKind::Intrinsic(_) => return format!("StatementKind::Intrinsic:Unimplemented"),
82+
StatementKind::ConstEvalCounter => {
83+
return format!("StatementKind::ConstEvalCounter:Unimplemented");
84+
}
85+
StatementKind::Nop => return format!("StatementKind::Nop:Unimplemented"),
7386
}
7487
pretty
7588
}
@@ -355,7 +368,7 @@ pub fn pretty_rvalue(rval: &Rvalue) -> String {
355368
pretty.push_str(" ");
356369
pretty.push_str(&pretty_ty(cnst.ty().kind()));
357370
}
358-
Rvalue::ShallowInitBox(_, _) => todo!(),
371+
Rvalue::ShallowInitBox(_, _) => (),
359372
Rvalue::ThreadLocalRef(item) => {
360373
pretty.push_str("thread_local_ref");
361374
pretty.push_str(format!("{:#?}", item).as_str());

src/bootstrap/src/bin/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ fn check_version(config: &Config) -> Option<String> {
174174
"update `config.toml` to use `change-id = {latest_change_id}` instead"
175175
));
176176

177-
if io::stdout().is_terminal() {
177+
if io::stdout().is_terminal() && !config.dry_run() {
178178
t!(fs::write(warned_id_path, latest_change_id.to_string()));
179179
}
180180
}

src/bootstrap/src/core/config/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,7 @@ impl Config {
19691969
config
19701970
}
19711971

1972-
pub(crate) fn dry_run(&self) -> bool {
1972+
pub fn dry_run(&self) -> bool {
19731973
match self.dry_run {
19741974
DryRun::Disabled => false,
19751975
DryRun::SelfCheck | DryRun::UserSelected => true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// run-pass
2+
use std::ptr::addr_of;
3+
4+
// When the unsized tail is a `dyn Trait`, its alignments is only dynamically known. This means the
5+
// packed(2) needs to be applied at runtime: the actual alignment of the field is `min(2,
6+
// usual_alignment)`. Here we check that we do this right by comparing size, alignment, and field
7+
// offset before and after unsizing.
8+
fn main() {
9+
#[repr(C, packed(2))]
10+
struct Packed<T: ?Sized>(u8, core::mem::ManuallyDrop<T>);
11+
12+
let p = Packed(0, core::mem::ManuallyDrop::new(1));
13+
let p: &Packed<usize> = &p;
14+
let sized = (core::mem::size_of_val(p), core::mem::align_of_val(p));
15+
let sized_offset = unsafe { addr_of!(p.1).cast::<u8>().offset_from(addr_of!(p.0)) };
16+
let p: &Packed<dyn Send> = p;
17+
let un_sized = (core::mem::size_of_val(p), core::mem::align_of_val(p));
18+
let un_sized_offset = unsafe { addr_of!(p.1).cast::<u8>().offset_from(addr_of!(p.0)) };
19+
assert_eq!(sized, un_sized);
20+
assert_eq!(sized_offset, un_sized_offset);
21+
}

src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
1111
const ENTRY_LIMIT: usize = 900;
1212
// FIXME: The following limits should be reduced eventually.
1313
const ISSUES_ENTRY_LIMIT: usize = 1852;
14-
const ROOT_ENTRY_LIMIT: usize = 866;
14+
const ROOT_ENTRY_LIMIT: usize = 867;
1515

1616
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
1717
"rs", // test source files

tests/ui/packed/dyn-trait.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// run-pass
2+
use std::ptr::addr_of;
3+
4+
// When the unsized tail is a `dyn Trait`, its alignments is only dynamically known. This means the
5+
// packed(2) needs to be applied at runtime: the actual alignment of the field is `min(2,
6+
// usual_alignment)`. Here we check that we do this right by comparing size, alignment, and field
7+
// offset before and after unsizing.
8+
fn main() {
9+
#[repr(C, packed(2))]
10+
struct Packed<T: ?Sized>(u8, core::mem::ManuallyDrop<T>);
11+
12+
let p = Packed(0, core::mem::ManuallyDrop::new(1));
13+
let p: &Packed<usize> = &p;
14+
let sized = (core::mem::size_of_val(p), core::mem::align_of_val(p));
15+
let sized_offset = unsafe { addr_of!(p.1).cast::<u8>().offset_from(addr_of!(p.0)) };
16+
let p: &Packed<dyn Send> = p;
17+
let un_sized = (core::mem::size_of_val(p), core::mem::align_of_val(p));
18+
let un_sized_offset = unsafe { addr_of!(p.1).cast::<u8>().offset_from(addr_of!(p.0)) };
19+
assert_eq!(sized, un_sized);
20+
assert_eq!(sized_offset, un_sized_offset);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// compile-flags: -Z unpretty=stable-mir -Z mir-opt-level=3
2+
// check-pass
3+
4+
fn foo(i:i32) -> i32 {
5+
i + 1
6+
}
7+
8+
fn bar(vec: &mut Vec<i32>) -> Vec<i32> {
9+
let mut new_vec = vec.clone();
10+
new_vec.push(1);
11+
new_vec
12+
}
13+
14+
fn main(){}

0 commit comments

Comments
 (0)