summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-10-26 07:33:03 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-10-26 07:33:03 -0700
commite15727cf2ad6ebe2503f9ea0e16dccf118bc93ff (patch)
tree66f2a97bd0d786f8b5eb95e86bc1ce3ab1d68912
parent9733bb6dad3b0c430a82b2592d5519383479cb86 (diff)
downloadtxr-e15727cf2ad6ebe2503f9ea0e16dccf118bc93ff.tar.gz
txr-e15727cf2ad6ebe2503f9ea0e16dccf118bc93ff.tar.bz2
txr-e15727cf2ad6ebe2503f9ea0e16dccf118bc93ff.zip
defvar: warn about prior lexical uses.
Now that the compiler has a more efficient treatment of global lexical variables, code which accesses global variables that have not yet been defined will misbehave if the intent is to for those variables to be dynamically scoped. There is such a bug in the op expander, in fact. * eval.c (me_def_variable): When defvar/defparm are expanding, they now check whether there is an outstanding unbound warning against the variable. If so, then a warning is issued that the variable was previously used lexically and is now being marked special. * unwind.c (uw_warning_exists): New function. * unwind.h (uw_warning_exists): Declared.
-rw-r--r--eval.c6
-rw-r--r--unwind.c5
-rw-r--r--unwind.h1
3 files changed, 11 insertions, 1 deletions
diff --git a/eval.c b/eval.c
index 50c6fbc7..e28e1164 100644
--- a/eval.c
+++ b/eval.c
@@ -2929,8 +2929,12 @@ static val me_def_variable(val form, val menv)
if (!bindable(sym))
not_bindable_error(form, sym);
- if (op == defparm_s || op == defvar_s)
+ if (op == defparm_s || op == defvar_s) {
mark_special(sym);
+ if (uw_warning_exists(cons(var_s, sym)))
+ eval_warn(form, lit("~s: global ~s marked special after lexical uses"),
+ op, sym, nao);
+ }
return apply_frob_args(list(prog1_s,
cons(defvarl_s,
diff --git a/unwind.c b/unwind.c
index b89bf991..36c1a1e0 100644
--- a/unwind.c
+++ b/unwind.c
@@ -707,6 +707,11 @@ val uw_defer_warning(val args)
return nil;
}
+val uw_warning_exists(val tag)
+{
+ return member(tag, deferred_warnings, equal_f, cdr_f);
+}
+
val uw_register_tentative_def(val tag)
{
uw_purge_deferred_warning(tag);
diff --git a/unwind.h b/unwind.h
index b08f8dc9..33106a0a 100644
--- a/unwind.h
+++ b/unwind.h
@@ -137,6 +137,7 @@ noreturn val uw_throwfv(val sym, val fmt, struct args *);
noreturn val uw_errorf(val fmt, ...);
noreturn val uw_errorfv(val fmt, struct args *args);
val uw_defer_warning(val args);
+val uw_warning_exists(val tag);
val uw_dump_deferred_warnings(val stream);
val uw_release_deferred_warnings(void);
val uw_purge_deferred_warning(val tag);