summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--constant.h2
-rw-r--r--gc.c1
-rw-r--r--internal.h1
-rw-r--r--test/ruby/test_const.rb9
-rw-r--r--variable.c9
-rw-r--r--vm.c14
7 files changed, 40 insertions, 1 deletions
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 <nobu@ruby-lang.org>
+
+ * variable.c (rb_const_set): show the previous definition
+ location. [EXPERIMENTAL]
+
Sat Sep 3 23:56:24 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
* 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)
{