Skip to content

"_" patterns and validity invariants #261

Open
@RalfJung

Description

@RalfJung

The following code is not even unsafe, so it certainly cannot be UB:

fn foo(ptr: *const bool) {
    let _ = *ptr;
}

foo(&3u8 as *const u8 as *const bool);

This indicates that the pointer does not really get dereferenced, so the pointed-to data is never interpreted at type bool and thus must not be valid. I am not sure I like this; *ptr (as a value expression!) to me seems like it should conceptually perform the load even if the result is later discarded.

Something similar happens here:

fn bar(ptr: *const (i8, bool)) { unsafe {
    let (x, _) = *ptr;
} }

This compiles effectively to let x = (*ptr).0, so again whatever data is in the second field does not matter. (Note that *ptr here occurs only as a place expression, not as a value expression, so it makes sense that in (*ptr).0 we do not require the second field to be valid.)

I think this behavior of "_" can be explained by saying that it suppresses the place-to-value coercion, and it is smart enough to even do this in cases like (x, _) where the coercion is partially suppressed. But I am not sure I like this semantics, it seems rather counter-intuitive to me. It also makes patterns much harder to explain. And it leads to strange special cases such as rust-lang/rust#79735 (I cannot tell if this is some compiler author also being confused by "_", or if the intention is that ! is special in that even creating the place is already UB, or something else).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-validityTopic: Related to validity invariantsS-pending-documentationStatus: The issue is "resolved," but this resolution needs documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions