summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--bootstraptest/test_exception.rb15
-rw-r--r--compile.c25
-rw-r--r--insns.def74
-rw-r--r--iseq.c4
-rw-r--r--test/ruby/test_exception.rb20
-rw-r--r--vm_core.h10
-rw-r--r--vm_insnhelper.c19
8 files changed, 132 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 732ef9a337..89394e8a34 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+Wed Aug 8 16:27:58 2012 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c, insns.def (checkmatch):
+ remove checkincludearray instruction and
+ add new instruction checkmatch.
+ This change is to solve
+ [Bug #4438] "rescue args type check omitted".
+
+ * iseq.c: increment ISEQ_MAJOR_VERSION because removal of
+ checkincludearray instruction.
+
+ * vm_core.h: add several definitions for
+ the checkmatch instruction.
+
+ * vm_insnhelper.c (check_match): added.
+
+ * bootstraptest/test_exception.rb: add a test.
+
+ * test/ruby/test_exception.rb: ditto.
+
Wed Aug 8 05:51:20 2012 Eric Hodel <drbrain@segment7.net>
* proc.c (method_clone): Added documentation. Patch by Robin Dupret.
diff --git a/bootstraptest/test_exception.rb b/bootstraptest/test_exception.rb
index f7d5eeaa07..b0d37234b8 100644
--- a/bootstraptest/test_exception.rb
+++ b/bootstraptest/test_exception.rb
@@ -414,3 +414,18 @@ assert_equal 'exception class/object expected', %q{
e.message
end
}, '[ruby-core:24767]'
+
+assert_equal 'ok', %q{
+ class C
+ def ===(o)
+ true
+ end
+ end
+ begin
+ begin
+ rescue C.new
+ end
+ rescue TypeError
+ :ok
+ end
+}
diff --git a/compile.c b/compile.c
index 5d028c9236..36ccd90e80 100644
--- a/compile.c
+++ b/compile.c
@@ -2458,6 +2458,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int onl
}
}
+ ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
+
if (nd_type(val) == NODE_STR) {
debugp_param("nd_lit", val->nd_lit);
OBJ_FREEZE(val->nd_lit);
@@ -2466,8 +2468,8 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int onl
else {
COMPILE(cond_seq, "when cond", val);
}
- ADD_INSN1(cond_seq, nd_line(val), topn, INT2FIX(1));
- ADD_SEND(cond_seq, nd_line(val), ID2SYM(idEqq), INT2FIX(1));
+
+ ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
vals = vals->nd_next;
}
@@ -3207,8 +3209,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
case NODE_ARGSCAT:
case NODE_ARGSPUSH:
only_special_literals = 0;
+ ADD_INSN (cond_seq, nd_line(vals), dup);
COMPILE(cond_seq, "when/cond splat", vals);
- ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue);
+ ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
break;
default:
@@ -3289,8 +3292,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
case NODE_ARGSPUSH:
ADD_INSN(ret, nd_line(vals), putnil);
COMPILE(ret, "when2/cond splat", vals);
- ADD_INSN1(ret, nd_line(vals), checkincludearray, Qfalse);
- ADD_INSN(ret, nd_line(vals), pop);
+ ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
ADD_INSNL(ret, nd_line(vals), branchif, l1);
break;
default:
@@ -3687,9 +3689,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
switch (nd_type(narg)) {
case NODE_ARRAY:
while (narg) {
- COMPILE(ret, "rescue arg", narg->nd_head);
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
- ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
+ COMPILE(ret, "rescue arg", narg->nd_head);
+ ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
ADD_INSNL(ret, nd_line(node), branchif, label_hit);
narg = narg->nd_next;
}
@@ -3699,9 +3701,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
case NODE_ARGSPUSH:
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
COMPILE(ret, "rescue/cond splat", narg);
- ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
- ADD_INSN(ret, nd_line(node), swap);
- ADD_INSN(ret, nd_line(node), pop);
+ ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
ADD_INSNL(ret, nd_line(node), branchif, label_hit);
break;
default:
@@ -3710,10 +3710,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
}
}
else {
- ADD_INSN1(ret, nd_line(node), putobject,
- rb_eStandardError);
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
- ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1));
+ ADD_INSN1(ret, nd_line(node), putobject, rb_eStandardError);
+ ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
ADD_INSNL(ret, nd_line(node), branchif, label_hit);
}
ADD_INSNL(ret, nd_line(node), jump, label_miss);
diff --git a/insns.def b/insns.def
index 12cbed730d..b2f17c5fef 100644
--- a/insns.def
+++ b/insns.def
@@ -541,46 +541,6 @@ splatarray
/**
@c put
- @e check value is included in ary
- @j 配列 ary に要素 obj が入っているかどうかチェック。case/when で利用する。
- */
-DEFINE_INSN
-checkincludearray
-(VALUE flag)
-(VALUE obj, VALUE ary)
-(VALUE obj, VALUE result)
-{
- int i;
- result = Qfalse;
-
- if (!RB_TYPE_P(ary, T_ARRAY)) {
- ary = rb_Array(ary);
- }
-
- if (flag == Qtrue) {
- /* NODE_CASE */
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- /* TODO: fix me (use another method dispatch) */
- if (RTEST(rb_funcall2(RARRAY_PTR(ary)[i], idEqq, 1, &obj))) {
- result = Qtrue;
- break;
- }
- }
- }
- else {
- obj = Qfalse;
- /* NODE_WHEN */
- for (i = 0; i < RARRAY_LEN(ary); i++) {
- if (RTEST(RARRAY_PTR(ary)[i])) {
- obj = result = Qtrue;
- break;
- }
- }
- }
-}
-
-/**
- @c put
@e put new Hash.
@j 新しいハッシュをスタックトップの n 個を初期値として生成する。
n はキーと値のペアなので 2 の倍数でなければならない。
@@ -859,6 +819,40 @@ defined
/**
@c setting
+ @e check `target' matches `pattern'.
+ `flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
+ VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
+ VM_CHECKMATCH_TYPE_CASE: check `patten === target'.
+ VM_CHECKMATCH_TYPE_RESCUE: check `pattern.kind_op?(Module) && pattern == target'.
+ if `flag & VM_CHECKMATCH_ARRAY' is not 0, then `patten' is array of patterns.
+ @j see above comments.
+ */
+DEFINE_INSN
+checkmatch
+(rb_num_t flag)
+(VALUE target, VALUE pattern)
+(VALUE result)
+{
+ result = Qfalse;
+
+ if (flag & VM_CHECKMATCH_ARRAY) {
+ int i;
+ for (i = 0; i < RARRAY_LEN(pattern); i++) {
+ if (RTEST(check_match(RARRAY_PTR(pattern)[i], target, flag & VM_CHECKMATCH_TYPE_MASK))) {
+ result = Qtrue;
+ break;
+ }
+ }
+ }
+ else {
+ if (RTEST(check_match(pattern, target, flag & VM_CHECKMATCH_TYPE_MASK))) {
+ result = Qtrue;
+ }
+ }
+}
+
+/**
+ @c setting
@e trace
@j trace 用の命令。
*/
diff --git a/iseq.c b/iseq.c
index 8b08752185..8d8d92174d 100644
--- a/iseq.c
+++ b/iseq.c
@@ -21,8 +21,8 @@
#include "insns.inc"
#include "insns_info.inc"
-#define ISEQ_MAJOR_VERSION 1
-#define ISEQ_MINOR_VERSION 2
+#define ISEQ_MAJOR_VERSION 2
+#define ISEQ_MINOR_VERSION 0
VALUE rb_cISeq;
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index c49bd51064..93b24bbdd5 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -431,4 +431,24 @@ end.join
ensure
t.close(true) if t
end
+
+ Bug4438 = '[ruby-core:35364]'
+
+ def test_rescue_single_argument
+ assert_raise(TypeError, Bug4438) do
+ begin
+ raise
+ rescue 1
+ end
+ end
+ end
+
+ def test_rescue_splat_argument
+ assert_raise(TypeError, Bug4438) do
+ begin
+ raise
+ rescue *Array(1)
+ end
+ end
+ end
end
diff --git a/vm_core.h b/vm_core.h
index 62850f28ce..da20e18acc 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -598,6 +598,16 @@ typedef struct {
} rb_binding_t;
/* used by compile time and send insn */
+
+enum vm_check_match_type {
+ VM_CHECKMATCH_TYPE_WHEN = 1,
+ VM_CHECKMATCH_TYPE_CASE = 2,
+ VM_CHECKMATCH_TYPE_RESCUE = 3
+};
+
+#define VM_CHECKMATCH_TYPE_MASK 0x03
+#define VM_CHECKMATCH_ARRAY 0x04
+
#define VM_CALL_ARGS_SPLAT_BIT (0x01 << 1)
#define VM_CALL_ARGS_BLOCKARG_BIT (0x01 << 2)
#define VM_CALL_FCALL_BIT (0x01 << 3)
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index b9c5e115c1..bb39b848cf 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1848,3 +1848,22 @@ rb_vm_using_modules(NODE *cref, VALUE klass)
}
}
+static VALUE
+check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
+{
+ switch (type) {
+ case VM_CHECKMATCH_TYPE_WHEN:
+ return pattern;
+ case VM_CHECKMATCH_TYPE_CASE:
+ return rb_funcall2(pattern, idEqq, 1, &target);
+ case VM_CHECKMATCH_TYPE_RESCUE: {
+ if (!rb_obj_is_kind_of(pattern, rb_cModule)) {
+ rb_raise(rb_eTypeError, "class or module required for rescue clause");
+ }
+ return RTEST(rb_funcall2(pattern, idEqq, 1, &target));
+ }
+ default:
+ rb_bug("check_match: unreachable");
+ }
+}
+