Skip to content

Commit a9876cb

Browse files
authored
Allow field(0) projection as a no-op when target value is a PtrLocal (#871)
The change in #811 allows pointer casts between pointers to data and pointers to "transparent wrapper structs" containing one field with the same data. While the code tries to insert `field(0, _)` projections when casting, this remediation falls short when the cast pointer is of a second degree, i.e., a pointer to a pointer. An example of this can be observed in `Iterator<_>::next`, where a pointer `**T` is cast to a pointer `*NonNull<T>`, `NonNull` being one of these "transparent wrapper structs". The proposed code change allows for a `field(0, _)` projection to be treated as a No-Op when applied to a non-aggregate (nor union), specifically a `PtrLocal` for the case of `next()`. This fixes `iter.next()` for cases where `Some(element)` is returned. The case where it returns `None` is a separate issue tested but not fixed here.
1 parent bc9101e commit a9876cb

File tree

5 files changed

+66
-0
lines changed

5 files changed

+66
-0
lines changed

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,26 @@ This is done without consideration of the validity of the Downcast[^downcast].
450450
</k>
451451
```
452452

453+
In context with pointer casts, the semantics handles the special case of a _transparent wrapper struct_:
454+
A pointer to a struct containing a single element can be cast to a pointer to the single element itself.
455+
While the pointer cast tries to insert and remove field projections to the singleton field,
456+
it is still possible that a field projection occurs on a value which is not an Aggregate (nor a union).
457+
This necessitates a special rule which allows the semantics to perform a field projection to field 0 as a Noop.
458+
The situation typically arises when the stored value is a pointer (`NonNull`), therefore the rule is restricted to this case.
459+
The context is populated with the correct field access data, so that write-backs will correct the stored value to an Aggregate.
460+
461+
```k
462+
rule <k> #traverseProjection(
463+
DEST,
464+
PtrLocal(_, _, _, _) #as VALUE,
465+
projectionElemField(fieldIdx(0), TY) PROJS,
466+
CTXTS
467+
)
468+
=> #traverseProjection(DEST, VALUE, PROJS, CtxField(variantIdx(0), ListItem(VALUE), 0, TY) CTXTS) ... </k>
469+
[preserves-definedness, priority(100)]
470+
```
471+
472+
453473
#### Unions
454474
```k
455475
// Case: Union is in same state as field projection
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct Thing { payload: u16 }
2+
3+
fn main() {
4+
let a = [Thing{payload: 1}, Thing{payload: 2}, Thing{payload: 3}];
5+
6+
let mut i = a.iter();
7+
let elem = i.next();
8+
assert!(elem.unwrap().payload == 1);
9+
let elem = i.next();
10+
assert!(elem.unwrap().payload == 2);
11+
let elem = i.next();
12+
assert!(elem.unwrap().payload == 3);
13+
// let elem = i.next();
14+
// assert!(elem.is_none());
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct Thing { payload: u16 }
2+
3+
fn main() {
4+
let a = [Thing{payload: 1}, Thing{payload: 2}, Thing{payload: 3}];
5+
6+
let mut i = a.iter();
7+
let elem = i.next();
8+
assert!(elem.unwrap().payload == 1);
9+
let elem = i.next();
10+
assert!(elem.unwrap().payload == 2);
11+
let elem = i.next();
12+
assert!(elem.unwrap().payload == 3);
13+
let elem = i.next();
14+
assert!(elem.is_none());
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
┌─ 1 (root, init)
3+
│ #execTerminator ( terminator ( ... kind: terminatorKindCall ( ... func: operandC
4+
│ span: 0
5+
6+
│ (1990 steps)
7+
└─ 3 (stuck, leaf)
8+
#traverseProjection ( toStack ( 1 , local ( 1 ) ) , Range ( .List ) , .Projectio
9+
span: 146
10+
11+
12+
┌─ 2 (root, leaf, target, terminal)
13+
│ #EndProgram ~> .K
14+
15+

kmir/src/tests/integration/test_integration.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'iterator-simple-fail',
5959
'unions-fail',
6060
'transmute-maybe-uninit-fail',
61+
'iter_next_2-fail',
6162
]
6263

6364

0 commit comments

Comments
 (0)