Commit ab9d6dcf by Ian Lance Taylor

Avoid endless loop on array with recursive length.

From-SVN: r168223
parent 3746f0c7
...@@ -6463,6 +6463,9 @@ class Builtin_call_expression : public Call_expression ...@@ -6463,6 +6463,9 @@ class Builtin_call_expression : public Call_expression
Gogo* gogo_; Gogo* gogo_;
// The builtin function being called. // The builtin function being called.
Builtin_function_code code_; Builtin_function_code code_;
// Used to stop endless loops when the length of an array uses len
// or cap of the array itself.
mutable bool seen_;
}; };
Builtin_call_expression::Builtin_call_expression(Gogo* gogo, Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
...@@ -6471,7 +6474,7 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo, ...@@ -6471,7 +6474,7 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
bool is_varargs, bool is_varargs,
source_location location) source_location location)
: Call_expression(fn, args, is_varargs, location), : Call_expression(fn, args, is_varargs, location),
gogo_(gogo), code_(BUILTIN_INVALID) gogo_(gogo), code_(BUILTIN_INVALID), seen_(false)
{ {
Func_expression* fnexp = this->fn()->func_expression(); Func_expression* fnexp = this->fn()->func_expression();
gcc_assert(fnexp != NULL); gcc_assert(fnexp != NULL);
...@@ -6781,6 +6784,9 @@ Builtin_call_expression::do_is_constant() const ...@@ -6781,6 +6784,9 @@ Builtin_call_expression::do_is_constant() const
case BUILTIN_LEN: case BUILTIN_LEN:
case BUILTIN_CAP: case BUILTIN_CAP:
{ {
if (this->seen_)
return false;
Expression* arg = this->one_arg(); Expression* arg = this->one_arg();
if (arg == NULL) if (arg == NULL)
return false; return false;
...@@ -6793,10 +6799,15 @@ Builtin_call_expression::do_is_constant() const ...@@ -6793,10 +6799,15 @@ Builtin_call_expression::do_is_constant() const
if (arg_type->array_type() != NULL if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL) && arg_type->array_type()->length() != NULL)
return arg_type->array_type()->length()->is_constant(); return true;
if (this->code_ == BUILTIN_LEN && arg_type->is_string_type()) if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
return arg->is_constant(); {
this->seen_ = true;
bool ret = arg->is_constant();
this->seen_ = false;
return ret;
}
} }
break; break;
...@@ -6868,8 +6879,13 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant, ...@@ -6868,8 +6879,13 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
if (arg_type->array_type() != NULL if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL) && arg_type->array_type()->length() != NULL)
{ {
if (this->seen_)
return false;
Expression* e = arg_type->array_type()->length(); Expression* e = arg_type->array_type()->length();
if (e->integer_constant_value(iota_is_constant, val, ptype)) this->seen_ = true;
bool r = e->integer_constant_value(iota_is_constant, val, ptype);
this->seen_ = false;
if (r)
{ {
*ptype = Type::lookup_integer_type("int"); *ptype = Type::lookup_integer_type("int");
return true; return true;
...@@ -7484,7 +7500,18 @@ Builtin_call_expression::do_get_tree(Translate_context* context) ...@@ -7484,7 +7500,18 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
gcc_assert(args != NULL && args->size() == 1); gcc_assert(args != NULL && args->size() == 1);
Expression* arg = *args->begin(); Expression* arg = *args->begin();
Type* arg_type = arg->type(); Type* arg_type = arg->type();
if (this->seen_)
{
gcc_assert(saw_errors());
return error_mark_node;
}
this->seen_ = true;
tree arg_tree = arg->get_tree(context); tree arg_tree = arg->get_tree(context);
this->seen_ = false;
if (arg_tree == error_mark_node) if (arg_tree == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -7503,7 +7530,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context) ...@@ -7503,7 +7530,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
if (arg_type->is_string_type()) if (arg_type->is_string_type())
val_tree = String_type::length_tree(gogo, arg_tree); val_tree = String_type::length_tree(gogo, arg_tree);
else if (arg_type->array_type() != NULL) else if (arg_type->array_type() != NULL)
val_tree = arg_type->array_type()->length_tree(gogo, arg_tree); {
if (this->seen_)
{
gcc_assert(saw_errors());
return error_mark_node;
}
this->seen_ = true;
val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
this->seen_ = false;
}
else if (arg_type->map_type() != NULL) else if (arg_type->map_type() != NULL)
{ {
static tree map_len_fndecl; static tree map_len_fndecl;
...@@ -7532,7 +7568,17 @@ Builtin_call_expression::do_get_tree(Translate_context* context) ...@@ -7532,7 +7568,17 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
else else
{ {
if (arg_type->array_type() != NULL) if (arg_type->array_type() != NULL)
val_tree = arg_type->array_type()->capacity_tree(gogo, arg_tree); {
if (this->seen_)
{
gcc_assert(saw_errors());
return error_mark_node;
}
this->seen_ = true;
val_tree = arg_type->array_type()->capacity_tree(gogo,
arg_tree);
this->seen_ = false;
}
else if (arg_type->channel_type() != NULL) else if (arg_type->channel_type() != NULL)
{ {
static tree chan_cap_fndecl; static tree chan_cap_fndecl;
......
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