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

ruby-changes:66418

From: Nobuyoshi <ko1@a...>
Date: Thu, 3 Jun 2021 15:11:37 +0900 (JST)
Subject: [ruby-changes:66418] 37eb5e7439 (master): Warn more duplicate literal hash keys

https://git.ruby-lang.org/ruby.git/commit/?id=37eb5e7439

From 37eb5e74395f148782f7d67b5218fb2e66b113d7 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Thu, 3 Jun 2021 12:32:44 +0900
Subject: Warn more duplicate literal hash keys

Following non-special_const literals:
* T_BIGNUM
* T_FLOAT (non-flonum)
* T_RATIONAL
* T_COMPLEX
---
 compile.c                 | 16 ++++++++--------
 internal/compile.h        |  2 ++
 parse.y                   | 34 +++++++++++++++++++++++++++++++++-
 test/ruby/test_literal.rb |  4 ++++
 4 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/compile.c b/compile.c
index aedc9c5..1b23d21 100644
--- a/compile.c
+++ b/compile.c
@@ -1967,8 +1967,8 @@ iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl) https://github.com/ruby/ruby/blob/trunk/compile.c#L1967
     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) https://github.com/ruby/ruby/blob/trunk/compile.c#L2004
     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) https://github.com/ruby/ruby/blob/trunk/compile.c#L2039
 }
 
 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 c1f2a36..99c15d6 100644
--- a/internal/compile.h
+++ b/internal/compile.h
@@ -20,6 +20,8 @@ int rb_dvar_defined(ID, const struct rb_iseq_struct *); https://github.com/ruby/ruby/blob/trunk/internal/compile.h#L20
 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 e669adb..0b69bc1 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) https://github.com/ruby/ruby/blob/trunk/parse.y#L12184
     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 10cb09b..ed93b74 100644
--- a/test/ruby/test_literal.rb
+++ b/test/ruby/test_literal.rb
@@ -480,6 +480,10 @@ class TestRubyLiteral < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_literal.rb#L480
       '"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}")
-- 
cgit v1.1


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

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