// method table.
// We are going to evaluate RHS multiple times.
- go_assert(rhs->is_variable());
+ go_assert(rhs->is_multi_eval_safe());
// Get the type descriptor for the right hand side. This will be
// NULL for a nil interface.
Location location)
{
// We are going to evaluate RHS multiple times.
- go_assert(rhs->is_variable());
+ go_assert(rhs->is_multi_eval_safe());
// Build an expression to check that the type is valid. It will
// panic with an appropriate runtime type error if the type is not
Statement_inserter* inserter,
Location loc)
{
- go_assert(val->is_variable() || val->is_constant());
- go_assert(bound->is_variable() || bound->is_constant());
+ go_assert(val->is_multi_eval_safe());
+ go_assert(bound->is_multi_eval_safe());
Type* int_type = Type::lookup_integer_type("int");
int int_type_size = int_type->integer_type()->bits();
if (((this->type()->is_string_type()
&& this->expr_->type()->is_slice_type())
|| this->expr_->type()->interface_type() != NULL)
- && !this->expr_->is_variable())
+ && !this->expr_->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->expr_, this->location());
Array_type* a = expr_type->array_type();
Type* e = a->element_type()->forwarded();
go_assert(e->integer_type() != NULL);
- go_assert(this->expr_->is_variable());
+ go_assert(this->expr_->is_multi_eval_safe());
Expression* buf;
if (this->no_escape_ && !this->no_copy_)
Location location = this->location();
if (this->op_ == OPERATOR_MULT
- && !this->expr_->is_variable())
+ && !this->expr_->is_multi_eval_safe())
{
go_assert(this->expr_->type()->points_to() != NULL);
switch (this->requires_nil_check(gogo))
}
}
- if (this->create_temp_ && !this->expr_->is_variable())
+ if (this->create_temp_ && !this->expr_->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->expr_, location);
bexpr = gogo->backend()->var_expression(decl, loc);
}
- go_assert(!this->create_temp_ || this->expr_->is_variable());
+ go_assert(!this->create_temp_ || this->expr_->is_multi_eval_safe());
ret = gogo->backend()->address_expression(bexpr, loc);
break;
}
case NIL_CHECK_NEEDED:
{
- go_assert(this->expr_->is_variable());
+ go_assert(this->expr_->is_multi_eval_safe());
// If we're nil-checking the result of a set-and-use-temporary
// expression, then pick out the target temp and use that
&& (gogo->check_divide_by_zero() || gogo->check_divide_overflow()))
|| is_string_op)
{
- if (!this->left_->is_variable() && !this->left_->is_constant())
+ if (!this->left_->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, this->left_, loc);
inserter->insert(temp);
this->left_ = Expression::make_temporary_reference(temp, loc);
}
- if (!this->right_->is_variable() && !this->right_->is_constant())
+ if (!this->right_->is_multi_eval_safe())
{
temp =
Statement::make_temporary(NULL, this->right_, loc);
if (left_type->is_string_type() && right_type->is_string_type())
{
- go_assert(left->is_variable() || left->is_constant());
- go_assert(right->is_variable() || right->is_constant());
+ go_assert(left->is_multi_eval_safe());
+ go_assert(right->is_multi_eval_safe());
if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
{
// we are going to do nil checks below, but it's easy enough to
// always do it.
Expression* expr = this->expr_;
- if (!expr->is_variable())
+ if (!expr->is_multi_eval_safe())
{
Temporary_statement* etemp = Statement::make_temporary(NULL, expr, loc);
inserter->insert(etemp);
pa != this->args()->end();
++pa)
{
- if (!(*pa)->is_variable() && !(*pa)->is_constant())
+ if (!(*pa)->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pa, loc);
Expression* zero = Expression::make_integer_ul(0, NULL, loc);
*pa = Expression::make_slice_value(at, nil, zero, zero, loc);
}
- if (!(*pa)->is_variable())
+ if (!(*pa)->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pa, loc);
go_assert(args != NULL && args->size() == 2);
Expression* arg1 = args->front();
Expression* arg2 = args->back();
- go_assert(arg1->is_variable());
- go_assert(arg2->is_variable());
+ go_assert(arg1->is_multi_eval_safe());
+ go_assert(arg2->is_multi_eval_safe());
bool arg2_is_string = arg2->type()->is_string_type();
Expression* ret;
pa != this->args()->end();
++pa)
{
- if (!(*pa)->is_variable() && (*pa)->type()->interface_type() != NULL)
+ if (!(*pa)->is_multi_eval_safe()
+ && (*pa)->type()->interface_type() != NULL)
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pa, loc);
case BUILTIN_CAP:
{
Expression_list::iterator pa = this->args()->begin();
- if (!(*pa)->is_variable()
+ if (!(*pa)->is_multi_eval_safe()
&& ((*pa)->type()->map_type() != NULL
|| (*pa)->type()->channel_type() != NULL))
{
Expression_list::const_iterator pa = args->begin();
for (++pa; pa != args->end(); ++pa)
{
- if ((*pa)->is_variable())
+ if ((*pa)->is_multi_eval_safe())
add->push_back(*pa);
else
{
{
Location loc = (*pa)->location();
Expression* arg = *pa;
- if (!arg->is_variable())
+ if (!arg->is_multi_eval_safe())
{
Temporary_statement *temp =
Statement::make_temporary(NULL, arg, loc);
&& this->args_ != NULL && this->args_->size() == 1)
{
Expression* arg = this->args_->front();
- if (!arg->is_variable())
+ if (!arg->is_multi_eval_safe())
{
Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc);
inserter->insert(ts);
&& this->args_ != NULL && this->args_->size() == 1)
{
Expression* arg = this->args_->front();
- if (!arg->is_variable())
+ if (!arg->is_multi_eval_safe())
{
Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc);
inserter->insert(ts);
&& this->args_ != NULL && this->args_->size() == 1)
{
Expression* arg = this->args_->front();
- if (!arg->is_variable())
+ if (!arg->is_multi_eval_safe())
{
Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc);
inserter->insert(ts);
&& this->args_ != NULL && this->args_->size() == 1)
{
Expression* arg = this->args_->front();
- if (!arg->is_variable())
+ if (!arg->is_multi_eval_safe())
{
Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc);
inserter->insert(ts);
}
Temporary_statement* temp;
- if (array_type->is_slice_type() && !array->is_variable())
+ if (array_type->is_slice_type() && !array->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, array, loc);
inserter->insert(temp);
this->array_ = Expression::make_temporary_reference(temp, loc);
array = this->array_;
}
- if (!start->is_variable() && !start->is_constant())
+ if (!start->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, start, loc);
inserter->insert(temp);
}
if (end != NULL
&& !end->is_nil_expression()
- && !end->is_variable()
- && !end->is_constant())
+ && !end->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, end, loc);
inserter->insert(temp);
this->end_ = Expression::make_temporary_reference(temp, loc);
end = this->end_;
}
- if (cap != NULL && !cap->is_variable() && !cap->is_constant())
+ if (cap != NULL && !cap->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, cap, loc);
inserter->insert(temp);
go_assert(this->array_->type()->is_error());
return context->backend()->error_expression();
}
- go_assert(!array_type->is_slice_type() || this->array_->is_variable());
+ go_assert(!array_type->is_slice_type()
+ || this->array_->is_multi_eval_safe());
Location loc = this->location();
Gogo* gogo = context->gogo();
}
Temporary_statement* temp;
- if (!string->is_variable())
+ if (!string->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, string, loc);
inserter->insert(temp);
this->string_ = Expression::make_temporary_reference(temp, loc);
string = this->string_;
}
- if (!start->is_variable())
+ if (!start->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, start, loc);
inserter->insert(temp);
}
if (end != NULL
&& !end->is_nil_expression()
- && !end->is_variable())
+ && !end->is_multi_eval_safe())
{
temp = Statement::make_temporary(NULL, end, loc);
inserter->insert(temp);
return context->backend()->error_expression();
}
- go_assert(this->string_->is_variable());
- go_assert(this->start_->is_variable());
+ go_assert(this->string_->is_multi_eval_safe());
+ go_assert(this->start_->is_multi_eval_safe());
Expression* start = Expression::make_cast(int_type, this->start_, loc);
Bfunction* bfn = context->function()->func_value()->get_decl();
end = length;
else
{
- go_assert(this->end_->is_variable());
+ go_assert(this->end_->is_multi_eval_safe());
end = Expression::make_cast(int_type, this->end_, loc);
}
NULL))
{
if (this->index_->type()->interface_type() != NULL
- && !this->index_->is_variable())
+ && !this->index_->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->index_, loc);
this->index_, loc);
}
- if (!this->index_->is_variable())
+ if (!this->index_->is_multi_eval_safe())
{
Temporary_statement* temp = Statement::make_temporary(NULL, this->index_,
loc);
if (this->value_pointer_->is_error_expression()
|| this->value_pointer_->type()->is_error_type())
return Expression::make_error(loc);
- if (!this->value_pointer_->is_variable())
+ if (!this->value_pointer_->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->value_pointer_, loc);
}
go_assert(this->value_pointer_ != NULL
- && this->value_pointer_->is_variable());
+ && this->value_pointer_->is_multi_eval_safe());
Expression* val = Expression::make_dereference(this->value_pointer_,
NIL_CHECK_NOT_NEEDED,
return Expression::make_error(this->location());
}
- if (!this->expr_->is_variable())
+ if (!this->expr_->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, this->expr_, this->location());
go_assert(saw_errors());
return Expression::make_error(loc);
}
- if (!(*pv)->is_variable())
+ if (!(*pv)->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pv, loc);
go_assert(saw_errors());
return Expression::make_error(loc);
}
- if (!(*pv)->is_variable())
+ if (!(*pv)->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pv, loc);
go_assert(saw_errors());
return Expression::make_error(loc);
}
- if (key->type()->interface_type() != NULL && !key->is_variable())
+ if (key->type()->interface_type() != NULL
+ && !key->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, key, loc);
go_assert(saw_errors());
return Expression::make_error(loc);
}
- if (val->type()->interface_type() != NULL && !val->is_variable())
+ if (val->type()->interface_type() != NULL
+ && !val->is_multi_eval_safe())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, val, loc);
|| (no->is_variable() && !no->var_value()->is_global()));
}
+// Return true if multiple evaluations are OK.
+
+bool
+Expression::is_multi_eval_safe()
+{
+ switch (this->classification_)
+ {
+ case EXPRESSION_VAR_REFERENCE:
+ {
+ // A variable is a simple reference if not stored in the heap.
+ const Named_object* no = this->var_expression()->named_object();
+ if (no->is_variable())
+ return !no->var_value()->is_in_heap();
+ else if (no->is_result_variable())
+ return !no->result_var_value()->is_in_heap();
+ else
+ go_unreachable();
+ }
+
+ case EXPRESSION_TEMPORARY_REFERENCE:
+ return true;
+
+ default:
+ break;
+ }
+
+ if (!this->is_constant())
+ return false;
+
+ // Only numeric and boolean constants are really multi-evaluation
+ // safe. We don't want multiple copies of string constants.
+ Type* type = this->type();
+ return type->is_numeric_type() || type->is_boolean_type();
+}
+
const Named_object*
Expression::named_constant() const
{
return Expression::make_error(this->location());
}
- if (!this->expr_->is_variable())
+ if (!this->expr_->is_multi_eval_safe())
{
Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_,
this->location());