mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36658 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
8637eac406
commit
93b6f8d619
8 changed files with 132 additions and 55 deletions
20
ChangeLog
20
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>
|
Wed Aug 8 05:51:20 2012 Eric Hodel <drbrain@segment7.net>
|
||||||
|
|
||||||
* proc.c (method_clone): Added documentation. Patch by Robin Dupret.
|
* proc.c (method_clone): Added documentation. Patch by Robin Dupret.
|
||||||
|
|
|
@ -414,3 +414,18 @@ assert_equal 'exception class/object expected', %q{
|
||||||
e.message
|
e.message
|
||||||
end
|
end
|
||||||
}, '[ruby-core:24767]'
|
}, '[ruby-core:24767]'
|
||||||
|
|
||||||
|
assert_equal 'ok', %q{
|
||||||
|
class C
|
||||||
|
def ===(o)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
rescue C.new
|
||||||
|
end
|
||||||
|
rescue TypeError
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
25
compile.c
25
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) {
|
if (nd_type(val) == NODE_STR) {
|
||||||
debugp_param("nd_lit", val->nd_lit);
|
debugp_param("nd_lit", val->nd_lit);
|
||||||
OBJ_FREEZE(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 {
|
else {
|
||||||
COMPILE(cond_seq, "when cond", val);
|
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);
|
ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
|
||||||
vals = vals->nd_next;
|
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_ARGSCAT:
|
||||||
case NODE_ARGSPUSH:
|
case NODE_ARGSPUSH:
|
||||||
only_special_literals = 0;
|
only_special_literals = 0;
|
||||||
|
ADD_INSN (cond_seq, nd_line(vals), dup);
|
||||||
COMPILE(cond_seq, "when/cond splat", vals);
|
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);
|
ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -3289,8 +3292,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
||||||
case NODE_ARGSPUSH:
|
case NODE_ARGSPUSH:
|
||||||
ADD_INSN(ret, nd_line(vals), putnil);
|
ADD_INSN(ret, nd_line(vals), putnil);
|
||||||
COMPILE(ret, "when2/cond splat", vals);
|
COMPILE(ret, "when2/cond splat", vals);
|
||||||
ADD_INSN1(ret, nd_line(vals), checkincludearray, Qfalse);
|
ADD_INSN1(ret, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
|
||||||
ADD_INSN(ret, nd_line(vals), pop);
|
|
||||||
ADD_INSNL(ret, nd_line(vals), branchif, l1);
|
ADD_INSNL(ret, nd_line(vals), branchif, l1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -3687,9 +3689,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
||||||
switch (nd_type(narg)) {
|
switch (nd_type(narg)) {
|
||||||
case NODE_ARRAY:
|
case NODE_ARRAY:
|
||||||
while (narg) {
|
while (narg) {
|
||||||
COMPILE(ret, "rescue arg", narg->nd_head);
|
|
||||||
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
|
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);
|
ADD_INSNL(ret, nd_line(node), branchif, label_hit);
|
||||||
narg = narg->nd_next;
|
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:
|
case NODE_ARGSPUSH:
|
||||||
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
|
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
|
||||||
COMPILE(ret, "rescue/cond splat", narg);
|
COMPILE(ret, "rescue/cond splat", narg);
|
||||||
ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue);
|
ADD_INSN1(ret, nd_line(node), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
|
||||||
ADD_INSN(ret, nd_line(node), swap);
|
|
||||||
ADD_INSN(ret, nd_line(node), pop);
|
|
||||||
ADD_INSNL(ret, nd_line(node), branchif, label_hit);
|
ADD_INSNL(ret, nd_line(node), branchif, label_hit);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -3710,10 +3710,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ADD_INSN1(ret, nd_line(node), putobject,
|
|
||||||
rb_eStandardError);
|
|
||||||
ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0));
|
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), branchif, label_hit);
|
||||||
}
|
}
|
||||||
ADD_INSNL(ret, nd_line(node), jump, label_miss);
|
ADD_INSNL(ret, nd_line(node), jump, label_miss);
|
||||||
|
|
74
insns.def
74
insns.def
|
@ -539,46 +539,6 @@ splatarray
|
||||||
obj = tmp;
|
obj = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@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
|
@c put
|
||||||
@e put new Hash.
|
@e put new Hash.
|
||||||
|
@ -857,6 +817,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
|
@c setting
|
||||||
@e trace
|
@e trace
|
||||||
|
|
4
iseq.c
4
iseq.c
|
@ -21,8 +21,8 @@
|
||||||
#include "insns.inc"
|
#include "insns.inc"
|
||||||
#include "insns_info.inc"
|
#include "insns_info.inc"
|
||||||
|
|
||||||
#define ISEQ_MAJOR_VERSION 1
|
#define ISEQ_MAJOR_VERSION 2
|
||||||
#define ISEQ_MINOR_VERSION 2
|
#define ISEQ_MINOR_VERSION 0
|
||||||
|
|
||||||
VALUE rb_cISeq;
|
VALUE rb_cISeq;
|
||||||
|
|
||||||
|
|
|
@ -431,4 +431,24 @@ end.join
|
||||||
ensure
|
ensure
|
||||||
t.close(true) if t
|
t.close(true) if t
|
||||||
end
|
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
|
end
|
||||||
|
|
10
vm_core.h
10
vm_core.h
|
@ -598,6 +598,16 @@ typedef struct {
|
||||||
} rb_binding_t;
|
} rb_binding_t;
|
||||||
|
|
||||||
/* used by compile time and send insn */
|
/* 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_SPLAT_BIT (0x01 << 1)
|
||||||
#define VM_CALL_ARGS_BLOCKARG_BIT (0x01 << 2)
|
#define VM_CALL_ARGS_BLOCKARG_BIT (0x01 << 2)
|
||||||
#define VM_CALL_FCALL_BIT (0x01 << 3)
|
#define VM_CALL_FCALL_BIT (0x01 << 3)
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue