diff --git a/ChangeLog b/ChangeLog index d3ff66d588..3c00b060d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Sat Feb 11 12:04:05 2012 Nobuyoshi Nakada + + * compile.c (defined_expr): guard the whole expression. + [ruby-dev:45021][Bug#5786] + Sat Feb 11 08:34:42 2012 Eric Hodel * ext/zlib/zlib.c (rb_inflate_add_dictionary): Added diff --git a/compile.c b/compile.c index da8ef32c58..32bda525b3 100644 --- a/compile.c +++ b/compile.c @@ -238,6 +238,9 @@ r_value(VALUE value) #define ADD_LABEL(seq, label) \ ADD_ELEM((seq), (LINK_ELEMENT *) (label)) +#define APPEND_LABEL(seq, before, label) \ + APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label)) + #define ADD_ADJUST(seq, line, label) \ ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (line))) @@ -392,8 +395,23 @@ ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem) anchor->last = elem; verify_list("add", anchor); } + +/* + * elem1, before, elem2 => elem1, before, elem, elem2 + */ +static void +APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem) +{ + elem->prev = before; + elem->next = before->next; + elem->next->prev = elem; + before->next = elem; + if (before == anchor->last) anchor->last = elem; + verify_list("add", anchor); +} #if CPDEBUG < 0 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem)) +#define APPEND_ELEM(anchor, before, elem) ADD_ELEM(iseq, (anchor), (before), (elem)) #endif static int @@ -2616,6 +2634,7 @@ compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath) } } +#define defined_expr defined_expr0 static int defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, LABEL **lfinish, VALUE needstr) @@ -2737,21 +2756,9 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]); } if (!self) { - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(), - rb_str_concat(rb_str_new2 - ("defined guard in "), - iseq->name), - ISEQ_TYPE_DEFINED_GUARD, 0); - defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse); ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]); - - ADD_LABEL(ret, lstart); COMPILE(ret, "defined/recv", node->nd_recv); - ADD_LABEL(ret, lend); - ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]); ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD), ID2SYM(node->nd_mid), needstr); } @@ -2815,6 +2822,29 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, } return 0; } +#undef defined_expr + +static int +defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, + NODE *node, LABEL **lfinish, VALUE needstr) +{ + LINK_ELEMENT *lcur = ret->last; + int done = defined_expr0(iseq, ret, node, lfinish, needstr); + if (lfinish[1]) { + int line = nd_line(node); + LABEL *lstart = NEW_LABEL(line); + LABEL *lend = NEW_LABEL(line); + VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(), + rb_str_concat(rb_str_new2 + ("defined guard in "), + iseq->name), + ISEQ_TYPE_DEFINED_GUARD, 0); + APPEND_LABEL(ret, lcur, lstart); + ADD_LABEL(ret, lend); + ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]); + } + return done; +} #define BUFSIZE 0x100 diff --git a/test/ruby/test_defined.rb b/test/ruby/test_defined.rb index bae85c9265..2552626b9e 100644 --- a/test/ruby/test_defined.rb +++ b/test/ruby/test_defined.rb @@ -113,15 +113,27 @@ class TestDefined < Test::Unit::TestCase def a? defined?(A) end + def b? + defined?(A::B) + end end def test_autoloaded_noload loaded = $".dup $".clear + loadpath = $:.dup + $:.clear x = TestAutoloadedNoload.new assert_equal("constant", x.a?) + assert_nil(x.b?) assert_equal([], $") ensure $".replace(loaded) + $:.replace(loadpath) + end + + def test_exception + bug5786 = '[ruby-dev:45021]' + assert_nil(defined?(raise("[Bug#5786]")::A), bug5786) end end