diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 52ffc321cbb6f..e9e60d04ae9e4 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -159,7 +159,8 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Furthermore, `align >= unsized_align`, and therefore we only need to do: // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align); - let full_size = bx.add(unsized_offset_unadjusted, unsized_size); + // total <= isize::MAX, so nuw+nsw. + let unrounded_size = bx.unchecked_suadd(unsized_offset_unadjusted, unsized_size); // Issue #27023: must add any necessary padding to `size` // (to make it a multiple of `align`) before returning it. @@ -173,10 +174,15 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // `(size + (align-1)) & -align` let one = bx.const_usize(1); let addend = bx.sub(full_align, one); - let add = bx.add(full_size, addend); + let add = bx.add(unrounded_size, addend); let neg = bx.neg(full_align); let full_size = bx.and(add, neg); + // round_up(x, a) >= x for pow2 a; with nuw above LLVM deduces + // full_size >= unrounded_size >= offset > 0 (#152788). + let size_ge = bx.icmp(IntPredicate::IntUGE, full_size, unrounded_size); + bx.assume(size_ge); + (full_size, full_align) } _ => bug!("size_and_align_of_dst: {t} not supported"), diff --git a/tests/codegen-llvm/dst-size-of-val-not-zst.rs b/tests/codegen-llvm/dst-size-of-val-not-zst.rs new file mode 100644 index 0000000000000..8a515c9e7a8aa --- /dev/null +++ b/tests/codegen-llvm/dst-size-of-val-not-zst.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ min-llvm-version: 21 +//@ needs-deterministic-layouts + +#![crate_type = "lib"] + +// Regression test for #152788: `size_of_val(p) == 0` folds to `false` for +// DSTs with a non-zero prefix (nuw+nsw on offset+tail, assume on rounding). + +pub struct Foo(pub [u32; 3], pub T); + +// CHECK-LABEL: @size_of_val_dyn_not_zero +#[no_mangle] +pub fn size_of_val_dyn_not_zero(p: &Foo) -> bool { + // CHECK: ret i1 false + std::mem::size_of_val(p) == 0 +} + +// CHECK-LABEL: @size_of_val_slice_u8_not_zero +#[no_mangle] +pub fn size_of_val_slice_u8_not_zero(p: &Foo<[u8]>) -> bool { + // CHECK: ret i1 false + std::mem::size_of_val(p) == 0 +} + +// CHECK-LABEL: @size_of_val_slice_i32_not_zero +#[no_mangle] +pub fn size_of_val_slice_i32_not_zero(p: &Foo<[i32]>) -> bool { + // CHECK: ret i1 false + std::mem::size_of_val(p) == 0 +} diff --git a/tests/codegen-llvm/dst-vtable-align-nonzero.rs b/tests/codegen-llvm/dst-vtable-align-nonzero.rs index 2eee91876683c..f074bc23fb056 100644 --- a/tests/codegen-llvm/dst-vtable-align-nonzero.rs +++ b/tests/codegen-llvm/dst-vtable-align-nonzero.rs @@ -1,4 +1,7 @@ //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ revisions: LLVM20 CURRENT +//@ [LLVM20] max-llvm-major-version: 20 +//@ [CURRENT] min-llvm-version: 21 #![crate_type = "lib"] #![feature(core_intrinsics)] @@ -30,10 +33,18 @@ pub struct Struct { pub fn eliminates_runtime_check_when_align_1( x: &Struct>, ) -> &WrapperWithAlign1 { - // CHECK: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]] + // LLVM20: load [[USIZE:i[0-9]+]], {{.+}} !range {{![0-9]+}} + // LLVM20: load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]] + // CURRENT: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]] // CHECK-NOT: llvm.umax - // CHECK-NOT: icmp // CHECK-NOT: select + // CURRENT-NOT: icmp + // LLVM20-NOT: icmp + // LLVM20: [[DOES_NOT_SHRINK:%.+]] = icmp ug{{[et]}} + // LLVM20-NEXT: call void @llvm.assume(i1 [[DOES_NOT_SHRINK]]) + // LLVM20-NOT: llvm.umax + // LLVM20-NOT: icmp + // LLVM20-NOT: select // CHECK: ret &x.dst }