summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-24 09:20:42 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-24 09:20:42 +0000
commit66d247bcb50a29769ff940100223544c125521aa (patch)
tree2d6f3c72524c2669cbb370b14204a914344c6614
parent24f00be686bdd5dc78a59b7566e85ab70796de01 (diff)
* compile.c: fix to output warning when the same literals
are available as a condition of same case clause. And remove infomation ('#n') because we can find duplicated condition with explicit line numbers. [ruby-core:38343] [Ruby 1.9 - Bug #5068] * test/ruby/test_syntax.rb: add a test for above. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35459 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog10
-rw-r--r--compile.c96
-rw-r--r--test/ruby/test_syntax.rb23
3 files changed, 80 insertions, 49 deletions
diff --git a/ChangeLog b/ChangeLog
index bcde6499fd..5f48bda3d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Tue Apr 24 18:12:13 2012 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c: fix to output warning when the same literals
+ are available as a condition of same case clause.
+ And remove infomation ('#n') because we can find duplicated
+ condition with explicit line numbers.
+ [ruby-core:38343] [Ruby 1.9 - Bug #5068]
+
+ * test/ruby/test_syntax.rb: add a test for above.
+
Tue Apr 24 17:03:51 2012 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (waitpid): need to check the return value of
diff --git a/compile.c b/compile.c
index 508d599d08..74982db138 100644
--- a/compile.c
+++ b/compile.c
@@ -1309,6 +1309,21 @@ static const struct st_hash_type cdhash_type = {
cdhash_hash,
};
+struct cdhash_set_label_struct {
+ VALUE hash;
+ int pos;
+ int len;
+};
+
+static int
+cdhash_set_label_i(VALUE key, VALUE val, void *ptr)
+{
+ struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
+ LABEL *lobj = (LABEL *)(val & ~1);
+ rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
+ return ST_CONTINUE;
+}
+
/**
ruby insn object list -> raw instruction sequence
*/
@@ -1427,41 +1442,19 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
if (lobj->sp == -1) {
lobj->sp = sp;
}
- generated_iseq[pos + 1 + j] =
- lobj->position - (pos + len);
+ generated_iseq[pos + 1 + j] = lobj->position - (pos + len);
break;
}
case TS_CDHASH:
{
- /*
- * [obj, label, ...]
- */
- int i;
- VALUE lits = operands[j];
- VALUE map = rb_hash_new();
- RHASH_TBL(map)->type = &cdhash_type;
-
- for (i=0; i < RARRAY_LEN(lits); i+=2) {
- VALUE obj = rb_ary_entry(lits, i);
- VALUE lv = rb_ary_entry(lits, i+1);
- lobj = (LABEL *)(lv & ~1);
-
- if (!lobj->set) {
- rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
- "unknown label");
- }
- if (!st_lookup(rb_hash_tbl(map), obj, 0)) {
- rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len)));
- }
- else {
- int n = i/2 + 1;
- rb_compile_warning(RSTRING_PTR(iseq->filename), iobj->line_no,
- "duplicated when clause (#%d) is ignored", n);
- }
- }
+ VALUE map = operands[j];
+ struct cdhash_set_label_struct data = {
+ map, pos, len,
+ };
+ rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
+
hide_obj(map);
generated_iseq[pos + 1 + j] = map;
- iseq_add_mark_object(iseq, map);
break;
}
case TS_LINDEX:
@@ -2428,25 +2421,26 @@ case_when_optimizable_literal(NODE * node)
case NODE_STR:
return node->nd_lit;
}
- return Qfalse;
+ return Qundef;
}
-static VALUE
-when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE special_literals)
+static int
+when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int only_special_literals, VALUE literals)
{
while (vals) {
- VALUE lit;
- NODE* val;
-
- val = vals->nd_head;
+ NODE* val = vals->nd_head;
+ VALUE lit = case_when_optimizable_literal(val);
- if (special_literals &&
- (lit = case_when_optimizable_literal(val)) != Qfalse) {
- rb_ary_push(special_literals, lit);
- rb_ary_push(special_literals, (VALUE)(l1) | 1);
+ if (lit == Qundef) {
+ only_special_literals = 0;
}
else {
- special_literals = Qfalse;
+ if (rb_hash_lookup(literals, lit) != Qnil) {
+ rb_compile_warning(RSTRING_PTR(iseq->filename), nd_line(val), "duplicated when clause is ignored");
+ }
+ else {
+ rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
+ }
}
if (nd_type(val) == NODE_STR) {
@@ -2462,7 +2456,7 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE s
ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
vals = vals->nd_next;
}
- return special_literals;
+ return only_special_literals;
}
static int
@@ -3152,11 +3146,15 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
DECL_ANCHOR(head);
DECL_ANCHOR(body_seq);
DECL_ANCHOR(cond_seq);
- VALUE special_literals = rb_ary_tmp_new(1);
+ int only_special_literals = 1;
+ VALUE literals = rb_hash_new();
INIT_ANCHOR(head);
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);
+
+ RHASH_TBL(literals)->type = &cdhash_type;
+
if (node->nd_head == 0) {
COMPILE_(ret, "when", node->nd_body, poped);
break;
@@ -3188,12 +3186,12 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
if (vals) {
switch (nd_type(vals)) {
case NODE_ARRAY:
- special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals);
+ only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
break;
case NODE_SPLAT:
case NODE_ARGSCAT:
case NODE_ARGSPUSH:
- special_literals = 0;
+ only_special_literals = 0;
COMPILE(cond_seq, "when/cond splat", vals);
ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue);
ADD_INSNL(cond_seq, nd_line(vals), branchif, l1);
@@ -3230,11 +3228,11 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel);
}
- if (special_literals) {
+ if (only_special_literals) {
+ iseq_add_mark_object(iseq, literals);
+
ADD_INSN(ret, nd_line(tempnode), dup);
- ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch,
- special_literals, elselabel);
- iseq_add_mark_object_compile_time(iseq, special_literals);
+ ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, literals, elselabel);
}
ADD_SEQ(ret, cond_seq);
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index af795440c5..fd5b14d6c3 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -128,6 +128,29 @@ class TestSyntax < Test::Unit::TestCase
assert_not_label(:foo, 'class Foo < not_label:foo; end', bug6347)
end
+ def test_duplicated_when
+ w = 'warning: duplicated when clause is ignored'
+ assert_warn(/3: #{w}.+4: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
+ eval %q{
+ case 1
+ when 1, 1
+ when 1, 1
+ when 1, 1
+ end
+ }
+ }
+ assert_warn(/#{w}/){#/3: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
+ a = 1
+ eval %q{
+ case 1
+ when 1, 1
+ when 1, a
+ when 1, 1
+ end
+ }
+ }
+ end
+
private
def not_label(x) @result = x; @not_label ||= nil end