compiler: check duplicate numeric keys in map literals
Updates golang/go#28104 Reviewed-on: https://go-review.googlesource.com/c/162882 From-SVN: r269242
This commit is contained in:
parent
6054700c46
commit
9e0ed73606
@ -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.
|
||||
|
@ -14454,6 +14454,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
|
||||
{
|
||||
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(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<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)
|
||||
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<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
|
||||
|
||||
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();
|
||||
|
Loading…
Reference in New Issue
Block a user