aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/base.zc2
-rw-r--r--src/compiler/decl.zc37
2 files changed, 38 insertions, 1 deletions
diff --git a/src/compiler/base.zc b/src/compiler/base.zc
index de699aa..7d06f8e 100644
--- a/src/compiler/base.zc
+++ b/src/compiler/base.zc
@@ -192,7 +192,7 @@ int bincap = bprec_BASE - bname_BASE, uncap = useq_BASE - uname_BASE, asgcap = a
const int T_EOF = 0, T_NUM = 1, T_ID = 2, T_STR = 3, T_OP = 4, T_FLT = 5, T_BSTR = 6;
const int K_FN = 1, K_GVAR = 2, K_GARR = 3, K_CONST = 4, K_KW = 5, K_ENH = 6, K_TYPE = 7, K_DOC = 8;
-const int F_DEF = 1, F_SIG = 2, F_UNTYPED = 4, F_STMT = 8, F_EXPR = 16, F_TOP = 32, F_FALLBACK = 64, F_GEN = 128, F_PRE = 256, F_O3 = 512, F_EXT = 1024, F_TPL = 2048, F_STATIC = 4096, F_DECL = 8192, F_RETOWN = 16384, F_EARLY = 32768;
+const int F_DEF = 1, F_SIG = 2, F_UNTYPED = 4, F_STMT = 8, F_EXPR = 16, F_TOP = 32, F_FALLBACK = 64, F_GEN = 128, F_PRE = 256, F_O3 = 512, F_EXT = 1024, F_TPL = 2048, F_STATIC = 4096, F_DECL = 8192, F_RETOWN = 16384, F_EARLY = 32768, F_GUESS = 65536;
// variable states for the lifetime analyzer
const int S_PLAIN = 0, S_M = 1, S_U = 2, S_D = 3, S_DEAD = 4, S_CHILD = 5, S_BORROW = 6;
// expression classes: plain word, a new object, or a bare variable (C_VAR + index)
diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc
index 52d08c7..6bc8245 100644
--- a/src/compiler/decl.zc
+++ b/src/compiler/decl.zc
@@ -81,8 +81,44 @@ 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; let owned[16];
+ while (tk != T_EOF) {
+ 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) {
+ 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;
@@ -359,6 +395,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