diff options
| -rw-r--r-- | src/compiler/analyzer.zc | 8 | ||||
| -rw-r--r-- | src/compiler/decl.zc | 2 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/infer_owned_return_borrow_first.zc | 10 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/infer_owned_return_mixed.zc | 11 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/u_return_param_field.zc | 7 | ||||
| -rw-r--r-- | tests/conformance/6-ownership/u_return_plain_param.zc | 8 |
6 files changed, 45 insertions, 1 deletions
diff --git a/src/compiler/analyzer.zc b/src/compiler/analyzer.zc index 839c1ef..55a96bb 100644 --- a/src/compiler/analyzer.zc +++ b/src/compiler/analyzer.zc @@ -1644,6 +1644,7 @@ int assigncheck(int k, int i, int rc) { // the function has no .u (its callers compiled after this point see it). an m // object is lent, not given, so returning it is an error, and so is a plain word // from an owned function that was called before its body. +int ret_borrowed; int retcheck(int c) { int i; if (isptr(xty) || xty == tword) { @@ -1670,9 +1671,16 @@ int retcheck(int c) { if ((isptr(xty) || isagg(xty)) && ((xaf && xaf[2] == 4) || (xbor >= 0 && lafact[xbor] && lafact[xbor][2] == 4))) { cerr("an array literal cannot escape its function through return"); return 0; } i = -1; if (c >= C_VAR && tracked(c - C_VAR)) i = c - C_VAR; + // a value that comes from a parameter the caller still owns (not a .d one, + // which is tracked) is a borrow: it can't become the caller's owned result. + if (c != C_FRESH && i < 0 && isptr(xty) && effect_mask(c)) { + if (fret) { cerr("a borrowed parameter cannot be returned as an owned result"); return 0; } + ret_borrowed = 1; + } if (i >= 0 && lstate[lroot(i)] == S_DEAD) { cerrn(i, "used after it was given away"); return 0; } if (i >= 0 && (lstate[i] == S_D || (lstate[i] == S_M && lown[i])) && (fret || finfer)) lstate[i] = S_U; // returning an owned object (a d object, or a local that owns one) gives it up, as u*x does if (!fret && finfer && (c == C_FRESH || (i >= 0 && lstate[i] == S_U))) { + if (ret_borrowed) cerr("this function also returns a borrowed parameter, so its result can't be owned"); if (sflag[finsym] & F_EARLY) serrn(sname[finsym], "is called before its body, so its owned return can't be known there; declare the return type with .u"); ssig[finsym] = ssig[finsym] | 1; // the return is owned: callers read it from the signature sflag[finsym] = sflag[finsym] | F_RETOWN; diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc index 6bc8245..e2c3613 100644 --- a/src/compiler/decl.zc +++ b/src/compiler/decl.zc @@ -435,7 +435,7 @@ int fndef(int chk, int rty, int ret, int n) { fixall(sfix[s], here); sfix[s] = 0; fn_begin(chk, ret); lt = lt_begin(sval[s], sname[s], lfl); xc_fn = sname[s]; - finsym = s; finfer = !ret; + finsym = s; finfer = !ret; ret_borrowed = 0; effect_current = effect_record(s); rt.fill_w(effect_current, 0, 50); effect_current[0] = 1; if (!chk || stubgen) effect_current[0] = 2; effect_current[1] = np; i = 0; while (i < np) { if (pt[i] == 2) { effect_current[2 + i] = EF_CONSUME; effect_current[26 + i] = EF_CONSUME; } i++; } if (typed && explicit_rty) fty = rty; diff --git a/tests/conformance/6-ownership/infer_owned_return_borrow_first.zc b/tests/conformance/6-ownership/infer_owned_return_borrow_first.zc new file mode 100644 index 0000000..e75fb10 --- /dev/null +++ b/tests/conformance/6-ownership/infer_owned_return_borrow_first.zc @@ -0,0 +1,10 @@ +// expect error: a borrowed parameter cannot be returned as an owned result +// spec 6.8 +include rt; +struct node { int v; node* next; }; +node* pick(node* other, int which) { + if (which) return other; + return rt.new(node); +} +fn main() { } +// zc0: skip diff --git a/tests/conformance/6-ownership/infer_owned_return_mixed.zc b/tests/conformance/6-ownership/infer_owned_return_mixed.zc new file mode 100644 index 0000000..5216003 --- /dev/null +++ b/tests/conformance/6-ownership/infer_owned_return_mixed.zc @@ -0,0 +1,11 @@ +// expect error: a borrowed parameter cannot be returned as an owned result +// spec 6.8 +include rt; +struct node { int value; node* next; }; +node* pick(node* other, int which) { + node* fresh = rt.new(node); + if (which) return fresh; + return other; +} +fn main() { node* a = rt.new(node); node* b = pick(a, 1); rt.put_n(b.value); } +// zc0: skip diff --git a/tests/conformance/6-ownership/u_return_param_field.zc b/tests/conformance/6-ownership/u_return_param_field.zc new file mode 100644 index 0000000..af8284d --- /dev/null +++ b/tests/conformance/6-ownership/u_return_param_field.zc @@ -0,0 +1,7 @@ +// expect error: a borrowed parameter cannot be returned as an owned result +// spec 6.8 +include rt; +struct node { int v; node* next; }; +node*.u nxt(node* l) { node* c = l.next; return c; } +fn main() { } +// zc0: skip diff --git a/tests/conformance/6-ownership/u_return_plain_param.zc b/tests/conformance/6-ownership/u_return_plain_param.zc new file mode 100644 index 0000000..5aca40b --- /dev/null +++ b/tests/conformance/6-ownership/u_return_plain_param.zc @@ -0,0 +1,8 @@ +// expect error: a borrowed parameter cannot be returned as an owned result +// spec 6.8 +include rt; +memdebug on; +struct node { int value; node* next; }; +node*.u pick(node* other) { return other; } +fn main() { node* a = rt.new(node); { node* b = pick(a); rt.put_n(b.value); } rt.put_n(a.value); } +// zc0: skip |
