aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2010-12-24 01:26:14 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2010-12-24 01:26:14 +0000
commitab9d6dcfbeced3e2e0052c1cacb541e79e622bdf (patch)
tree7d62e153325fc825945f9edfd0e6316eb47bf1f5 /gcc/go
parent3746f0c781beee40cd72fccfe88357bc16ffe1f9 (diff)
downloadgcc-ab9d6dcfbeced3e2e0052c1cacb541e79e622bdf.zip
gcc-ab9d6dcfbeced3e2e0052c1cacb541e79e622bdf.tar.gz
gcc-ab9d6dcfbeced3e2e0052c1cacb541e79e622bdf.tar.bz2
Avoid endless loop on array with recursive length.
From-SVN: r168223
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/expressions.cc58
1 files changed, 52 insertions, 6 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 09d79a0..f64e5ee 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -6463,6 +6463,9 @@ class Builtin_call_expression : public Call_expression
Gogo* gogo_;
// The builtin function being called.
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,
@@ -6471,7 +6474,7 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
bool is_varargs,
source_location 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();
gcc_assert(fnexp != NULL);
@@ -6781,6 +6784,9 @@ Builtin_call_expression::do_is_constant() const
case BUILTIN_LEN:
case BUILTIN_CAP:
{
+ if (this->seen_)
+ return false;
+
Expression* arg = this->one_arg();
if (arg == NULL)
return false;
@@ -6793,10 +6799,15 @@ Builtin_call_expression::do_is_constant() const
if (arg_type->array_type() != 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())
- return arg->is_constant();
+ {
+ this->seen_ = true;
+ bool ret = arg->is_constant();
+ this->seen_ = false;
+ return ret;
+ }
}
break;
@@ -6868,8 +6879,13 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
{
+ if (this->seen_)
+ return false;
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");
return true;
@@ -7484,7 +7500,18 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
gcc_assert(args != NULL && args->size() == 1);
Expression* arg = *args->begin();
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);
+
+ this->seen_ = false;
+
if (arg_tree == error_mark_node)
return error_mark_node;
@@ -7503,7 +7530,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
if (arg_type->is_string_type())
val_tree = String_type::length_tree(gogo, arg_tree);
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)
{
static tree map_len_fndecl;
@@ -7532,7 +7568,17 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
else
{
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)
{
static tree chan_cap_fndecl;