summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--bootstraptest/test_jump.rb24
-rw-r--r--compile.c4
-rw-r--r--insns.def2
-rw-r--r--proc.c6
-rw-r--r--vm.c2
-rw-r--r--vm_core.h2
-rw-r--r--vm_insnhelper.c17
8 files changed, 60 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index fafc00e347..d771c4fb2f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Mon May 10 02:58:33 2010 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * compile.c (iseq_compile_each), vm_insnhelper.c (vm_invoke_block,
+ vm_throw): allow "return" and "yield" even in singleton class
+ definition. based on a patch from wanabe <s.wanabe AT gmail.com>
+ for "return". [ruby-core:21379] [ruby-dev:40975]
+
+ * insns.def (defineclass): ditto (straightforwardly push block ptr,
+ instead of dfp ptr with special flag).
+
+ * vm_core.h (RUBY_VM_CLASS_SPECIAL_P): ditto (no longer needed).
+
+ * proc.c (proc_new): ditto (remove handling for special flag).
+
+ * bootstraptest/test_jump.rb: add tests for above.
+
Mon May 10 02:29:51 2010 Yusuke Endoh <mame@tsg.ne.jp>
* cont.c (fiber_switch): raise FiberError when returning to dead
diff --git a/bootstraptest/test_jump.rb b/bootstraptest/test_jump.rb
index 9484df8852..c53d83591e 100644
--- a/bootstraptest/test_jump.rb
+++ b/bootstraptest/test_jump.rb
@@ -282,3 +282,27 @@ assert_normal_exit %q{
break
end
}, '[ruby-core:28172]'
+
+assert_equal "true", %q{
+ class Object
+ def return_eigenclass
+ class << self
+ return self
+ end
+ end
+ end
+ s = "foo"
+ s.return_eigenclass == class << s; self; end
+}, '[ruby-core:21379]'
+
+assert_equal "true", %q{
+ class Object
+ def yield_eigenclass
+ class << self
+ yield self
+ end
+ end
+ end
+ s = "foo"
+ s.yield_eigenclass {|c| c == class << s; self; end }
+}, '[ruby-dev:40975]'
diff --git a/compile.c b/compile.c
index 61dc7e10dd..ff1bb23ef5 100644
--- a/compile.c
+++ b/compile.c
@@ -4225,7 +4225,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
rb_iseq_t *is = iseq;
if (is) {
- if (is->type == ISEQ_TYPE_TOP || is->type == ISEQ_TYPE_CLASS) {
+ if (is->type == ISEQ_TYPE_TOP) {
COMPILE_ERROR((ERROR_ARGS "Invalid return"));
}
else {
@@ -4265,7 +4265,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
unsigned long flag = 0;
INIT_ANCHOR(args);
- if (iseq->type == ISEQ_TYPE_TOP || iseq->type == ISEQ_TYPE_CLASS) {
+ if (iseq->type == ISEQ_TYPE_TOP) {
COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
}
diff --git a/insns.def b/insns.def
index ba6f1d6627..79b92d8a4d 100644
--- a/insns.def
+++ b/insns.def
@@ -953,7 +953,7 @@ defineclass
/* enter scope */
vm_push_frame(th, class_iseq,
- VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_DFP() | 0x02,
+ VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_BLOCK_PTR(),
class_iseq->iseq_encoded, GET_SP(), 0,
class_iseq->local_size);
RESTORE_REGS();
diff --git a/proc.c b/proc.c
index 81ec03d954..7f7c2e8cd0 100644
--- a/proc.c
+++ b/proc.c
@@ -375,16 +375,14 @@ proc_new(VALUE klass, int is_lambda)
rb_control_frame_t *cfp = th->cfp;
rb_block_t *block;
- if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 &&
- !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) {
+ if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0) {
block = GC_GUARDED_PTR_REF(cfp->lfp[0]);
}
else {
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 &&
- !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) {
+ if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0) {
block = GC_GUARDED_PTR_REF(cfp->lfp[0]);
diff --git a/vm.c b/vm.c
index e7c9a33df5..084c8c853e 100644
--- a/vm.c
+++ b/vm.c
@@ -477,7 +477,6 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
}
if (GC_GUARDED_PTR_REF(cfp->lfp[0])) {
- if (!RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) {
rb_proc_t *p;
blockprocval = vm_make_proc_from_block(
@@ -486,7 +485,6 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass)
GetProcPtr(blockprocval, p);
*cfp->lfp = GC_GUARDED_PTR(&p->block);
}
- }
envval = rb_vm_make_env_object(th, cfp);
diff --git a/vm_core.h b/vm_core.h
index 2174613156..050d7834b4 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -597,8 +597,6 @@ typedef rb_control_frame_t *
#define RUBY_VM_NORMAL_ISEQ_P(ptr) \
(ptr && !RUBY_VM_IFUNC_P(ptr))
-#define RUBY_VM_CLASS_SPECIAL_P(ptr) (((VALUE)(ptr)) & 0x02)
-
#define RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp) ((rb_block_t *)(&(cfp)->self))
#define RUBY_VM_GET_CFP_FROM_BLOCK_PTR(b) \
((rb_control_frame_t *)((VALUE *)(b) - 5))
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 4f041a9465..f1ef50981f 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -913,8 +913,9 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_n
const rb_block_t *block = GET_BLOCK_PTR();
rb_iseq_t *iseq;
int argc = (int)num;
+ int type = GET_ISEQ()->local_iseq->type;
- if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0) {
+ if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
rb_vm_localjump_error("no block given (yield)", Qnil, 0);
}
iseq = block->iseq;
@@ -1434,6 +1435,11 @@ vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
search_parent:
if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
+ if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ dfp = cfp->dfp;
+ goto search_parent;
+ }
dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
base_iseq = base_iseq->parent_iseq;
@@ -1499,10 +1505,17 @@ vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
else if (state == TAG_RETURN) {
rb_control_frame_t *cfp = GET_CFP();
VALUE *dfp = GET_DFP();
- VALUE * const lfp = GET_LFP();
+ VALUE *lfp = GET_LFP();
/* check orphan and get dfp */
while ((VALUE *) cfp < th->stack + th->stack_size) {
+ if (!lfp) {
+ lfp = cfp->lfp;
+ }
+ if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_CLASS) {
+ lfp = 0;
+ }
+
if (cfp->lfp == lfp) {
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
VALUE *tdfp = dfp;