Commit 6e25f095 by Ian Lance Taylor

Don't crash on recursive variables and typed consts.

From-SVN: r168012
parent 74841464
...@@ -2285,6 +2285,32 @@ Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type, ...@@ -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); 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. // A reference to a const in an expression.
class Const_expression : public Expression class Const_expression : public Expression
...@@ -2295,6 +2321,10 @@ class Const_expression : public Expression ...@@ -2295,6 +2321,10 @@ class Const_expression : public Expression
constant_(constant), type_(NULL), seen_(false) constant_(constant), type_(NULL), seen_(false)
{ } { }
Named_object*
named_object()
{ return this->constant_; }
const std::string& const std::string&
name() const name() const
{ return this->constant_->name(); } { return this->constant_->name(); }
...@@ -2565,6 +2595,19 @@ Const_expression::do_determine_type(const Type_context* context) ...@@ -2565,6 +2595,19 @@ Const_expression::do_determine_type(const Type_context* context)
void void
Const_expression::do_check_types(Gogo*) 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()) if (this->type_ == NULL || this->type_->is_abstract())
return; return;
...@@ -2682,6 +2725,32 @@ Expression::make_const_reference(Named_object* constant, ...@@ -2682,6 +2725,32 @@ Expression::make_const_reference(Named_object* constant,
return new Const_expression(constant, location); 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. // The nil value.
class Nil_expression : public Expression class Nil_expression : public Expression
......
...@@ -3056,7 +3056,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global, ...@@ -3056,7 +3056,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
: type_(type), init_(init), preinit_(NULL), location_(location), : type_(type), init_(init), preinit_(NULL), location_(location),
is_global_(is_global), is_parameter_(is_parameter), is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false), 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_init_tuple_(false), type_from_range_index_(false),
type_from_range_value_(false), type_from_chan_element_(false), type_from_range_value_(false), type_from_chan_element_(false),
is_type_switch_var_(false) is_type_switch_var_(false)
...@@ -3090,7 +3090,18 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function) ...@@ -3090,7 +3090,18 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
{ {
if (this->init_ != NULL && !this->init_is_lowered_) 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_); gogo->lower_expression(function, &this->init_);
this->seen_ = false;
this->init_is_lowered_ = true; this->init_is_lowered_ = true;
} }
} }
...@@ -3209,7 +3220,7 @@ Variable::type_from_chan_element(Expression* expr, bool report_error) const ...@@ -3209,7 +3220,7 @@ Variable::type_from_chan_element(Expression* expr, bool report_error) const
// with type determination, then this should be unnecessary. // with type determination, then this should be unnecessary.
Type* Type*
Variable::type() const Variable::type()
{ {
// A variable in a type switch with a nil case will have the wrong // A variable in a type switch with a nil case will have the wrong
// type here. This gets fixed up in determine_type, below. // type here. This gets fixed up in determine_type, below.
...@@ -3224,14 +3235,26 @@ Variable::type() const ...@@ -3224,14 +3235,26 @@ Variable::type() const
type = NULL; 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) if (type != NULL)
return type; ;
else if (this->type_from_init_tuple_) 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_) 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_) else if (this->type_from_chan_element_)
return this->type_from_chan_element(init, false); type = this->type_from_chan_element(init, false);
else else
{ {
gcc_assert(init != NULL); gcc_assert(init != NULL);
...@@ -3244,9 +3267,21 @@ Variable::type() const ...@@ -3244,9 +3267,21 @@ Variable::type() const
if (type->is_void_type()) if (type->is_void_type())
type = Type::make_error_type(); type = Type::make_error_type();
}
this->seen_ = false;
return type; 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. // Set the type if necessary.
......
...@@ -1039,6 +1039,9 @@ class Variable ...@@ -1039,6 +1039,9 @@ class Variable
// Get the type of the variable. // Get the type of the variable.
Type* Type*
type();
Type*
type() const; type() const;
// Return whether the type is defined yet. // Return whether the type is defined yet.
...@@ -1258,6 +1261,8 @@ class Variable ...@@ -1258,6 +1261,8 @@ class Variable
bool is_varargs_parameter_ : 1; bool is_varargs_parameter_ : 1;
// Whether something takes the address of this variable. // Whether something takes the address of this variable.
bool is_address_taken_ : 1; 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. // True if we have lowered the initialization expression.
bool init_is_lowered_ : 1; bool init_is_lowered_ : 1;
// True if init is a tuple used to set the type. // True if init is a tuple used to set the type.
......
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