aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2010-12-18 03:03:16 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2010-12-18 03:03:16 +0000
commit6e25f095d8731f6da3643da168705f3b9e8e2d2c (patch)
tree84e7d40b307dd4390c585f793d9c7ef16e93f5ab /gcc
parent748414642faf35f955a8bfa38d9febd3ef88fdb0 (diff)
downloadgcc-6e25f095d8731f6da3643da168705f3b9e8e2d2c.zip
gcc-6e25f095d8731f6da3643da168705f3b9e8e2d2c.tar.gz
gcc-6e25f095d8731f6da3643da168705f3b9e8e2d2c.tar.bz2
Don't crash on recursive variables and typed consts.
From-SVN: r168012
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/expressions.cc69
-rw-r--r--gcc/go/gofrontend/gogo.cc51
-rw-r--r--gcc/go/gofrontend/gogo.h5
3 files changed, 117 insertions, 8 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index cb5c45c..39baf9d 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -2285,6 +2285,32 @@ Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type,
return new Complex_expression(real, imag, type, location);
}
+// Find a named object in an expression.
+
+class Find_named_object : public Traverse
+{
+ public:
+ Find_named_object(Named_object* no)
+ : Traverse(traverse_expressions),
+ no_(no), found_(false)
+ { }
+
+ // Whether we found the object.
+ bool
+ found() const
+ { return this->found_; }
+
+ protected:
+ int
+ expression(Expression**);
+
+ private:
+ // The object we are looking for.
+ Named_object* no_;
+ // Whether we found it.
+ bool found_;
+};
+
// A reference to a const in an expression.
class Const_expression : public Expression
@@ -2295,6 +2321,10 @@ class Const_expression : public Expression
constant_(constant), type_(NULL), seen_(false)
{ }
+ Named_object*
+ named_object()
+ { return this->constant_; }
+
const std::string&
name() const
{ return this->constant_->name(); }
@@ -2565,6 +2595,19 @@ Const_expression::do_determine_type(const Type_context* context)
void
Const_expression::do_check_types(Gogo*)
{
+ if (this->type_ != NULL && this->type_->is_error_type())
+ return;
+
+ Expression* init = this->constant_->const_value()->expr();
+ Find_named_object find_named_object(this->constant_);
+ Expression::traverse(&init, &find_named_object);
+ if (find_named_object.found())
+ {
+ this->report_error(_("constant refers to itself"));
+ this->type_ = Type::make_error_type();
+ return;
+ }
+
if (this->type_ == NULL || this->type_->is_abstract())
return;
@@ -2682,6 +2725,32 @@ Expression::make_const_reference(Named_object* constant,
return new Const_expression(constant, location);
}
+// Find a named object in an expression.
+
+int
+Find_named_object::expression(Expression** pexpr)
+{
+ switch ((*pexpr)->classification())
+ {
+ case Expression::EXPRESSION_CONST_REFERENCE:
+ if (static_cast<Const_expression*>(*pexpr)->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ case Expression::EXPRESSION_VAR_REFERENCE:
+ if ((*pexpr)->var_expression()->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ case Expression::EXPRESSION_FUNC_REFERENCE:
+ if ((*pexpr)->func_expression()->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ default:
+ return TRAVERSE_CONTINUE;
+ }
+ this->found_ = true;
+ return TRAVERSE_EXIT;
+}
+
// The nil value.
class Nil_expression : public Expression
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 2946299..d8d704d 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -3056,7 +3056,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
: type_(type), init_(init), preinit_(NULL), location_(location),
is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false),
- is_address_taken_(false), init_is_lowered_(false),
+ is_address_taken_(false), seen_(false), init_is_lowered_(false),
type_from_init_tuple_(false), type_from_range_index_(false),
type_from_range_value_(false), type_from_chan_element_(false),
is_type_switch_var_(false)
@@ -3090,7 +3090,18 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
{
if (this->init_ != NULL && !this->init_is_lowered_)
{
+ if (this->seen_)
+ {
+ // We will give an error elsewhere, this is just to prevent
+ // an infinite loop.
+ return;
+ }
+ this->seen_ = true;
+
gogo->lower_expression(function, &this->init_);
+
+ this->seen_ = false;
+
this->init_is_lowered_ = true;
}
}
@@ -3209,7 +3220,7 @@ Variable::type_from_chan_element(Expression* expr, bool report_error) const
// with type determination, then this should be unnecessary.
Type*
-Variable::type() const
+Variable::type()
{
// A variable in a type switch with a nil case will have the wrong
// type here. This gets fixed up in determine_type, below.
@@ -3224,14 +3235,26 @@ Variable::type() const
type = NULL;
}
+ if (this->seen_)
+ {
+ if (this->type_ == NULL || !this->type_->is_error_type())
+ {
+ error_at(this->location_, "variable initializer refers to itself");
+ this->type_ = Type::make_error_type();
+ }
+ return this->type_;
+ }
+
+ this->seen_ = true;
+
if (type != NULL)
- return type;
+ ;
else if (this->type_from_init_tuple_)
- return this->type_from_tuple(init, false);
+ type = this->type_from_tuple(init, false);
else if (this->type_from_range_index_ || this->type_from_range_value_)
- return this->type_from_range(init, this->type_from_range_index_, false);
+ type = this->type_from_range(init, this->type_from_range_index_, false);
else if (this->type_from_chan_element_)
- return this->type_from_chan_element(init, false);
+ type = this->type_from_chan_element(init, false);
else
{
gcc_assert(init != NULL);
@@ -3244,9 +3267,21 @@ Variable::type() const
if (type->is_void_type())
type = Type::make_error_type();
-
- return type;
}
+
+ this->seen_ = false;
+
+ return type;
+}
+
+// Fetch the type from a const pointer, in which case it should have
+// been set already.
+
+Type*
+Variable::type() const
+{
+ gcc_assert(this->type_ != NULL);
+ return this->type_;
}
// Set the type if necessary.
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 49f1be5..552a643 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -1039,6 +1039,9 @@ class Variable
// Get the type of the variable.
Type*
+ type();
+
+ Type*
type() const;
// Return whether the type is defined yet.
@@ -1258,6 +1261,8 @@ class Variable
bool is_varargs_parameter_ : 1;
// Whether something takes the address of this variable.
bool is_address_taken_ : 1;
+ // True if we have seen this variable in a traversal.
+ bool seen_ : 1;
// True if we have lowered the initialization expression.
bool init_is_lowered_ : 1;
// True if init is a tuple used to set the type.