[前][次][番号順一覧][スレッド一覧]

ruby-changes:26444

From: shugo <ko1@a...>
Date: Thu, 20 Dec 2012 17:14:04 +0900 (JST)
Subject: [ruby-changes:26444] shugo:r38495 (trunk): * vm_core.h (rb_vm_defineclass_type_t),

shugo	2012-12-20 17:13:53 +0900 (Thu, 20 Dec 2012)

  New Revision: 38495

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38495

  Log:
    * vm_core.h (rb_vm_defineclass_type_t),
      compile.c (iseq_compile_each), insns.def (defineclass): change the
      meaning of the third operand of defineclass as follows:
        lower 3bits: the type of the defineclass
                       0 = class, 1 = singleton class, 2 = module
        4th bit: a flag represents whether the defineclass is scoped
                   0 = not scoped (e.g., class Foo)
           1 = scoped (e.g., class Bar::Baz)
        5th bit: a flag represents whether the superclass is specified
                   0 = not specified (e.g., class Foo)
                   1 = specified (e.g., class Bar < Foo)
      If the superclass is specified and is not a class, a TypeError
      should be raised.  [ruby-dev:46747] [Bug #7572]
    
    * test/ruby/test_class.rb: related test.

  Modified files:
    trunk/ChangeLog
    trunk/compile.c
    trunk/insns.def
    trunk/test/ruby/test_class.rb
    trunk/vm_core.h

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38494)
+++ ChangeLog	(revision 38495)
@@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Dec 20 16:53:59 2012  Shugo Maeda  <shugo@r...>
+
+	* vm_core.h (rb_vm_defineclass_type_t),
+	  compile.c (iseq_compile_each), insns.def (defineclass): change the
+	  meaning of the third operand of defineclass as follows:
+	    lower 3bits: the type of the defineclass
+	                   0 = class, 1 = singleton class, 2 = module
+	    4th bit: a flag represents whether the defineclass is scoped
+	               0 = not scoped (e.g., class Foo)
+		       1 = scoped (e.g., class Bar::Baz)
+	    5th bit: a flag represents whether the superclass is specified
+	               0 = not specified (e.g., class Foo)
+	               1 = specified (e.g., class Bar < Foo)
+	  If the superclass is specified and is not a class, a TypeError
+	  should be raised.  [ruby-dev:46747] [Bug #7572]
+
+	* test/ruby/test_class.rb: related test.
+
 Thu Dec 20 16:52:37 2012  Martin Bosslet  <Martin.Bosslet@g...>
 
 	* NEWS: announce AEAD encryption support in the OpenSSL extension.
Index: insns.def
===================================================================
--- insns.def	(revision 38494)
+++ insns.def	(revision 38495)
@@ -885,17 +885,23 @@ trace https://github.com/ruby/ruby/blob/trunk/insns.def#L885
  */
 DEFINE_INSN
 defineclass
-(ID id, ISEQ class_iseq, rb_num_t define_type)
+(ID id, ISEQ class_iseq, rb_num_t flags)
 (VALUE cbase, VALUE super)
 (VALUE val)
 {
     VALUE klass;
+    rb_vm_defineclass_type_t type = VM_DEFINECLASS_TYPE(flags);
 
-    switch ((int)define_type) {
-      case 0: /* scoped:   class Foo::Bar */
-      case 3: /* no scope: class Bar */
+    switch (type) {
+      case VM_DEFINECLASS_TYPE_CLASS:
 	/* val is dummy.  classdef returns class scope value */
 
+	if (VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) &&
+	    !RB_TYPE_P(super, T_CLASS)) {
+	    rb_raise(rb_eTypeError, "superclass must be a Class (%s given)",
+		     rb_obj_classname(super));
+	}
+
 	if (super == Qnil) {
 	    super = rb_cObject;
 	}
@@ -906,7 +912,8 @@ defineclass https://github.com/ruby/ruby/blob/trunk/insns.def#L912
 	rb_autoload_load(cbase, id);
 	if ((klass = vm_search_const_defined_class(cbase, id)) != 0) {
 	    /* already exist */
-	    klass = define_type == 0 ? rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id);
+	    klass = VM_DEFINECLASS_SCOPED_P(flags) ?
+		rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id);
 	    if (!RB_TYPE_P(klass, T_CLASS)) {
 		rb_raise(rb_eTypeError, "%s is not a class", rb_id2name(id));
 	    }
@@ -929,13 +936,12 @@ defineclass https://github.com/ruby/ruby/blob/trunk/insns.def#L936
 	    rb_class_inherited(super, klass);
 	}
 	break;
-      case 1:
+      case VM_DEFINECLASS_TYPE_SINGLETON_CLASS:
 	/* val is dummy.  classdef returns class scope value */
 	/* super is dummy */
 	klass = rb_singleton_class(cbase);
 	break;
-      case 2: /* scoped:   module Foo::Bar  or  module ::Bar */
-      case 5: /* no scope: module Bar */
+      case VM_DEFINECLASS_TYPE_MODULE:
 	/* val is dummy.  classdef returns class scope value */
 	/* super is dummy */
 
@@ -943,7 +949,8 @@ defineclass https://github.com/ruby/ruby/blob/trunk/insns.def#L949
 
 	/* find klass */
 	if ((klass = vm_search_const_defined_class(cbase, id)) != 0) {
-	    klass = define_type == 2 ? rb_public_const_get_at(klass, id) : rb_const_get_at(klass, id);
+	    klass = VM_DEFINECLASS_SCOPED_P(flags) ?
+		rb_const_get_at(klass, id) : rb_public_const_get_at(klass, id);
 	    /* already exist */
 	    if (!RB_TYPE_P(klass, T_MODULE)) {
 		rb_raise(rb_eTypeError, "%s is not a module", rb_id2name(id));
@@ -957,7 +964,7 @@ defineclass https://github.com/ruby/ruby/blob/trunk/insns.def#L964
 	}
 	break;
       default:
-	rb_bug("unknown defineclass type: %d", (int)define_type);
+	rb_bug("unknown defineclass type: %d", (int)type);
     }
 
     COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC, NULL));
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 38494)
+++ vm_core.h	(revision 38495)
@@ -612,6 +612,21 @@ typedef struct rb_thread_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L612
     unsigned long running_time_us;
 } rb_thread_t;
 
