aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/expr.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/expr.zc')
-rw-r--r--src/compiler/expr.zc10
1 files changed, 10 insertions, 0 deletions
diff --git a/src/compiler/expr.zc b/src/compiler/expr.zc
index a6cc55c..141ca16 100644
--- a/src/compiler/expr.zc
+++ b/src/compiler/expr.zc
@@ -657,6 +657,15 @@ word closure_layout(int closure_index, int count) {
// the code that creates the closure runs, it allocates the block (code, then
// captured values), writes the three code words and copies each captured
// variable in. ctx_push / ctx_pop save and restore the enclosing function's
+// a shared variable is reachable only from a function of its own hold block, which holds
+// the block's lock for the whole call. a closure might run after the call returns.
+int shared_use(int s) {
+ int rank = sflag[s] / F_SHARED_RANK;
+ if (fhold == rank && !nclo && infn) return 0;
+ if (fhold == rank && nclo) { serrn(sname[s], "is shared; a closure can't use it, because it may run after the hold block's lock is released"); return 0; }
+ serrn(sname[s], "is shared in a hold block; only the functions written inside that block can use it (they hold its lock)");
+ return 0;
+}
// compiler state around the body.
int closure() {
char* xcf;
@@ -1095,6 +1104,7 @@ int primary() {
xcval = sval[s];
return C_PLAIN;
}
+ if (s >= 0 && (skind[s] == K_GVAR || skind[s] == K_GARR) && (sflag[s] & F_SHARED)) shared_use(s);
if (s >= 0 && skind[s] == K_GVAR) {
if (cmode) { vf_symbols(); xvk = svkind[s]; xvv = svvalue[s]; vf_at(rsn - 1, xvk, xvv); }
lit(sval[s]);