diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2018-10-26 07:33:03 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2018-10-26 07:33:03 -0700 |
commit | e15727cf2ad6ebe2503f9ea0e16dccf118bc93ff (patch) | |
tree | 66f2a97bd0d786f8b5eb95e86bc1ce3ab1d68912 | |
parent | 9733bb6dad3b0c430a82b2592d5519383479cb86 (diff) | |
download | txr-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.c | 6 | ||||
-rw-r--r-- | unwind.c | 5 | ||||
-rw-r--r-- | unwind.h | 1 |
3 files changed, 11 insertions, 1 deletions
@@ -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, @@ -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); @@ -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); |