aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/decl.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/decl.zc')
-rw-r--r--src/compiler/decl.zc43
1 files changed, 42 insertions, 1 deletions
diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc
index 55e23a7..313d1ab 100644
--- a/src/compiler/decl.zc
+++ b/src/compiler/decl.zc
@@ -81,8 +81,48 @@ int prescan_fn(int ret, int n, int o3) {
sflag[s] = sflag[s] | F_SIG | F_PRE;
}
if (o3) sflag[s] = sflag[s] | F_O3;
+ if (!ret && is_op(s_lb) && prescan_owned(n)) { sflag[s] = sflag[s] | F_GUESS; if (sflag[s] & F_PRE) ssig[s] = ssig[s] | 1; }
return 0;
}
+// true for a token that makes a fresh owned object when called: new or heap.
+// nothing else: a call to the function itself is no evidence.
+int prescan_maker() {
+ return tk == T_ID && (rt.eq_w(tv, "rt.new") || rt.eq_w(tv, "new") || rt.eq_w(tv, "heap"));
+}
+// prescan: at the { of an untagged function's body, guess whether it returns an
+// owned object: a return of a fresh object, or of a local last set from one.
+// the guess only makes the function compile as if declared .u; its body is then
+// checked against that, so a wrong guess is an error, never a silent leak.
+int prescan_owned(int self) {
+ int depth = 0, n, k, found = 0, nown = 0, decl = 0; let owned[16];
+ while (tk != T_EOF) {
+ // a declaration's name follows a type name, a *, let or a comma; a plain
+ // assignment (to a global, say) follows ; { or }
+ int was = decl;
+ decl = tk == T_ID || (tk == T_OP && (rt.eq_w(tv, "*") || rt.eq_w(tv, ",")));
+ if (is_op(s_lb)) depth++;
+ else if (is_op(s_rb)) { depth--; if (!depth) { next(); return found; } }
+ else if (tk == T_ID && rt.eq_w(tv, "return")) {
+ next();
+ if (tk == T_ID) {
+ n = tv; peek();
+ if (pk_tk == T_OP && pk_tv == s_lp && prescan_maker()) found = 1;
+ else if (pk_tk == T_OP && pk_tv == s_semi) { k = 0; while (k < nown) { if (owned[k] == n) found = 1; k++; } }
+ }
+ continue;
+ }
+ else if (tk == T_ID && was) {
+ n = tv; peek();
+ if (pk_tk == T_OP && pk_tv == s_eq) {
+ next(); next();
+ if (prescan_maker()) { peek(); if (pk_tk == T_OP && pk_tv == s_lp && nown < 16) { owned[nown] = n; nown++; } }
+ continue;
+ }
+ }
+ next();
+ }
+ return found;
+}
// scan ahead, without emitting code, to learn what a block of tokens contains.
int prescan(int kind, int obj) {
int depth = 0, sp = panic, sn = nerr, pend = 0, po3 = 0, n, dep; char* oldmodule = module_name; word oldimports = module_imports;
@@ -409,6 +449,7 @@ int fndef(int chk, int rty, int ret, int n) {
if (amb & 1) { t = lookup(pn[i]); if (t >= 0 && skind[t] == K_TYPE) { pty[i] = sval[t]; typed = 1; } }
amb = amb >> 1; i++;
}
+ if (!ret && (sflag[s] & F_GUESS)) ret = 1; // prescan saw it return an owned object: compile it as .u
sig = ret + np + np + tags * 64;
lo = borrows_clause(pn, np, 1);
// a definition after a prototype keeps the prototype's borrows clause
@@ -448,7 +489,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;