Skip to content

Commit 404a488

Browse files
committed
Add range information to slice metadata for types that are known to not be ZST
This uses a conservative approximation since the layout of the pointee is not always available when computing the metadata layout.
1 parent 4f4a413 commit 404a488

File tree

4 files changed

+74
-5
lines changed

4 files changed

+74
-5
lines changed

compiler/rustc_middle/src/ty/sty.rs

+28
Original file line numberDiff line numberDiff line change
@@ -2842,6 +2842,34 @@ impl<'tcx> Ty<'tcx> {
28422842
}
28432843
}
28442844

2845+
pub fn is_trivially_non_zst(self, tcx: TyCtxt<'tcx>) -> bool {
2846+
match self.kind() {
2847+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
2848+
| ty::Uint(_)
2849+
| ty::Int(_)
2850+
| ty::Bool
2851+
| ty::Float(_)
2852+
| ty::FnPtr(_)
2853+
| ty::RawPtr(..)
2854+
| ty::Char
2855+
| ty::Ref(..)
2856+
| ty::Closure(..) => true,
2857+
ty::Array(ty, len) => {
2858+
if let Some(len) = len.try_to_target_usize(tcx) {
2859+
return len > 0 && ty.is_trivially_non_zst(tcx);
2860+
}
2861+
false
2862+
}
2863+
ty::Tuple(tys) => tys.iter().any(|ty| ty.is_trivially_non_zst(tcx)),
2864+
ty::Adt(def, args) => def.all_fields().any(|field| {
2865+
let ty = field.ty(tcx, args);
2866+
ty.is_trivially_non_zst(tcx)
2867+
}),
2868+
2869+
_ => false,
2870+
}
2871+
}
2872+
28452873
/// Fast path helper for primitives which are always `Copy` and which
28462874
/// have a side-effect-free `Clone` impl.
28472875
///

compiler/rustc_ty_utils/src/layout.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,24 @@ fn layout_of_uncached<'tcx>(
200200
return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
201201
}
202202

203-
let Abi::Scalar(metadata) = metadata_layout.abi else {
203+
let Abi::Scalar(mut metadata) = metadata_layout.abi else {
204204
return Err(error(cx, LayoutError::Unknown(pointee)));
205205
};
206206

207+
if !ty.is_unsafe_ptr() {
208+
match pointee.kind() {
209+
ty::Slice(element) => {
210+
if element.is_trivially_non_zst(tcx) {
211+
metadata.valid_range_mut().end = dl.ptr_sized_integer().signed_max() as u128;
212+
}
213+
},
214+
ty::Str => {
215+
metadata.valid_range_mut().end = dl.ptr_sized_integer().signed_max() as u128;
216+
}
217+
_ => {}
218+
}
219+
}
220+
207221
metadata
208222
} else {
209223
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
@@ -212,7 +226,18 @@ fn layout_of_uncached<'tcx>(
212226
ty::Foreign(..) => {
213227
return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
214228
}
215-
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
229+
ty::Slice(element) => {
230+
let mut metadata = scalar_unit(Int(dl.ptr_sized_integer(), false));
231+
if !ty.is_unsafe_ptr() && !element.is_trivially_non_zst(tcx) {
232+
metadata.valid_range_mut().end = dl.ptr_sized_integer().signed_max() as u128;
233+
}
234+
metadata
235+
},
236+
ty::Str => {
237+
let mut metadata = scalar_unit(Int(dl.ptr_sized_integer(), false));
238+
metadata.valid_range_mut().end = dl.ptr_sized_integer().signed_max() as u128;
239+
metadata
240+
},
216241
ty::Dynamic(..) => {
217242
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
218243
vtable.valid_range_mut().start = 1;

tests/codegen/intrinsics/transmute.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,11 @@ pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option<Box<[u8]>> {
372372
#[no_mangle]
373373
pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] {
374374
// CHECK: %_0.0 = inttoptr i64 %x.0 to ptr
375-
// CHECK: %0 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0
376-
// CHECK: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1
377-
// CHECK: ret { ptr, i64 } %1
375+
// CHECK: %0 = icmp ule i64 %x.1, 9223372036854775807
376+
// CHECK: call void @llvm.assume(i1 %0)
377+
// CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0
378+
// CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1
379+
// CHECK: ret { ptr, i64 } %2
378380
transmute(x)
379381
}
380382

tests/codegen/slice-len.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// ignore-debug: the debug assertions get in the way
2+
// compile-flags: -O
3+
// min-llvm-version: 16
4+
#![crate_type = "lib"]
5+
6+
// check that slice.len() has range metadata
7+
8+
// CHECK-LABEL: @slice_len
9+
#[no_mangle]
10+
pub fn slice_len(slice: &&[i32]) -> usize {
11+
// CHECK: load {{.*}} !range
12+
slice.len()
13+
// CHECK: ret
14+
}

0 commit comments

Comments
 (0)