From bc2a1f2a98b04f040ea485cedd3283f2f3906e4c Mon Sep 17 00:00:00 2001 From: nobu Date: Sat, 3 Sep 2011 15:11:53 +0000 Subject: [PATCH] * variable.c (rb_const_set): show the previous definition location. [EXPERIMENTAL] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33175 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++++ constant.h | 2 ++ gc.c | 1 + internal.h | 1 + test/ruby/test_const.rb | 9 +++++++++ variable.c | 9 ++++++++- vm.c | 14 ++++++++++++++ 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a8601c2dfe..5254017d50 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Sun Sep 4 00:11:49 2011 Nobuyoshi Nakada + + * variable.c (rb_const_set): show the previous definition + location. [EXPERIMENTAL] + Sat Sep 3 23:56:24 2011 Nobuyoshi Nakada * configure.in (sizeof_struct_dirent_too_small): check if struct diff --git a/constant.h b/constant.h index 8232910737..9354241961 100644 --- a/constant.h +++ b/constant.h @@ -19,6 +19,8 @@ typedef enum { typedef struct rb_const_entry_struct { rb_const_flag_t flag; VALUE value; /* should be mark */ + VALUE file; + int line; } rb_const_entry_t; VALUE rb_mod_private_constant(int argc, VALUE *argv, VALUE obj); diff --git a/gc.c b/gc.c index 3fc465b482..e6784624a4 100644 --- a/gc.c +++ b/gc.c @@ -1569,6 +1569,7 @@ mark_const_entry_i(ID key, const rb_const_entry_t *ce, st_data_t data) { struct mark_tbl_arg *arg = (void*)data; gc_mark(arg->objspace, ce->value, arg->lev); + gc_mark(arg->objspace, ce->file, arg->lev); return ST_CONTINUE; } diff --git a/internal.h b/internal.h index 576ec32699..c7c921fe05 100644 --- a/internal.h +++ b/internal.h @@ -195,6 +195,7 @@ void rb_vm_change_state(void); void rb_vm_inc_const_missing_count(void); void rb_thread_mark(void *th); const void **rb_vm_get_insns_address_table(void); +VALUE rb_sourcefilename(void); /* vm_dump.c */ void rb_vm_bugreport(void); diff --git a/test/ruby/test_const.rb b/test/ruby/test_const.rb index 3708a5a0ca..31adb2a0ce 100644 --- a/test/ruby/test_const.rb +++ b/test/ruby/test_const.rb @@ -45,4 +45,13 @@ class TestConst < Test::Unit::TestCase assert defined?(TEST4) assert_equal 8, TEST4 end + + def test_redefinition + c = Class.new + c.const_set(:X, 1) + assert_output(nil, <<-WARNING) {c.const_set(:X, 2)} +#{__FILE__}:#{__LINE__-1}: warning: already initialized constant X +#{__FILE__}:#{__LINE__-3}: warning: previous definition of X was here +WARNING + end end diff --git a/variable.c b/variable.c index 9526b6226f..3909b799c4 100644 --- a/variable.c +++ b/variable.c @@ -2057,8 +2057,13 @@ rb_const_set(VALUE klass, ID id, VALUE val) autoload_delete(klass, id); } else { + const char *name = rb_id2name(id); visibility = ce->flag; - rb_warn("already initialized constant %s", rb_id2name(id)); + rb_warn("already initialized constant %s", name); + if (!NIL_P(ce->file) && ce->line) { + rb_compile_warn(RSTRING_PTR(ce->file), ce->line, + "previous definition of %s was here", name); + } } } } @@ -2068,6 +2073,8 @@ rb_const_set(VALUE klass, ID id, VALUE val) ce = ALLOC(rb_const_entry_t); ce->flag = (rb_const_flag_t)visibility; ce->value = val; + ce->file = rb_sourcefilename(); + ce->line = rb_sourceline(); st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce); } diff --git a/vm.c b/vm.c index 80b0857de5..d57f62b516 100644 --- a/vm.c +++ b/vm.c @@ -829,6 +829,20 @@ vm_backtrace(rb_thread_t *th, int lev) return rb_ary_reverse(ary); } +VALUE +rb_sourcefilename(void) +{ + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); + + if (cfp) { + return cfp->iseq->filename; + } + else { + return Qnil; + } +} + const char * rb_sourcefile(void) {