diff options
| -rw-r--r-- | docs/SPEC.md | 1 | ||||
| -rw-r--r-- | src/compiler/builtins.zc | 9 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/drop_elements_pop_ok.zc | 12 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/drop_no_move_out_child.zc | 12 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/drop_no_move_out_field.zc | 13 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/drop_no_move_out_pop.zc | 11 | ||||
| -rw-r--r-- | tests/xref.baseline | 1 |
7 files changed, 58 insertions, 1 deletions
diff --git a/docs/SPEC.md b/docs/SPEC.md index 8c2f5dc..dc4934a 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -997,6 +997,7 @@ let guard = drop(heap(0), fn() { unlock(); }); // unl 6.15.2 a value dies, and its drop runs, where 6.5 frees it: at the end of its owner's block or an early exit, at `rt.free`, when its owner is reassigned (6.8.5), or with its container, whose drop runs before its children's. a new value assigned to the owner can have its own drop set on the next statement, like a declaration's. a value with a drop that nothing holds (a temporary) dies at the end of its full statement, with hint: value with drop is never bound; it drops at the end of this statement. an owned local with a drop is not "never used" (6.5.2): holding it is its use. 6.15.3 the collector runs the drop of an unreachable value after its sweep, never during it, and at most once: the value is kept until a later collection finds it unreachable again. a drop that stores `this` somewhere reachable keeps the value alive, and its drop does not run again. there is no collection at exit, so collector-owned values are not dropped then. a freed block forgets its drop, so a block reused at the same address has none. 6.15.4 copying a value with a drop into an actor message is error: x: has drop and can't be copied into a message. +6.15.5 nothing moves out of a value with a drop, whose drop may need what it holds. a field or element of it is a borrowed projection and can't be given away (error: a borrowed projection cannot transfer ownership; transfer its owner), and `pop` on an array that has a drop, or on an array field of a value with a drop, is error: a: can't move out of a value with drop. there is no `take`. borrowing a child is fine, and an array without a drop hands out its elements with `pop` as before, drops and all. ## 7. compile-time execution diff --git a/src/compiler/builtins.zc b/src/compiler/builtins.zc index 8c00636..44ed3b1 100644 --- a/src/compiler/builtins.zc +++ b/src/compiler/builtins.zc @@ -670,13 +670,18 @@ int typearg() { } // len(a), cap(a), push(a, x), pop(a), resize(a, n): growable arrays. // len of a T[n] is just n. +// arrroot: the local the array belongs to (itself, or the owner of the struct it is a field of), or -1 +int arrroot = 0 - 1; word arrvalue(int c) { - argloc = -1; arrloc = -1; + argloc = -1; arrloc = -1; arrroot = -1; if (lv && lvk == LV_LOCAL && xty[0] == TY_DYN) { arrloc = lvi; if (o3on && o3cache[lvi]) argloc = lvi; } effect_value = effect_mask(c); rval(); plainuse(c); af_access(xaf, tpack()); + if (arrloc >= 0) arrroot = lroot(arrloc); + else if (c >= C_VAR && tracked(c - C_VAR)) arrroot = lroot(c - C_VAR); + else if (xbor >= 0 && tracked(xbor)) arrroot = lroot(xbor); return xty; } // parse an array argument and retain the receiver's mutation and bounds facts. @@ -803,6 +808,8 @@ int array_pop(word t) { if (isfl(xty)) xfloat = 1; xaf = 0; xbor = -1; effect_value = 0; if (isref(xty)) { + // pop moves the element out: not out of an array with a drop, whose drop may need it (6.15.5) + if (fchk && arrroot >= 0 && ldroppable(arrroot)) cerrn(arrroot, "can't move out of a value with drop"); xcls = C_FRESH; xaf = af_new(-1, 2, tpack()); newsz = -1; newleaf = 0; return C_FRESH; } return 0; diff --git a/tests/conformance/6-ownership/drop_elements_pop_ok.zc b/tests/conformance/6-ownership/drop_elements_pop_ok.zc new file mode 100644 index 0000000..9c97e44 --- /dev/null +++ b/tests/conformance/6-ownership/drop_elements_pop_ok.zc @@ -0,0 +1,12 @@ +// expect: 5 drop5 after +// destructors 6.15.5: an array without a drop can hand out a droppable element; pop gives it to the new owner, whose block end drops it +include rt; +struct node { int v; void drop() { rt.put_s("drop"); rt.put_n(this.v); rt.put_s(" "); } } +fn main() { + node*[?] a = rt.new(node*[?]); + node* x = rt.new(node); x.v = 5; a.push(x); + { node* y = a.pop(); rt.put_n(y.v); rt.put_s(" "); } + rt.put_s("after "); + return 0; +} +// zc0: skip diff --git a/tests/conformance/6-ownership/drop_no_move_out_child.zc b/tests/conformance/6-ownership/drop_no_move_out_child.zc new file mode 100644 index 0000000..ca4a1c9 --- /dev/null +++ b/tests/conformance/6-ownership/drop_no_move_out_child.zc @@ -0,0 +1,12 @@ +// expect error: a borrowed projection cannot transfer ownership; transfer its owner +// destructors 6.15.5: a child of a value with a drop can be borrowed but not given away +include rt; +struct node { node* next; int v; void drop() { rt.put_s("drop "); rt.put_n(this.v); } } +int eat(node*.d n) { rt.put_n(n.v); return 0; } +fn main() { + node* a = rt.new(node); a.v = 1; + a.next = rt.new(node); a.next.v = 2; + eat(a.next); + return 0; +} +// zc0: skip diff --git a/tests/conformance/6-ownership/drop_no_move_out_field.zc b/tests/conformance/6-ownership/drop_no_move_out_field.zc new file mode 100644 index 0000000..e4d863c --- /dev/null +++ b/tests/conformance/6-ownership/drop_no_move_out_field.zc @@ -0,0 +1,13 @@ +// expect error: b: can't move out of a value with drop +// destructors 6.15.5: an array that is a field of a value with a drop is part of it, so pop on it is refused too +include rt; +struct bag { int*[?] items; void drop() { rt.put_s("bag drop\n"); } } +fn main() { + bag* b = rt.new(bag); + b.items = rt.new(int*[?]); + int* x = rt.new(int); *x = 5; b.items.push(x); + int* y = b.items.pop(); + rt.put_n(*y); + return 0; +} +// zc0: skip diff --git a/tests/conformance/6-ownership/drop_no_move_out_pop.zc b/tests/conformance/6-ownership/drop_no_move_out_pop.zc new file mode 100644 index 0000000..3ee248f --- /dev/null +++ b/tests/conformance/6-ownership/drop_no_move_out_pop.zc @@ -0,0 +1,11 @@ +// expect error: a: can't move out of a value with drop +// destructors 6.15.5: pop moves an element out, so it is refused on an array with a drop, whose drop may need the element +include rt; +fn main() { + int*[?] a = drop(rt.new(int*[?]), fn() { rt.put_s("arr drop\n"); }); + int* x = rt.new(int); *x = 5; a.push(x); + int* y = a.pop(); + rt.put_n(*y); + return 0; +} +// zc0: skip diff --git a/tests/xref.baseline b/tests/xref.baseline index 1660302..e83798d 100644 --- a/tests/xref.baseline +++ b/tests/xref.baseline @@ -25,6 +25,7 @@ argowner args argowner_fact args argtemporary args arrloc arrvalue chk_reset +arrroot arrvalue asg_quiet assigncheck reassign_free asgcap reserve_assignment asm_fixes reserve_asm_references |
