aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-02-27 04:56:12 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-02-27 04:56:12 +0000
commit9e0ed736065afad7da7850f508f316f2954d8960 (patch)
tree31b9e77c3af31dec1d03b664af976ab677649342 /gcc
parent6054700c46cfee76846678750972993d8447374c (diff)
downloadgcc-9e0ed736065afad7da7850f508f316f2954d8960.zip
gcc-9e0ed736065afad7da7850f508f316f2954d8960.tar.gz
gcc-9e0ed736065afad7da7850f508f316f2954d8960.tar.bz2
compiler: check duplicate numeric keys in map literals
Updates golang/go#28104 Reviewed-on: https://go-review.googlesource.com/c/162882 From-SVN: r269242
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc108
-rw-r--r--gcc/go/gofrontend/expressions.h8
3 files changed, 115 insertions, 3 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index bb8a931..5b49264 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 1576613..b1f503a 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<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;
+}
+
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 86d950b..5d61b69 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();