This Go frontend patch by Ben Shi checks for duplicate numeric keys in
map literals.  This is for https://golang.org/issue/28104.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 269241)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-2c74b84184941ebea318f69fe43a81f657790b63
+bc036b3a03e089e78b892067e40dbb0e7ecca9e2
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 269196)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -14454,6 +14454,7 @@ Composite_literal_expression::lower_map(
 {
   Location location = this->location();
   Unordered_map(unsigned int, std::vector<Expression*>) st;
+  Unordered_map(unsigned int, std::vector<Expression*>) nt;
   if (this->vals_ != NULL)
     {
       if (!this->has_keys_)
@@ -14488,8 +14489,8 @@ Composite_literal_expression::lower_map(
          if (!(*p)->is_constant())
            continue;
          std::string sval;
-         // Check if there are duplicate constant string keys.
-         if ((*p)->string_constant_value(&sval))
+         Numeric_constant nval;
+         if ((*p)->string_constant_value(&sval)) // Check string keys.
            {
              unsigned int h = Gogo::hash_string(sval, 0);
              // Search the index h in the hash map.
@@ -14526,6 +14527,42 @@ Composite_literal_expression::lower_map(
                  mit->second.push_back(*p);
                }
            }
+         else if ((*p)->numeric_constant_value(&nval)) // Check numeric keys.
+           {
+             unsigned int h = nval.hash(0);
+             Unordered_map(unsigned int, std::vector<Expression*>)::iterator 
mit;
+             mit = nt.find(h);
+             if (mit == nt.end())
+               {
+                 // No duplicate since h is a new code.
+                 // Create a new vector indexed by h and add it to the hash 
map.
+                 std::vector<Expression*> l;
+                 l.push_back(*p);
+                 std::pair<unsigned int, std::vector<Expression*> > val(h, l);
+                 nt.insert(val);
+               }
+             else
+               {
+                 // Do further check since h already exists.
+                 for (std::vector<Expression*>::iterator lit =
+                          mit->second.begin();
+                      lit != mit->second.end();
+                      lit++)
+                   {
+                     Numeric_constant rval;
+                     bool ok = (*lit)->numeric_constant_value(&rval);
+                     go_assert(ok);
+                     if (nval.equals(rval))
+                       {
+                         go_error_at((*p)->location(),
+                                     "duplicate key in map literal");
+                         return Expression::make_error(location);
+                       }
+                   }
+                 // Add this new numeric key to the vector indexed by h.
+                 mit->second.push_back(*p);
+               }
+           }
        }
     }
 
@@ -16472,6 +16509,36 @@ Numeric_constant::operator=(const Numeri
   return *this;
 }
 
+// Check equality with another numeric constant.
+
+bool
+Numeric_constant::equals(const Numeric_constant& a) const
+{
+  if (this->classification_ != a.classification_)
+    return false;
+
+  if (this->type_ != NULL && a.type_ != NULL
+      && !Type::are_identical(this->type_, a.type_,
+                             Type::COMPARE_ALIASES, NULL))
+    return false;
+
+  switch (a.classification_)
+    {
+    case NC_INVALID:
+      break;
+    case NC_INT:
+    case NC_RUNE:
+      return mpz_cmp(this->u_.int_val, a.u_.int_val) == 0;
+    case NC_FLOAT:
+      return mpfr_cmp(this->u_.float_val, a.u_.float_val) == 0;
+    case NC_COMPLEX:
+      return mpc_cmp(this->u_.complex_val, a.u_.complex_val) == 0;
+    default:
+      go_unreachable();
+    }
+  return false;
+}
+
 // Clear the contents.
 
 void
@@ -17198,3 +17265,40 @@ Numeric_constant::expression(Location lo
       go_unreachable();
     }
 }
+
+// Calculate a hash code with a given seed.
+
+unsigned int
+Numeric_constant::hash(unsigned int seed) const
+{
+  unsigned long val;
+  const unsigned int PRIME = 97;
+  long e = 0;
+  double f = 1.0;
+  mpfr_t m;
+
+  switch (this->classification_)
+    {
+    case NC_INVALID:
+      return PRIME;
+    case NC_INT:
+    case NC_RUNE:
+      val = mpz_get_ui(this->u_.int_val);
+      break;
+    case NC_COMPLEX:
+      mpfr_init(m);
+      mpc_abs(m, this->u_.complex_val, MPFR_RNDN);
+      val = mpfr_get_ui(m, MPFR_RNDN);
+      mpfr_clear(m);
+      break;
+    case NC_FLOAT:
+      f = mpfr_get_d_2exp(&e, this->u_.float_val, MPFR_RNDN) * 4294967295.0;
+      val = static_cast<unsigned long>(e + static_cast<long>(f));
+      break;
+    default:
+      go_unreachable();
+    }
+
+  return (static_cast<unsigned int>(val) + seed) * PRIME;
+}
+
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h     (revision 269196)
+++ gcc/go/gofrontend/expressions.h     (working copy)
@@ -4163,6 +4163,10 @@ class Numeric_constant
 
   Numeric_constant& operator=(const Numeric_constant&);
 
+  // Check equality with another numeric constant.
+  bool
+  equals(const Numeric_constant&) const;
+
   // Set to an unsigned long value.
   void
   set_unsigned_long(Type*, unsigned long);
@@ -4282,6 +4286,10 @@ class Numeric_constant
   Expression*
   expression(Location) const;
 
+  // Calculate a hash code with a given seed.
+  unsigned int
+  hash(unsigned int seed) const;
+
  private:
   void
   clear();

Reply via email to