summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/expressions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r--gcc/go/gofrontend/expressions.cc700
1 files changed, 451 insertions, 249 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 241dc36e5e1..69f4e016ba4 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -6951,7 +6951,9 @@ class Builtin_call_expression : public Call_expression
complex_type(Type*);
Expression*
- lower_make();
+ lower_make(Statement_inserter*);
+
+ Expression* flatten_append(Gogo*, Named_object*, Statement_inserter*);
bool
check_int_value(Expression*, bool is_length);
@@ -7052,7 +7054,7 @@ Builtin_call_expression::do_set_recover_arg(Expression* arg)
// specific expressions. We also convert to a constant if we can.
Expression*
-Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
+Builtin_call_expression::do_lower(Gogo*, Named_object* function,
Statement_inserter* inserter, int)
{
if (this->is_error_expression())
@@ -7130,7 +7132,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
break;
case BUILTIN_MAKE:
- return this->lower_make();
+ return this->lower_make(inserter);
case BUILTIN_RECOVER:
if (function != NULL)
@@ -7144,30 +7146,6 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
}
break;
- case BUILTIN_APPEND:
- {
- // Lower the varargs.
- const Expression_list* args = this->args();
- if (args == NULL || args->empty())
- return this;
- Type* slice_type = args->front()->type();
- if (!slice_type->is_slice_type())
- {
- if (slice_type->is_nil_type())
- go_error_at(args->front()->location(), "use of untyped nil");
- else
- go_error_at(args->front()->location(),
- "argument 1 must be a slice");
- this->set_is_error();
- return this;
- }
- Type* element_type = slice_type->array_type()->element_type();
- this->lower_varargs(gogo, function, inserter,
- Type::make_array_type(element_type, NULL),
- 2, SLICE_STORAGE_DOES_NOT_ESCAPE);
- }
- break;
-
case BUILTIN_DELETE:
{
// Lower to a runtime function call.
@@ -7215,7 +7193,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
pa != this->args()->end();
++pa)
{
- if (!(*pa)->is_variable())
+ if (!(*pa)->is_variable() && !(*pa)->is_constant())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pa, loc);
@@ -7233,7 +7211,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
// append into temporary expressions.
Expression*
-Builtin_call_expression::do_flatten(Gogo*, Named_object*,
+Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
Statement_inserter* inserter)
{
Location loc = this->location();
@@ -7244,6 +7222,8 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
break;
case BUILTIN_APPEND:
+ return this->flatten_append(gogo, function, inserter);
+
case BUILTIN_COPY:
{
Type* at = this->args()->front()->type();
@@ -7285,16 +7265,19 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
case BUILTIN_LEN:
case BUILTIN_CAP:
- Expression_list::iterator pa = this->args()->begin();
- if (!(*pa)->is_variable()
- && ((*pa)->type()->map_type() != NULL
- || (*pa)->type()->channel_type() != NULL))
- {
- Temporary_statement* temp =
- Statement::make_temporary(NULL, *pa, loc);
- inserter->insert(temp);
- *pa = Expression::make_temporary_reference(temp, loc);
- }
+ {
+ Expression_list::iterator pa = this->args()->begin();
+ if (!(*pa)->is_variable()
+ && ((*pa)->type()->map_type() != NULL
+ || (*pa)->type()->channel_type() != NULL))
+ {
+ Temporary_statement* temp =
+ Statement::make_temporary(NULL, *pa, loc);
+ inserter->insert(temp);
+ *pa = Expression::make_temporary_reference(temp, loc);
+ }
+ }
+ break;
}
return this;
@@ -7303,7 +7286,7 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
// Lower a make expression.
Expression*
-Builtin_call_expression::lower_make()
+Builtin_call_expression::lower_make(Statement_inserter* inserter)
{
Location loc = this->location();
@@ -7340,10 +7323,6 @@ Builtin_call_expression::lower_make()
return Expression::make_error(this->location());
}
- bool have_big_args = false;
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- int uintptr_bits = uintptr_type->integer_type()->bits();
-
Type_context int_context(Type::lookup_integer_type("int"), false);
++parg;
@@ -7363,9 +7342,6 @@ Builtin_call_expression::lower_make()
len_arg->determine_type(&int_context);
if (!this->check_int_value(len_arg, true))
return Expression::make_error(this->location());
- if (len_arg->type()->integer_type() != NULL
- && len_arg->type()->integer_type()->bits() > uintptr_bits)
- have_big_args = true;
++parg;
}
@@ -7391,9 +7367,6 @@ Builtin_call_expression::lower_make()
return Expression::make_error(this->location());
}
- if (cap_arg->type()->integer_type() != NULL
- && cap_arg->type()->integer_type()->bits() > uintptr_bits)
- have_big_args = true;
++parg;
}
@@ -7404,34 +7377,236 @@ Builtin_call_expression::lower_make()
}
Location type_loc = first_arg->location();
- Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
Expression* call;
if (is_slice)
{
+ Type* et = type->array_type()->element_type();
+ Expression* type_arg = Expression::make_type_descriptor(et, type_loc);
if (cap_arg == NULL)
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKESLICE1BIG
- : Runtime::MAKESLICE1),
- loc, 2, type_arg, len_arg);
- else
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKESLICE2BIG
- : Runtime::MAKESLICE2),
- loc, 3, type_arg, len_arg, cap_arg);
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL,
+ len_arg,
+ loc);
+ inserter->insert(temp);
+ len_arg = Expression::make_temporary_reference(temp, loc);
+ cap_arg = Expression::make_temporary_reference(temp, loc);
+ }
+ call = Runtime::make_call(Runtime::MAKESLICE, loc, 3, type_arg,
+ len_arg, cap_arg);
}
else if (is_map)
- call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg,
- Expression::make_nil(loc),
- Expression::make_nil(loc));
+ {
+ Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
+ call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg,
+ Expression::make_nil(loc),
+ Expression::make_nil(loc));
+ }
else if (is_chan)
- call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+ {
+ Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
+ call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+ }
else
go_unreachable();
return Expression::make_unsafe_cast(type, call, loc);
}
+// Flatten a call to the predeclared append function. We do this in
+// the flatten phase, not the lowering phase, so that we run after
+// type checking and after order_evaluations.
+
+Expression*
+Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
+ Statement_inserter* inserter)
+{
+ if (this->is_error_expression())
+ return this;
+
+ Location loc = this->location();
+
+ const Expression_list* args = this->args();
+ go_assert(args != NULL && !args->empty());
+
+ Type* slice_type = args->front()->type();
+ go_assert(slice_type->is_slice_type());
+ Type* element_type = slice_type->array_type()->element_type();
+
+ if (args->size() == 1)
+ {
+ // append(s) evaluates to s.
+ return args->front();
+ }
+
+ Type* int_type = Type::lookup_integer_type("int");
+ Type* uint_type = Type::lookup_integer_type("uint");
+
+ // Implementing
+ // append(s1, s2...)
+ // or
+ // append(s1, a1, a2, a3, ...)
+
+ // s1tmp := s1
+ Temporary_statement* s1tmp = Statement::make_temporary(NULL, args->front(),
+ loc);
+ inserter->insert(s1tmp);
+
+ // l1tmp := len(s1tmp)
+ Named_object* lenfn = gogo->lookup_global("len");
+ Expression* lenref = Expression::make_func_reference(lenfn, NULL, loc);
+ Expression_list* call_args = new Expression_list();
+ call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
+ Expression* len = Expression::make_call(lenref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &len);
+ gogo->flatten_expression(function, inserter, &len);
+ Temporary_statement* l1tmp = Statement::make_temporary(int_type, len, loc);
+ inserter->insert(l1tmp);
+
+ Temporary_statement* s2tmp = NULL;
+ Temporary_statement* l2tmp = NULL;
+ Expression_list* add = NULL;
+ Expression* len2;
+ if (this->is_varargs())
+ {
+ go_assert(args->size() == 2);
+
+ // s2tmp := s2
+ s2tmp = Statement::make_temporary(NULL, args->back(), loc);
+ inserter->insert(s2tmp);
+
+ // l2tmp := len(s2tmp)
+ lenref = Expression::make_func_reference(lenfn, NULL, loc);
+ call_args = new Expression_list();
+ call_args->push_back(Expression::make_temporary_reference(s2tmp, loc));
+ len = Expression::make_call(lenref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &len);
+ gogo->flatten_expression(function, inserter, &len);
+ l2tmp = Statement::make_temporary(int_type, len, loc);
+ inserter->insert(l2tmp);
+
+ // len2 = l2tmp
+ len2 = Expression::make_temporary_reference(l2tmp, loc);
+ }
+ else
+ {
+ // We have to ensure that all the arguments are in variables
+ // now, because otherwise if one of them is an index expression
+ // into the current slice we could overwrite it before we fetch
+ // it.
+ add = new Expression_list();
+ Expression_list::const_iterator pa = args->begin();
+ for (++pa; pa != args->end(); ++pa)
+ {
+ if ((*pa)->is_variable())
+ add->push_back(*pa);
+ else
+ {
+ Temporary_statement* tmp = Statement::make_temporary(NULL, *pa,
+ loc);
+ inserter->insert(tmp);
+ add->push_back(Expression::make_temporary_reference(tmp, loc));
+ }
+ }
+
+ // len2 = len(add)
+ len2 = Expression::make_integer_ul(add->size(), int_type, loc);
+ }
+
+ // ntmp := l1tmp + len2
+ Expression* ref = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* sum = Expression::make_binary(OPERATOR_PLUS, ref, len2, loc);
+ gogo->lower_expression(function, inserter, &sum);
+ gogo->flatten_expression(function, inserter, &sum);
+ Temporary_statement* ntmp = Statement::make_temporary(int_type, sum, loc);
+ inserter->insert(ntmp);
+
+ // s1tmp = uint(ntmp) > uint(cap(s1tmp)) ?
+ // growslice(type, s1tmp, ntmp) :
+ // s1tmp[:ntmp]
+ // Using uint here means that if the computation of ntmp overflowed,
+ // we will call growslice which will panic.
+
+ Expression* left = Expression::make_temporary_reference(ntmp, loc);
+ left = Expression::make_cast(uint_type, left, loc);
+
+ Named_object* capfn = gogo->lookup_global("cap");
+ Expression* capref = Expression::make_func_reference(capfn, NULL, loc);
+ call_args = new Expression_list();
+ call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
+ Expression* right = Expression::make_call(capref, call_args, false, loc);
+ right = Expression::make_cast(uint_type, right, loc);
+
+ Expression* cond = Expression::make_binary(OPERATOR_GT, left, right, loc);
+
+ Expression* a1 = Expression::make_type_descriptor(element_type, loc);
+ Expression* a2 = Expression::make_temporary_reference(s1tmp, loc);
+ Expression* a3 = Expression::make_temporary_reference(ntmp, loc);
+ Expression* call = Runtime::make_call(Runtime::GROWSLICE, loc, 3,
+ a1, a2, a3);
+ call = Expression::make_unsafe_cast(slice_type, call, loc);
+
+ ref = Expression::make_temporary_reference(s1tmp, loc);
+ Expression* zero = Expression::make_integer_ul(0, int_type, loc);
+ Expression* ref2 = Expression::make_temporary_reference(ntmp, loc);
+ // FIXME: Mark this index as not requiring bounds checks.
+ ref = Expression::make_index(ref, zero, ref2, NULL, loc);
+
+ Expression* rhs = Expression::make_conditional(cond, call, ref, loc);
+
+ gogo->lower_expression(function, inserter, &rhs);
+ gogo->flatten_expression(function, inserter, &rhs);
+
+ Expression* lhs = Expression::make_temporary_reference(s1tmp, loc);
+ Statement* assign = Statement::make_assignment(lhs, rhs, loc);
+ inserter->insert(assign);
+
+ if (this->is_varargs())
+ {
+ // copy(s1tmp[l1tmp:], s2tmp)
+ a1 = Expression::make_temporary_reference(s1tmp, loc);
+ ref = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* nil = Expression::make_nil(loc);
+ // FIXME: Mark this index as not requiring bounds checks.
+ a1 = Expression::make_index(a1, ref, nil, NULL, loc);
+
+ a2 = Expression::make_temporary_reference(s2tmp, loc);
+
+ Named_object* copyfn = gogo->lookup_global("copy");
+ Expression* copyref = Expression::make_func_reference(copyfn, NULL, loc);
+ call_args = new Expression_list();
+ call_args->push_back(a1);
+ call_args->push_back(a2);
+ call = Expression::make_call(copyref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &call);
+ gogo->flatten_expression(function, inserter, &call);
+ inserter->insert(Statement::make_statement(call, false));
+ }
+ else
+ {
+ // For each argument:
+ // s1tmp[l1tmp+i] = a
+ unsigned long i = 0;
+ for (Expression_list::const_iterator pa = add->begin();
+ pa != add->end();
+ ++pa, ++i)
+ {
+ ref = Expression::make_temporary_reference(s1tmp, loc);
+ ref2 = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* off = Expression::make_integer_ul(i, int_type, loc);
+ ref2 = Expression::make_binary(OPERATOR_PLUS, ref2, off, loc);
+ // FIXME: Mark this index as not requiring bounds checks.
+ lhs = Expression::make_index(ref, ref2, NULL, NULL, loc);
+ gogo->lower_expression(function, inserter, &lhs);
+ gogo->flatten_expression(function, inserter, &lhs);
+ assign = Statement::make_assignment(lhs, *pa, loc);
+ inserter->insert(assign);
+ }
+ }
+
+ return Expression::make_temporary_reference(s1tmp, loc);
+}
+
// Return whether an expression has an integer value. Report an error
// if not. This is used when handling calls to the predeclared make
// function.
@@ -8011,6 +8186,7 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
bool is_print;
Type* arg_type = NULL;
+ Type* trailing_arg_types = NULL;
switch (this->code_)
{
case BUILTIN_PRINT:
@@ -8047,6 +8223,16 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
}
break;
+ case BUILTIN_APPEND:
+ if (!this->is_varargs()
+ && args != NULL
+ && !args->empty()
+ && args->front()->type()->is_slice_type())
+ trailing_arg_types =
+ args->front()->type()->array_type()->element_type();
+ is_print = false;
+ break;
+
default:
is_print = false;
break;
@@ -8103,6 +8289,12 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
}
(*pa)->determine_type(&subcontext);
+
+ if (trailing_arg_types != NULL)
+ {
+ arg_type = trailing_arg_types;
+ trailing_arg_types = NULL;
+ }
}
}
}
@@ -8309,54 +8501,102 @@ Builtin_call_expression::do_check_types(Gogo*)
case BUILTIN_APPEND:
{
const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
+ if (args == NULL || args->empty())
{
this->report_error(_("not enough arguments"));
break;
}
- if (args->size() > 2)
- {
- this->report_error(_("too many arguments"));
- break;
- }
- if (args->front()->type()->is_error()
- || args->back()->type()->is_error())
+
+ Type* slice_type = args->front()->type();
+ if (!slice_type->is_slice_type())
{
+ if (slice_type->is_error_type())
+ break;
+ if (slice_type->is_nil_type())
+ go_error_at(args->front()->location(), "use of untyped nil");
+ else
+ go_error_at(args->front()->location(),
+ "argument 1 must be a slice");
this->set_is_error();
break;
}
- Array_type* at = args->front()->type()->array_type();
- Type* e = at->element_type();
-
- // The language permits appending a string to a []byte, as a
- // special case.
- if (args->back()->type()->is_string_type())
+ Type* element_type = slice_type->array_type()->element_type();
+ if (this->is_varargs())
{
- if (e->integer_type() != NULL && e->integer_type()->is_byte())
- break;
- }
+ if (!args->back()->type()->is_slice_type()
+ && !args->back()->type()->is_string_type())
+ {
+ go_error_at(args->back()->location(),
+ "invalid use of %<...%> with non-slice/non-string");
+ this->set_is_error();
+ break;
+ }
- // The language says that the second argument must be
- // assignable to a slice of the element type of the first
- // argument. We already know the first argument is a slice
- // type.
- Type* arg2_type = Type::make_array_type(e, NULL);
- std::string reason;
- if (!Type::are_assignable(arg2_type, args->back()->type(), &reason))
- {
- if (reason.empty())
- this->report_error(_("argument 2 has invalid type"));
+ if (args->size() < 2)
+ {
+ this->report_error(_("not enough arguments"));
+ break;
+ }
+ if (args->size() > 2)
+ {
+ this->report_error(_("too many arguments"));
+ break;
+ }
+
+ if (args->back()->type()->is_string_type()
+ && element_type->integer_type() != NULL
+ && element_type->integer_type()->is_byte())
+ {
+ // Permit append(s1, s2...) when s1 is a slice of
+ // bytes and s2 is a string type.
+ }
else
{
- go_error_at(this->location(),
- "argument 2 has invalid type (%s)",
- reason.c_str());
- this->set_is_error();
+ // We have to test for assignment compatibility to a
+ // slice of the element type, which is not necessarily
+ // the same as the type of the first argument: the
+ // first argument might have a named type.
+ Type* check_type = Type::make_array_type(element_type, NULL);
+ std::string reason;
+ if (!Type::are_assignable(check_type, args->back()->type(),
+ &reason))
+ {
+ if (reason.empty())
+ go_error_at(args->back()->location(),
+ "argument 2 has invalid type");
+ else
+ go_error_at(args->back()->location(),
+ "argument 2 has invalid type (%s)",
+ reason.c_str());
+ this->set_is_error();
+ break;
+ }
+ }
+ }
+ else
+ {
+ Expression_list::const_iterator pa = args->begin();
+ int i = 2;
+ for (++pa; pa != args->end(); ++pa, ++i)
+ {
+ std::string reason;
+ if (!Type::are_assignable(element_type, (*pa)->type(),
+ &reason))
+ {
+ if (reason.empty())
+ go_error_at((*pa)->location(),
+ "argument %d has incompatible type", i);
+ else
+ go_error_at((*pa)->location(),
+ "argument %d has incompatible type (%s)",
+ i, reason.c_str());
+ this->set_is_error();
+ }
}
}
- break;
}
+ break;
case BUILTIN_REAL:
case BUILTIN_IMAG:
@@ -8719,97 +8959,39 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
Type* arg1_type = arg1->type();
Array_type* at = arg1_type->array_type();
go_assert(arg1->is_variable());
- Expression* arg1_val = at->get_value_pointer(gogo, arg1);
- Expression* arg1_len = at->get_length(gogo, arg1);
+
+ Expression* call;
Type* arg2_type = arg2->type();
go_assert(arg2->is_variable());
- Expression* arg2_val;
- Expression* arg2_len;
- if (arg2_type->is_slice_type())
- {
- at = arg2_type->array_type();
- arg2_val = at->get_value_pointer(gogo, arg2);
- arg2_len = at->get_length(gogo, arg2);
- }
+ if (arg2_type->is_string_type())
+ call = Runtime::make_call(Runtime::SLICESTRINGCOPY, location,
+ 2, arg1, arg2);
else
{
- go_assert(arg2->is_variable());
- arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
- location);
- arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
- location);
+ Type* et = at->element_type();
+ if (et->has_pointer())
+ {
+ Expression* td = Expression::make_type_descriptor(et,
+ location);
+ call = Runtime::make_call(Runtime::TYPEDSLICECOPY, location,
+ 3, td, arg1, arg2);
+ }
+ else
+ {
+ Expression* sz = Expression::make_type_info(et,
+ TYPE_INFO_SIZE);
+ call = Runtime::make_call(Runtime::SLICECOPY, location, 3,
+ arg1, arg2, sz);
+ }
}
- Expression* cond =
- Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location);
- Expression* length =
- Expression::make_conditional(cond, arg1_len, arg2_len, location);
-
- Type* element_type = at->element_type();
- int64_t element_size;
- bool ok = element_type->backend_type_size(gogo, &element_size);
- if (!ok)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_expression();
- }
- Expression* size_expr = Expression::make_integer_int64(element_size,
- length->type(),
- location);
- Expression* bytecount =
- Expression::make_binary(OPERATOR_MULT, size_expr, length, location);
- Expression* copy = Runtime::make_call(Runtime::COPY, location, 3,
- arg1_val, arg2_val, bytecount);
-
- Expression* compound = Expression::make_compound(copy, length, location);
- return compound->get_backend(context);
+ return call->get_backend(context);
}
case BUILTIN_APPEND:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 2);
- Expression* arg1 = args->front();
- Expression* arg2 = args->back();
-
- Array_type* at = arg1->type()->array_type();
- Type* element_type = at->element_type()->forwarded();
-
- go_assert(arg2->is_variable());
- Expression* arg2_val;
- Expression* arg2_len;
- int64_t size;
- if (arg2->type()->is_string_type()
- && element_type->integer_type() != NULL
- && element_type->integer_type()->is_byte())
- {
- arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
- location);
- arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
- location);
- size = 1;
- }
- else
- {
- arg2_val = at->get_value_pointer(gogo, arg2);
- arg2_len = at->get_length(gogo, arg2);
- bool ok = element_type->backend_type_size(gogo, &size);
- if (!ok)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_expression();
- }
- }
- Expression* element_size =
- Expression::make_integer_int64(size, NULL, location);
-
- Expression* append = Runtime::make_call(Runtime::APPEND, location, 4,
- arg1, arg2_val, arg2_len,
- element_size);
- append = Expression::make_unsafe_cast(arg1->type(), append, location);
- return append->get_backend(context);
- }
+ // Handled in Builtin_call_expression::flatten_append.
+ go_unreachable();
case BUILTIN_REAL:
case BUILTIN_IMAG:
@@ -12020,12 +12202,10 @@ Expression::make_allocation(Type* type, Location location)
return new Allocation_expression(type, location);
}
-// Class Struct_construction_expression.
-
-// Traversal.
+// Class Ordered_value_list.
int
-Struct_construction_expression::do_traverse(Traverse* traverse)
+Ordered_value_list::traverse_vals(Traverse* traverse)
{
if (this->vals_ != NULL)
{
@@ -12036,8 +12216,8 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
}
else
{
- for (std::vector<int>::const_iterator p =
- this->traverse_order_->begin();
+ for (std::vector<unsigned long>::const_iterator p =
+ this->traverse_order_->begin();
p != this->traverse_order_->end();
++p)
{
@@ -12047,6 +12227,18 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
}
}
}
+ return TRAVERSE_CONTINUE;
+}
+
+// Class Struct_construction_expression.
+
+// Traversal.
+
+int
+Struct_construction_expression::do_traverse(Traverse* traverse)
+{
+ if (this->traverse_vals(traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
return TRAVERSE_CONTINUE;
@@ -12057,10 +12249,10 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
bool
Struct_construction_expression::is_constant_struct() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL
@@ -12088,10 +12280,10 @@ Struct_construction_expression::is_constant_struct() const
bool
Struct_construction_expression::do_is_immutable() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL && !(*pv)->is_immutable())
@@ -12105,15 +12297,15 @@ Struct_construction_expression::do_is_immutable() const
void
Struct_construction_expression::do_determine_type(const Type_context*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
const Struct_field_list* fields = this->type_->struct_type()->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf, ++pv)
{
- if (pv == this->vals_->end())
+ if (pv == this->vals()->end())
return;
if (*pv != NULL)
{
@@ -12123,7 +12315,7 @@ Struct_construction_expression::do_determine_type(const Type_context*)
}
// Extra values are an error we will report elsewhere; we still want
// to determine the type to avoid knockon errors.
- for (; pv != this->vals_->end(); ++pv)
+ for (; pv != this->vals()->end(); ++pv)
(*pv)->determine_type_no_context();
}
@@ -12132,24 +12324,24 @@ Struct_construction_expression::do_determine_type(const Type_context*)
void
Struct_construction_expression::do_check_types(Gogo*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
Struct_type* st = this->type_->struct_type();
- if (this->vals_->size() > st->field_count())
+ if (this->vals()->size() > st->field_count())
{
this->report_error(_("too many expressions for struct"));
return;
}
const Struct_field_list* fields = st->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
int i = 0;
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf, ++pv, ++i)
{
- if (pv == this->vals_->end())
+ if (pv == this->vals()->end())
{
this->report_error(_("too few expressions for struct"));
break;
@@ -12173,7 +12365,7 @@ Struct_construction_expression::do_check_types(Gogo*)
this->set_is_error();
}
}
- go_assert(pv == this->vals_->end());
+ go_assert(pv == this->vals()->end());
}
// Flatten a struct construction expression. Store the values into
@@ -12183,7 +12375,7 @@ Expression*
Struct_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return this;
// If this is a constant struct, we don't need temporaries.
@@ -12191,8 +12383,8 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*,
return this;
Location loc = this->location();
- for (Expression_list::iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL)
@@ -12222,18 +12414,18 @@ Struct_construction_expression::do_get_backend(Translate_context* context)
Gogo* gogo = context->gogo();
Btype* btype = this->type_->get_backend(gogo);
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return gogo->backend()->zero_expression(btype);
const Struct_field_list* fields = this->type_->struct_type()->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
std::vector<Bexpression*> init;
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf)
{
Btype* fbtype = pf->type()->get_backend(gogo);
- if (pv == this->vals_->end())
+ if (pv == this->vals()->end())
init.push_back(gogo->backend()->zero_expression(fbtype));
else if (*pv == NULL)
{
@@ -12259,8 +12451,8 @@ Struct_construction_expression::do_export(Export* exp) const
{
exp->write_c_string("convert(");
exp->write_type(this->type_);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
exp->write_c_string(", ");
@@ -12278,7 +12470,7 @@ Struct_construction_expression::do_dump_expression(
{
ast_dump_context->dump_type(this->type_);
ast_dump_context->ostream() << "{";
- ast_dump_context->dump_expression_list(this->vals_);
+ ast_dump_context->dump_expression_list(this->vals());
ast_dump_context->ostream() << "}";
}
@@ -12299,8 +12491,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
int
Array_construction_expression::do_traverse(Traverse* traverse)
{
- if (this->vals_ != NULL
- && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+ if (this->traverse_vals(traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
@@ -12312,15 +12503,15 @@ Array_construction_expression::do_traverse(Traverse* traverse)
bool
Array_construction_expression::is_constant_array() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
// There are no constant constructors for interfaces.
if (this->type_->array_type()->element_type()->interface_type() != NULL)
return false;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL
@@ -12337,10 +12528,10 @@ Array_construction_expression::is_constant_array() const
bool
Array_construction_expression::do_is_immutable() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL && !(*pv)->is_immutable())
@@ -12354,11 +12545,11 @@ Array_construction_expression::do_is_immutable() const
void
Array_construction_expression::do_determine_type(const Type_context*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
Type_context subcontext(this->type_->array_type()->element_type(), false);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL)
@@ -12371,14 +12562,14 @@ Array_construction_expression::do_determine_type(const Type_context*)
void
Array_construction_expression::do_check_types(Gogo*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
Array_type* at = this->type_->array_type();
int i = 0;
Type* element_type = at->element_type();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv, ++i)
{
if (*pv != NULL
@@ -12399,7 +12590,7 @@ Expression*
Array_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return this;
// If this is a constant array, we don't need temporaries.
@@ -12407,8 +12598,8 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*,
return this;
Location loc = this->location();
- for (Expression_list::iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL)
@@ -12441,14 +12632,14 @@ Array_construction_expression::get_constructor(Translate_context* context,
std::vector<unsigned long> indexes;
std::vector<Bexpression*> vals;
Gogo* gogo = context->gogo();
- if (this->vals_ != NULL)
+ if (this->vals() != NULL)
{
size_t i = 0;
std::vector<unsigned long>::const_iterator pi;
if (this->indexes_ != NULL)
pi = this->indexes_->begin();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv, ++i)
{
if (this->indexes_ != NULL)
@@ -12488,13 +12679,13 @@ Array_construction_expression::do_export(Export* exp) const
{
exp->write_c_string("convert(");
exp->write_type(this->type_);
- if (this->vals_ != NULL)
+ if (this->vals() != NULL)
{
std::vector<unsigned long>::const_iterator pi;
if (this->indexes_ != NULL)
pi = this->indexes_->begin();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
exp->write_c_string(", ");
@@ -12535,10 +12726,10 @@ Array_construction_expression::do_dump_expression(
this->dump_slice_storage_expression(ast_dump_context);
ast_dump_context->ostream() << "{" ;
if (this->indexes_ == NULL)
- ast_dump_context->dump_expression_list(this->vals_);
+ ast_dump_context->dump_expression_list(this->vals());
else
{
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
for (std::vector<unsigned long>::const_iterator pi =
this->indexes_->begin();
pi != this->indexes_->end();
@@ -13167,7 +13358,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
size_t field_count = st->field_count();
std::vector<Expression*> vals(field_count);
- std::vector<int>* traverse_order = new(std::vector<int>);
+ std::vector<unsigned long>* traverse_order = new(std::vector<unsigned long>);
Expression_list::const_iterator p = this->vals_->begin();
Expression* external_expr = NULL;
const Named_object* external_no = NULL;
@@ -13299,7 +13490,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
type->named_type()->message_name().c_str());
vals[index] = val;
- traverse_order->push_back(index);
+ traverse_order->push_back(static_cast<unsigned long>(index));
}
if (!this->all_are_names_)
@@ -13330,15 +13521,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
return ret;
}
-// Used to sort an index/value array.
+// Index/value/traversal-order triple.
-class Index_value_compare
-{
- public:
- bool
- operator()(const std::pair<unsigned long, Expression*>& a,
- const std::pair<unsigned long, Expression*>& b)
- { return a.first < b.first; }
+struct IVT_triple {
+ unsigned long index;
+ unsigned long traversal_order;
+ Expression* expr;
+ IVT_triple(unsigned long i, unsigned long to, Expression *e)
+ : index(i), traversal_order(to), expr(e) { }
+ bool operator<(const IVT_triple& other) const
+ { return this->index < other.index; }
};
// Lower an array composite literal.
@@ -13442,35 +13634,45 @@ Composite_literal_expression::lower_array(Type* type)
indexes = NULL;
}
+ std::vector<unsigned long>* traverse_order = NULL;
if (indexes_out_of_order)
{
- typedef std::vector<std::pair<unsigned long, Expression*> > V;
+ typedef std::vector<IVT_triple> V;
V v;
v.reserve(indexes->size());
std::vector<unsigned long>::const_iterator pi = indexes->begin();
+ unsigned long torder = 0;
for (Expression_list::const_iterator pe = vals->begin();
pe != vals->end();
- ++pe, ++pi)
- v.push_back(std::make_pair(*pi, *pe));
+ ++pe, ++pi, ++torder)
+ v.push_back(IVT_triple(*pi, torder, *pe));
- std::sort(v.begin(), v.end(), Index_value_compare());
+ std::sort(v.begin(), v.end());
delete indexes;
delete vals;
+
indexes = new std::vector<unsigned long>();
indexes->reserve(v.size());
vals = new Expression_list();
vals->reserve(v.size());
+ traverse_order = new std::vector<unsigned long>();
+ traverse_order->reserve(v.size());
for (V::const_iterator p = v.begin(); p != v.end(); ++p)
{
- indexes->push_back(p->first);
- vals->push_back(p->second);
+ indexes->push_back(p->index);
+ vals->push_back(p->expr);
+ traverse_order->push_back(p->traversal_order);
}
}
- return this->make_array(type, indexes, vals);
+ Expression* ret = this->make_array(type, indexes, vals);
+ Array_construction_expression* ace = ret->array_literal();
+ if (ace != NULL && traverse_order != NULL)
+ ace->set_traverse_order(traverse_order);
+ return ret;
}
// Actually build the array composite literal. This handles