From f5f6218a23fdbe45d1a80c202a131f02c3eef0ce Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 25 Dec 2014 03:47:46 +0000 Subject: parse.y: warn past scope variable * parse.y (gettable_gen): warn possible reference to a local variable defined in a past scope. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48986 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++++ parse.y | 27 +++++++++++++++++++++++++-- test/ruby/test_parse.rb | 4 ++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8485eff2f..05ef5ded8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Thu Dec 25 12:47:44 2014 Nobuyoshi Nakada + + * parse.y (gettable_gen): warn possible reference to a local + variable defined in a past scope. + Thu Dec 25 10:09:14 2014 Nobuyoshi Nakada * ext/io/console/console.c (console_dev): id_console is not a diff --git a/parse.y b/parse.y index 20345085b5..bfc685a05f 100644 --- a/parse.y +++ b/parse.y @@ -113,6 +113,7 @@ struct local_vars { struct vtable *args; struct vtable *vars; struct vtable *used; + struct vtable *past; struct local_vars *prev; stack_type cmdargs; }; @@ -8827,6 +8828,17 @@ match_op_gen(struct parser_params *parser, NODE *node1, NODE *node2) return NEW_CALL(node1, tMATCH, NEW_LIST(node2)); } +static int +past_dvar_p(struct parser_params *parser, ID id) +{ + struct vtable *past = lvtbl->past; + while (past) { + if (vtable_included(past, id)) return 1; + past = past->prev; + } + return 0; +} + static NODE* gettable_gen(struct parser_params *parser, ID id) { @@ -8860,6 +8872,9 @@ gettable_gen(struct parser_params *parser, ID id) } return NEW_LVAR(id); } + if (!in_defined && RTEST(ruby_verbose) && past_dvar_p(parser, id)) { + rb_warningV("possible reference to past scope - %"PRIsVALUE, rb_id2str(id)); + } /* method call without arguments */ return NEW_VCALL(id); case ID_GLOBAL: @@ -9978,6 +9993,7 @@ local_push_gen(struct parser_params *parser, int inherit_dvars) local->used = !(inherit_dvars && (ifndef_ripper(compile_for_eval || e_option_supplied(parser))+0)) && RTEST(ruby_verbose) ? vtable_alloc(0) : 0; + local->past = 0; local->cmdargs = cmdarg_stack; cmdarg_stack = 0; lvtbl = local; @@ -9991,6 +10007,11 @@ local_pop_gen(struct parser_params *parser) warn_unused_var(parser, lvtbl); vtable_free(lvtbl->used); } + while (lvtbl->past) { + struct vtable *past = lvtbl->past; + lvtbl->past = past->prev; + vtable_free(past); + } vtable_free(lvtbl->args); vtable_free(lvtbl->vars); cmdarg_stack = lvtbl->cmdargs; @@ -10090,10 +10111,12 @@ dyna_pop_1(struct parser_params *parser) } tmp = lvtbl->args; lvtbl->args = lvtbl->args->prev; - vtable_free(tmp); + tmp->prev = lvtbl->past; + lvtbl->past = tmp; tmp = lvtbl->vars; lvtbl->vars = lvtbl->vars->prev; - vtable_free(tmp); + tmp->prev = lvtbl->past; + lvtbl->past = tmp; } static void diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index 70b38a2a7e..38dca83053 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -873,4 +873,8 @@ x = __ENCODING__ a = "\u{3042}" assert_warning(/#{a}/) {eval("#{a} = 1; /(?<#{a}>)/ =~ ''")} end + + def test_past_scope_variable + assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}} + end end -- cgit v1.2.3