summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2021-06-03 12:32:44 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2021-06-03 15:11:18 +0900
commit37eb5e74395f148782f7d67b5218fb2e66b113d7 (patch)
treef92f0414ab29ff9ff6b6dca6a13b600574d165b0
parenta023db49bfbbbe119638bae6abf8113f0de371de (diff)
Warn more duplicate literal hash keys
Following non-special_const literals: * T_BIGNUM * T_FLOAT (non-flonum) * T_RATIONAL * T_COMPLEX
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4548
-rw-r--r--compile.c16
-rw-r--r--internal/compile.h2
-rw-r--r--parse.y34
-rw-r--r--test/ruby/test_literal.rb4
4 files changed, 47 insertions, 9 deletions
diff --git a/compile.c b/compile.c
index aedc9c55b57..1b23d2133b7 100644
--- a/compile.c
+++ b/compile.c
@@ -1967,8 +1967,8 @@ iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl)
return COMPILE_OK;
}
-static int
-cdhash_cmp(VALUE val, VALUE lit)
+int
+rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
{
int tval, tlit;
@@ -2004,20 +2004,20 @@ cdhash_cmp(VALUE val, VALUE lit)
else if (tlit == T_RATIONAL) {
const struct RRational *rat1 = RRATIONAL(val);
const struct RRational *rat2 = RRATIONAL(lit);
- return cdhash_cmp(rat1->num, rat2->num) || cdhash_cmp(rat1->den, rat2->den);
+ return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
}
else if (tlit == T_COMPLEX) {
const struct RComplex *comp1 = RCOMPLEX(val);
const struct RComplex *comp2 = RCOMPLEX(lit);
- return cdhash_cmp(comp1->real, comp2->real) || cdhash_cmp(comp1->imag, comp2->imag);
+ return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
}
else {
UNREACHABLE_RETURN(-1);
}
}
-static st_index_t
-cdhash_hash(VALUE a)
+st_index_t
+rb_iseq_cdhash_hash(VALUE a)
{
switch (OBJ_BUILTIN_TYPE(a)) {
case -1:
@@ -2039,8 +2039,8 @@ cdhash_hash(VALUE a)
}
static const struct st_hash_type cdhash_type = {
- cdhash_cmp,
- cdhash_hash,
+ rb_iseq_cdhash_cmp,
+ rb_iseq_cdhash_hash,
};
struct cdhash_set_label_struct {
diff --git a/internal/compile.h b/internal/compile.h
index c1f2a366855..99c15d6a44b 100644
--- a/internal/compile.h
+++ b/internal/compile.h
@@ -20,6 +20,8 @@ int rb_dvar_defined(ID, const struct rb_iseq_struct *);
int rb_local_defined(ID, const struct rb_iseq_struct *);
const char *rb_insns_name(int i);
VALUE rb_insns_name_array(void);
+int rb_iseq_cdhash_cmp(VALUE val, VALUE lit);
+st_index_t rb_iseq_cdhash_hash(VALUE a);
/* iseq.c */
int rb_vm_insn_addr2insn(const void *);
diff --git a/parse.y b/parse.y
index e669adbcd5d..0b69bc1d7e3 100644
--- a/parse.y
+++ b/parse.y
@@ -12184,10 +12184,42 @@ append_literal_keys(st_data_t k, st_data_t v, st_data_t h)
return ST_CONTINUE;
}
+static bool
+hash_literal_key_p(VALUE k)
+{
+ switch (OBJ_BUILTIN_TYPE(k)) {
+ case T_NODE:
+ case T_REGEXP:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static int
+literal_cmp(VALUE val, VALUE lit)
+{
+ if (val == lit) return 0;
+ if (!hash_literal_key_p(val) || !hash_literal_key_p(lit)) return -1;
+ return rb_iseq_cdhash_cmp(val, lit);
+}
+
+static st_index_t
+literal_hash(VALUE a)
+{
+ if (!hash_literal_key_p(a)) return (st_index_t)a;
+ return rb_iseq_cdhash_hash(a);
+}
+
+static const struct st_hash_type literal_type = {
+ literal_cmp,
+ literal_hash,
+};
+
static NODE *
remove_duplicate_keys(struct parser_params *p, NODE *hash)
{
- st_table *literal_keys = st_init_numtable_with_size(hash->nd_alen / 2);
+ st_table *literal_keys = st_init_table_with_size(&literal_type, hash->nd_alen / 2);
NODE *result = 0;
rb_code_location_t loc = hash->nd_loc;
while (hash && hash->nd_head && hash->nd_next) {
diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb
index 10cb09b8334..ed93b74cfff 100644
--- a/test/ruby/test_literal.rb
+++ b/test/ruby/test_literal.rb
@@ -480,6 +480,10 @@ class TestRubyLiteral < Test::Unit::TestCase
'"a"',
'1000',
'1.0',
+ '1_000_000_000_000_000_000_000',
+ '1.0r',
+ '1.0i',
+ '1.72723e-77',
) do |key|
assert_warning(/key #{Regexp.quote(eval(key).inspect)} is duplicated/) do
eval("{#{key} => :bar, #{key} => :foo}")