Commit 9e0ed736 by Ian Lance Taylor

compiler: check duplicate numeric keys in map literals

    
    Updates golang/go#28104
    
    Reviewed-on: https://go-review.googlesource.com/c/162882

From-SVN: r269242
parent 6054700c
2c74b84184941ebea318f69fe43a81f657790b63 bc036b3a03e089e78b892067e40dbb0e7ecca9e2
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -14454,6 +14454,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, ...@@ -14454,6 +14454,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
{ {
Location location = this->location(); Location location = this->location();
Unordered_map(unsigned int, std::vector<Expression*>) st; Unordered_map(unsigned int, std::vector<Expression*>) st;
Unordered_map(unsigned int, std::vector<Expression*>) nt;
if (this->vals_ != NULL) if (this->vals_ != NULL)
{ {
if (!this->has_keys_) if (!this->has_keys_)
...@@ -14488,8 +14489,8 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, ...@@ -14488,8 +14489,8 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
if (!(*p)->is_constant()) if (!(*p)->is_constant())
continue; continue;
std::string sval; std::string sval;
// Check if there are duplicate constant string keys. Numeric_constant nval;
if ((*p)->string_constant_value(&sval)) if ((*p)->string_constant_value(&sval)) // Check string keys.
{ {
unsigned int h = Gogo::hash_string(sval, 0); unsigned int h = Gogo::hash_string(sval, 0);
// Search the index h in the hash map. // Search the index h in the hash map.
...@@ -14526,6 +14527,42 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, ...@@ -14526,6 +14527,42 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
mit->second.push_back(*p); 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 Numeric_constant& a) ...@@ -16472,6 +16509,36 @@ Numeric_constant::operator=(const Numeric_constant& a)
return *this; 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. // Clear the contents.
void void
...@@ -17198,3 +17265,40 @@ Numeric_constant::expression(Location loc) const ...@@ -17198,3 +17265,40 @@ Numeric_constant::expression(Location loc) const
go_unreachable(); 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;
}
...@@ -4163,6 +4163,10 @@ class Numeric_constant ...@@ -4163,6 +4163,10 @@ class Numeric_constant
Numeric_constant& operator=(const 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. // Set to an unsigned long value.
void void
set_unsigned_long(Type*, unsigned long); set_unsigned_long(Type*, unsigned long);
...@@ -4282,6 +4286,10 @@ class Numeric_constant ...@@ -4282,6 +4286,10 @@ class Numeric_constant
Expression* Expression*
expression(Location) const; expression(Location) const;
// Calculate a hash code with a given seed.
unsigned int
hash(unsigned int seed) const;
private: private:
void void
clear(); clear();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment