diff options
| author | 2026-10-15 09:56:19 +0330 | |
|---|---|---|
| committer | 2026-10-15 09:56:19 +0330 | |
| commit | 6bbac2edf7c50dac4d755a364b6dfd16471284d7 (patch) | |
| tree | e83b493f55ed07287cd2ab4e3a940c04871d9a14 /src/compiler/analyzer.zc | |
| parent | analyzer: use-after-end messages name the borrower, the owner and how the own... (diff) | |
analyzer: check borrow returns of forward-called functions at the unit's end; borrows clause for prototypes, definitions, externs and function types, checked against the body
Diffstat (limited to 'src/compiler/analyzer.zc')
| -rw-r--r-- | src/compiler/analyzer.zc | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/compiler/analyzer.zc b/src/compiler/analyzer.zc index 48debee..103f732 100644 --- a/src/compiler/analyzer.zc +++ b/src/compiler/analyzer.zc @@ -83,6 +83,51 @@ int effect_specialize(int original, int instance, word requirements, word edges) while (e && e != edges) { if (e[3] == original) e[3] = instance; e = e[0]; } return 0; } +// borrow returns of functions called before their body. such a call's result +// may turn out to alias an argument's owner, which is only known once the body +// has been read. the result's local keeps a shadow record (callee, the mask of +// parameters that got the owner, the owner, the token after the call, so only a call that is the whole right side counts); a +// use of the local after its owner ended is remembered, and effect_finish +// reports it when the callee's return aliases one of those parameters. +word shadow_new(int callee, int mask, int owner) { + word e; + if (!fchk || !live || dry || owner < 0 || !mask) return 0; + e = talloc(4); e[0] = callee; e[1] = mask; e[2] = owner; e[3] = tpack(); + return e; +} +// the local i is assigned: it takes the shadow of a forward call that is its whole right side. +int shadow_take(int i) { + if (!local_shadow) return 0; + local_shadow[i] = 0; + // the local read just before is the target of this assignment, not a use + if (effect_shadows && effect_shadows[10] == i && effect_shadows[11] == lreadpos[i]) effect_shadows = effect_shadows[0]; + if (xshadow && xshadow[3] == tpack()) local_shadow[i] = xshadow; + xshadow = 0; return 0; +} +int shadow_use(int i) { + word s = local_shadow[i], e; int o = s[2]; + if (!fchk || !live || lstate[o] != S_DEAD) return 0; + local_shadow[i] = 0; + e = talloc(12); e[10] = i; e[11] = tpack(); e[0] = effect_shadows; e[1] = s[0]; e[2] = s[1]; e[3] = tpack(); e[4] = curinc; e[5] = effect_floor; + e[6] = lname[i]; e[7] = 0; if (local_end_info) e[7] = local_end_info[o]; e[8] = lname[o]; e[9] = local_ended[o]; + effect_shadows = e; return 0; +} +int shadow_finish(int from) { + word e = effect_shadows, next; int flags, k; + effect_shadows = 0; + while (e) { + next = e[0]; + if (e[5] < from) { e[0] = effect_shadows; effect_shadows = e; e = next; continue; } + flags = 0; k = 0; + while (k < 24) { if ((e[2] >> k) & 1) flags = flags | effect_get(e[1], k); k++; } + if ((flags & (EF_ALIAS | EF_IDENTITY)) && !(flags & EF_UNKNOWN) && !dry) { + tunpack(e[3]); curinc = e[4]; panic = 0; + errat(); ended_message(e[6], e[7], e[8], e[9]); rt.put_s("; "); rt.put_s(sname[e[1]]); rt.put_s(", defined after this call, returns a borrow of its argument"); errend(); + } + e = next; + } + return 0; +} int effect_finish(int from) { word e, r, next; int changed = 1, flags, prior, save = tpack(), inc = curinc, i = 0; if (chkabort) return 0; @@ -110,6 +155,7 @@ int effect_finish(int from) { } e = next; } + shadow_finish(from); tunpack(save); curinc = inc; return 0; } int borrow_begin() { return 0; } @@ -393,6 +439,7 @@ int newloc(int n) { if (!local_captured) local_captured = chk_resize(0, 0, loccap); local_captured[i] = 0; if (!local_ended) local_ended = chk_resize(0, 0, loccap); local_ended[i] = 0; if (!local_end_info) local_end_info = chk_resize(0, 0, loccap); local_end_info[i] = 0; + if (!local_shadow) local_shadow = chk_resize(0, 0, loccap); local_shadow[i] = 0; lpos[i] = 0; lreadpos[i] = 0; lowner[i] = 0; @@ -1459,6 +1506,7 @@ int reassign_free(int i, int rc, int bor) { // a store of class rc into an lvalue of kind k (local or container index i) int assigncheck(int k, int i, int rc) { int st, j, r, js, bor, origin = effect_origin(rc); + if (k == LV_LOCAL) shadow_take(i); else xshadow = 0; if (k == LV_LOCAL && local_origin) { local_origin[i] = origin; local_origin_mask[i] = local_origin_mask[i] | effect_mask(rc); } if (k == LV_ELEM) { effect_note_mask(effect_mask(C_VAR + i), EF_WRITE); } if (k != LV_LOCAL && isptr(xty)) effect_note_mask(effect_mask(rc), EF_RETAIN); |
