Semantic for dereferencing a slice pointer(fat pointer)

I currently read some MIR about Vec.

From `Vec::clone`, `std::slice::from_raw_parts` is invoked to construct a slice pointer. The MIR for `std::slice::from_raw_parts` shows follow.

fn std::slice::from_raw_parts::<'_, i32>(_1: *const i32, _2: usize) -> &[i32] {
    let mut _0: &[i32];
    let mut _3: bool;
    let  _4: ();
    let mut _5: *mut ();
    let mut _6: usize;
    let mut _7: usize;
    let  _8: *const [i32];
    debug data => _1;
    debug len => _2;
    bb0: {
        StorageLive(_3);
        _3 = core::ub_checks::check_language_ub() -> [return: bb1, unwind unreachable];
    }
    bb1: {
        switchInt(move _3) -> [0: bb6, otherwise: bb2];
    }
    bb2: {
        StorageLive(_5);
        _5 = _1 as *mut ();
        StorageLive(_6);
        _6 = std::mem::size_of::<i32>() -> [return: bb3, unwind unreachable];
    }
    bb3: {
        StorageLive(_7);
        _7 = std::mem::align_of::<i32>() -> [return: bb4, unwind unreachable];
    }
    bb4: {
        _4 = std::slice::from_raw_parts::precondition_check(move _5, move _6, move _7, _2) -> [return: bb5, unwind unreachable];
    }
    bb5: {
        StorageDead(_7);
        StorageDead(_6);
        StorageDead(_5);
        goto -> bb6;
    }
    bb6: {
        StorageDead(_3);
        StorageLive(_8);
        _8 = std::ptr::slice_from_raw_parts::<i32>(move _1, move _2) -> [return: bb7, unwind unreachable];
    }
    bb7: {
        _0 = &(*_8);
        StorageDead(_8);
        return;
    }
}

I am curious about the semantics for _0 = &(*_8) in bb7.

If the cloned Vec is not allocated, _1 is an invalid pointer. For example, the empty can be created by Vec::new(). And the pointer it holds is align_of::<i32>() as *const i32.

Thus, my question is, is the star operator *_8 illegal? Or, &* is special for a fat pointer.

In that case the thin pointer half will be a non-NULL correctly aligned pointer (in practice align_of::<T>() as *const T) and the length will be 0. Any correctly aligned non-NULL pointer is valid for a slice where the amount of bytes it covers is 0 (slice.len() * size_of::<T>() == 0)

4 Likes

It’s special for a pointer to zero bytes, be that a fat pointer or a thin pointer.

For example, look at what you get from Box::new([111_u32; 0]): https://rust.godbolt.org/z/GG3P6bf76

3 Likes