diff --git a/kmir/src/kmir/kdist/mir-semantics/rt/data.md b/kmir/src/kmir/kdist/mir-semantics/rt/data.md index bcce7438b..0ed80bfed 100644 --- a/kmir/src/kmir/kdist/mir-semantics/rt/data.md +++ b/kmir/src/kmir/kdist/mir-semantics/rt/data.md @@ -330,6 +330,7 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr | CtxSubslice( List , Int , Int ) // start and end always counted from beginning | CtxPointerOffset( List, Int, Int ) // pointer offset for accessing elements with an offset (Offset, Origin Length) | "CtxWrapStruct" // special context adding a singleton Aggregate(0, _) around a value + | "CtxWrapSingletonArray" // special context adding a singleton Range(ListItem(_)) around a value syntax ProjectionElem ::= PointerOffset( Int, Int ) // Same as subslice but coming from BinopOffset injected by us @@ -368,6 +369,10 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr rule #buildUpdate(Aggregate(variantIdx(0), ListItem(VALUE) .List), CtxWrapStruct CTXS) => #buildUpdate(VALUE, CTXS) + // removing a singleton-array wrapper added by a SingletonArray projection + rule #buildUpdate(Range(ListItem(VALUE) .List), CtxWrapSingletonArray CTXS) + => #buildUpdate(VALUE, CTXS) + syntax StackFrame ::= #updateStackLocal ( StackFrame, Int, Value ) [function] @@ -501,6 +506,15 @@ The situation typically arises when the stored value is a pointer (`NonNull`) bu ) => #traverseProjection(DEST, Aggregate(variantIdx(0), ListItem(VALUE)), PROJS, CtxWrapStruct CTXTS) ... [preserves-definedness, priority(100)] + + rule #traverseProjection( + DEST, + VALUE, + projectionElemSingletonArray PROJS, + CTXTS + ) + => #traverseProjection(DEST, Range(ListItem(VALUE)), PROJS, CtxWrapSingletonArray CTXTS) ... + [preserves-definedness, priority(100)] ``` A somewhat dual case to this rule can occur when a pointer into an array of data elements has been offset and is then dereferenced. @@ -1235,6 +1249,7 @@ This eliminates any `Deref` projections from the place, and also resolves `Index rule #projectionsFor(CtxPointerOffset( _, OFFSET, ORIGIN_LENGTH) CTXS, PROJS) => #projectionsFor(CTXS, PointerOffset(OFFSET, ORIGIN_LENGTH) PROJS) rule #projectionsFor(CtxFieldUnion(F_IDX, _, TY) CTXS, PROJS) => #projectionsFor(CTXS, projectionElemField(F_IDX, TY) PROJS) rule #projectionsFor( CtxWrapStruct CTXS, PROJS) => #projectionsFor(CTXS, projectionElemWrapStruct PROJS) + rule #projectionsFor(CtxWrapSingletonArray CTXS, PROJS) => #projectionsFor(CTXS, projectionElemSingletonArray PROJS) // Borrowing a zero-sized local that is still `NewLocal`: initialise it, then reuse the regular rule. rule rvalueRef(REGION, KIND, place(local(I), PROJS)) diff --git a/kmir/src/tests/integration/data/prove-rs/singleton-array-pointer-cast.rs b/kmir/src/tests/integration/data/prove-rs/singleton-array-pointer-cast.rs new file mode 100644 index 000000000..44bf4b544 --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/singleton-array-pointer-cast.rs @@ -0,0 +1,9 @@ +fn main() { + let mut x: u8 = 1; + unsafe { + let p: *mut u8 = &mut x; + let q: *mut [u8; 1] = p as *mut [u8; 1]; + std::ptr::write(q, [2]); + } + assert!(x == 2); +}