From: Ian Lance Taylor Date: Wed, 27 Feb 2019 04:56:12 +0000 (+0000) Subject: compiler: check duplicate numeric keys in map literals X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9e0ed736065afad7da7850f508f316f2954d8960;p=gcc.git compiler: check duplicate numeric keys in map literals Updates golang/go#28104 Reviewed-on: https://go-review.googlesource.com/c/162882 From-SVN: r269242 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index bb8a931451e..5b49264d0d9 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 1576613c423..b1f503abffb 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -14454,6 +14454,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, { Location location = this->location(); Unordered_map(unsigned int, std::vector) st; + Unordered_map(unsigned int, std::vector) nt; if (this->vals_ != NULL) { if (!this->has_keys_) @@ -14488,8 +14489,8 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, 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(Gogo* gogo, Named_object* function, 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)::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 l; + l.push_back(*p); + std::pair > val(h, l); + nt.insert(val); + } + else + { + // Do further check since h already exists. + for (std::vector::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 Numeric_constant& a) 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 loc) const 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(e + static_cast(f)); + break; + default: + go_unreachable(); + } + + return (static_cast(val) + seed) * PRIME; +} + diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 86d950bc880..5d61b69c0fa 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -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();