+typedef enum {
+    VM_DEFINECLASS_TYPE_CLASS           = 0x00,
+    VM_DEFINECLASS_TYPE_SINGLETON_CLASS = 0x01,
+    VM_DEFINECLASS_TYPE_MODULE          = 0x02,
+    /* 0x03..0x06 is reserved */
+    VM_DEFINECLASS_TYPE_MASK            = 0x07,
+} rb_vm_defineclass_type_t;
+
+#define VM_DEFINECLASS_TYPE(x) ((x) & VM_DEFINECLASS_TYPE_MASK)
+#define VM_DEFINECLASS_FLAG_SCOPED         0x08
+#define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS 0x10
+#define VM_DEFINECLASS_SCOPED_P(x) ((x) & VM_DEFINECLASS_FLAG_SCOPED)
+#define VM_DEFINECLASS_HAS_SUPERCLASS_P(x) \
+    ((x) & VM_DEFINECLASS_FLAG_HAS_SUPERCLASS)
+
 /* iseq.c */
 #if defined __GNUC__ && __GNUC__ >= 4
 #pragma GCC visibility push(default)
Index: compile.c
===================================================================
--- compile.c	(revision 38494)
+++ compile.c	(revision 38495)
@@ -4848,9 +4848,12 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4848
 		rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
 		ISEQ_TYPE_CLASS, nd_line(node));
 	VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
+	int flags = VM_DEFINECLASS_TYPE_CLASS;
+	if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
+	if (node->nd_super) flags |= VM_DEFINECLASS_FLAG_HAS_SUPERCLASS;
 	COMPILE(ret, "super", node->nd_super);
 	ADD_INSN3(ret, nd_line(node), defineclass,
-		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(noscope ? 3 : 0));
+		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
 
 	if (poped) {
 	    ADD_INSN(ret, nd_line(node), pop);
@@ -4864,9 +4867,11 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4867
 	    ISEQ_TYPE_CLASS, nd_line(node));
 
 	VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
+	int flags = VM_DEFINECLASS_TYPE_MODULE;
+	if (!noscope) flags |= VM_DEFINECLASS_FLAG_SCOPED;
 	ADD_INSN (ret, nd_line(node), putnil); /* dummy */
 	ADD_INSN3(ret, nd_line(node), defineclass,
-		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(noscope ? 5 : 2));
+		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(flags));
 	if (poped) {
 	    ADD_INSN(ret, nd_line(node), pop);
 	}
@@ -4882,7 +4887,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L4887
 	ADD_INSN (ret, nd_line(node), putnil);
 	CONST_ID(singletonclass, "singletonclass");
 	ADD_INSN3(ret, nd_line(node), defineclass,
-		  ID2SYM(singletonclass), iseqval, INT2FIX(1));
+		  ID2SYM(singletonclass), iseqval,
+		  INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
 
 	if (poped) {
 	    ADD_INSN(ret, nd_line(node), pop);
Index: test/ruby/test_class.rb
===================================================================
--- test/ruby/test_class.rb	(revision 38494)
+++ test/ruby/test_class.rb	(revision 38495)
@@ -299,4 +299,41 @@ class TestClass < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_class.rb#L299
     assert_equal 1, m::C
     assert_equal 1, m.m
   end
+
+  def test_invalid_superclass
+    assert_raise(TypeError) do
+      eval <<-EOF
+        class C < nil
+        end
+      EOF
+    end
+
+    assert_raise(TypeError) do
+      eval <<-EOF
+        class C < false
+        end
+      EOF
+    end
+
+    assert_raise(TypeError) do
+      eval <<-EOF
+        class C < true
+        end
+      EOF
+    end
+
+    assert_raise(TypeError) do
+      eval <<-EOF
+        class C < 0
+        end
+      EOF
+    end
+
+    assert_raise(TypeError) do
+      eval <<-EOF
+        class C < ""
+        end
+      EOF
+    end
+  end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]