aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/go/gofrontend/expressions.cc52
-rw-r--r--gcc/go/gofrontend/gogo.cc3
2 files changed, 51 insertions, 4 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 8187e6d..553e6d6 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -2292,7 +2292,7 @@ class Const_expression : public Expression
public:
Const_expression(Named_object* constant, source_location location)
: Expression(EXPRESSION_CONST_REFERENCE, location),
- constant_(constant), type_(NULL)
+ constant_(constant), type_(NULL), seen_(false)
{ }
const std::string&
@@ -2350,6 +2350,9 @@ class Const_expression : public Expression
// The type of this reference. This is used if the constant has an
// abstract type.
Type* type_;
+ // Used to prevent infinite recursion when a constant incorrectly
+ // refers to itself.
+ mutable bool seen_;
};
// Lower a constant expression. This is where we convert the
@@ -2387,6 +2390,9 @@ bool
Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
Type** ptype) const
{
+ if (this->seen_)
+ return false;
+
Type* ctype;
if (this->type_ != NULL)
ctype = this->type_;
@@ -2396,9 +2402,14 @@ Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
return false;
Expression* e = this->constant_->const_value()->expr();
+
+ this->seen_ = true;
+
Type* t;
bool r = e->integer_constant_value(iota_is_constant, val, &t);
+ this->seen_ = false;
+
if (r
&& ctype != NULL
&& !Integer_expression::check_constant(val, ctype, this->location()))
@@ -2413,6 +2424,9 @@ Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
bool
Const_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
{
+ if (this->seen_)
+ return false;
+
Type* ctype;
if (this->type_ != NULL)
ctype = this->type_;
@@ -2421,9 +2435,14 @@ Const_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
if (ctype != NULL && ctype->float_type() == NULL)
return false;
+ this->seen_ = true;
+
Type* t;
bool r = this->constant_->const_value()->expr()->float_constant_value(val,
&t);
+
+ this->seen_ = false;
+
if (r && ctype != NULL)
{
if (!Float_expression::check_constant(val, ctype, this->location()))
@@ -2440,6 +2459,9 @@ bool
Const_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
Type **ptype) const
{
+ if (this->seen_)
+ return false;
+
Type* ctype;
if (this->type_ != NULL)
ctype = this->type_;
@@ -2448,10 +2470,15 @@ Const_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
if (ctype != NULL && ctype->complex_type() == NULL)
return false;
+ this->seen_ = true;
+
Type *t;
bool r = this->constant_->const_value()->expr()->complex_constant_value(real,
imag,
&t);
+
+ this->seen_ = false;
+
if (r && ctype != NULL)
{
if (!Complex_expression::check_constant(real, imag, ctype,
@@ -2470,13 +2497,32 @@ Const_expression::do_type()
{
if (this->type_ != NULL)
return this->type_;
+
+ if (this->seen_)
+ {
+ this->report_error(_("constant refers to itself"));
+ this->type_ = Type::make_error_type();
+ return this->type_;
+ }
+
+ this->seen_ = true;
+
Named_constant* nc = this->constant_->const_value();
Type* ret = nc->type();
+
if (ret != NULL)
- return ret;
+ {
+ this->seen_ = false;
+ return ret;
+ }
+
// During parsing, a named constant may have a NULL type, but we
// must not return a NULL type here.
- return nc->expr()->type();
+ ret = nc->expr()->type();
+
+ this->seen_ = false;
+
+ return ret;
}
// Set the type of the const reference.
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index b278711..2946299 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1472,7 +1472,8 @@ Check_types_traverse::constant(Named_object* named_object, bool)
&& !ctype->is_boolean_type()
&& !ctype->is_string_type())
{
- error_at(constant->location(), "invalid constant type");
+ if (!ctype->is_error_type())
+ error_at(constant->location(), "invalid constant type");
constant->set_error();
}
else if (!constant->expr()->is_constant())