aboutsummaryrefslogtreecommitdiff
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.cc3652
1 files changed, 1866 insertions, 1786 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index f45b4a2..bd2e318 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -140,128 +140,81 @@ Expression::determine_type_no_context()
this->do_determine_type(&context);
}
-// Return a tree handling any conversions which must be done during
+// Return an expression handling any conversions which must be done during
// assignment.
-tree
-Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
- Type* rhs_type, tree rhs_tree,
- Location location)
+Expression*
+Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type,
+ Expression* rhs, Location location)
{
- if (lhs_type->is_error() || rhs_type->is_error())
- return error_mark_node;
-
- if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node)
- return error_mark_node;
-
- Gogo* gogo = context->gogo();
-
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
+ Type* rhs_type = rhs->type();
+ if (lhs_type->is_error()
+ || rhs_type->is_error()
+ || rhs->is_error_expression())
+ return Expression::make_error(location);
if (lhs_type->forwarded() != rhs_type->forwarded()
&& lhs_type->interface_type() != NULL)
{
if (rhs_type->interface_type() == NULL)
- return Expression::convert_type_to_interface(context, lhs_type,
- rhs_type, rhs_tree,
- location);
+ return Expression::convert_type_to_interface(lhs_type, rhs, location);
else
- return Expression::convert_interface_to_interface(context, lhs_type,
- rhs_type, rhs_tree,
- false, location);
+ return Expression::convert_interface_to_interface(lhs_type, rhs, false,
+ location);
}
else if (lhs_type->forwarded() != rhs_type->forwarded()
&& rhs_type->interface_type() != NULL)
- return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
- rhs_tree, location);
+ return Expression::convert_interface_to_type(lhs_type, rhs, location);
else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
{
- // Assigning nil to an open array.
- go_assert(TREE_CODE(lhs_type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(lhs_type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__values") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__count") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
-
- tree val = build_constructor(lhs_type_tree, init);
- TREE_CONSTANT(val) = 1;
-
- return val;
+ // Assigning nil to a slice.
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0UL);
+ Expression* zero = Expression::make_integer(&zval, NULL, location);
+ mpz_clear(zval);
+ Expression* nil = Expression::make_nil(location);
+ return Expression::make_slice_value(lhs_type, nil, zero, zero, location);
}
else if (rhs_type->is_nil_type())
- {
- // The left hand side should be a pointer type at the tree
- // level.
- go_assert(POINTER_TYPE_P(lhs_type_tree));
- return fold_convert(lhs_type_tree, null_pointer_node);
- }
- else if (lhs_type_tree == TREE_TYPE(rhs_tree))
+ return Expression::make_nil(location);
+ else if (Type::are_identical(lhs_type, rhs_type, false, NULL))
{
// No conversion is needed.
- return rhs_tree;
- }
- else if (POINTER_TYPE_P(lhs_type_tree)
- || INTEGRAL_TYPE_P(lhs_type_tree)
- || SCALAR_FLOAT_TYPE_P(lhs_type_tree)
- || COMPLEX_FLOAT_TYPE_P(lhs_type_tree))
- return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree);
- else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE
- && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE)
- || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE
- && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE))
+ return rhs;
+ }
+ else if (lhs_type->points_to() != NULL)
+ return Expression::make_unsafe_cast(lhs_type, rhs, location);
+ else if (lhs_type->is_numeric_type())
+ return Expression::make_cast(lhs_type, rhs, location);
+ else if ((lhs_type->struct_type() != NULL
+ && rhs_type->struct_type() != NULL)
+ || (lhs_type->array_type() != NULL
+ && rhs_type->array_type() != NULL))
{
// Avoid confusion from zero sized variables which may be
// represented as non-zero-sized.
- if (int_size_in_bytes(lhs_type_tree) == 0
- || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0)
- return rhs_tree;
+ // TODO(cmang): This check is for a GCC-specific issue, and should be
+ // removed from the frontend. FIXME.
+ size_t lhs_size = gogo->backend()->type_size(lhs_type->get_backend(gogo));
+ size_t rhs_size = gogo->backend()->type_size(rhs_type->get_backend(gogo));
+ if (rhs_size == 0 || lhs_size == 0)
+ return rhs;
// This conversion must be permitted by Go, or we wouldn't have
// gotten here.
- go_assert(int_size_in_bytes(lhs_type_tree)
- == int_size_in_bytes(TREE_TYPE(rhs_tree)));
- return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR,
- lhs_type_tree, rhs_tree);
+ return Expression::make_unsafe_cast(lhs_type, rhs, location);
}
else
- {
- go_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree)));
- return rhs_tree;
- }
+ return rhs;
}
-// Return a tree for a conversion from a non-interface type to an
+// Return an expression for a conversion from a non-interface type to an
// interface type.
-tree
-Expression::convert_type_to_interface(Translate_context* context,
- Type* lhs_type, Type* rhs_type,
- tree rhs_tree, Location location)
+Expression*
+Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs,
+ Location location)
{
- Gogo* gogo = context->gogo();
Interface_type* lhs_interface_type = lhs_type->interface_type();
bool lhs_is_empty = lhs_interface_type->is_empty();
@@ -270,29 +223,22 @@ Expression::convert_type_to_interface(Translate_context* context,
// When setting an interface to nil, we just set both fields to
// NULL.
+ Type* rhs_type = rhs->type();
if (rhs_type->is_nil_type())
{
- Btype* lhs_btype = lhs_type->get_backend(gogo);
- return expr_to_tree(gogo->backend()->zero_expression(lhs_btype));
+ Expression* nil = Expression::make_nil(location);
+ return Expression::make_interface_value(lhs_type, nil, nil, location);
}
// This should have been checked already.
go_assert(lhs_interface_type->implements_interface(rhs_type, NULL));
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
// An interface is a tuple. If LHS_TYPE is an empty interface type,
// then the first field is the type descriptor for RHS_TYPE.
// Otherwise it is the interface method table for RHS_TYPE.
- tree first_field_value;
+ Expression* first_field;
if (lhs_is_empty)
- {
- Bexpression* rhs_bexpr =
- rhs_type->type_descriptor_pointer(gogo, location);
- first_field_value = expr_to_tree(rhs_bexpr);
- }
+ first_field = Expression::make_type_descriptor(rhs_type, location);
else
{
// Build the interface method table for this interface and this
@@ -307,131 +253,72 @@ Expression::convert_type_to_interface(Translate_context* context,
rhs_struct_type = rhs_type->deref()->struct_type();
is_pointer = true;
}
- tree method_table;
if (rhs_named_type != NULL)
- method_table =
- rhs_named_type->interface_method_table(gogo, lhs_interface_type,
- is_pointer);
+ first_field =
+ rhs_named_type->interface_method_table(lhs_interface_type,
+ is_pointer);
else if (rhs_struct_type != NULL)
- method_table =
- rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
- is_pointer);
+ first_field =
+ rhs_struct_type->interface_method_table(lhs_interface_type,
+ is_pointer);
else
- method_table = null_pointer_node;
- first_field_value = fold_convert_loc(location.gcc_location(),
- const_ptr_type_node, method_table);
+ first_field = Expression::make_nil(location);
}
- if (first_field_value == error_mark_node)
- return error_mark_node;
-
- // Start building a constructor for the value we will return.
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(lhs_type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0);
- elt->index = field;
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- first_field_value);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
- elt->index = field;
+ Expression* obj;
if (rhs_type->points_to() != NULL)
{
- // We are assigning a pointer to the interface; the interface
+ // We are assigning a pointer to the interface; the interface
// holds the pointer itself.
- elt->value = rhs_tree;
- return build_constructor(lhs_type_tree, init);
+ obj = rhs;
+ }
+ else
+ {
+ // We are assigning a non-pointer value to the interface; the
+ // interface gets a copy of the value in the heap.
+ obj = Expression::make_heap_expression(rhs, location);
}
- // We are assigning a non-pointer value to the interface; the
- // interface gets a copy of the value in the heap.
+ return Expression::make_interface_value(lhs_type, first_field, obj, location);
+}
- tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
+// Return an expression for the type descriptor of RHS.
- tree space = gogo->allocate_memory(rhs_type, object_size, location);
- space = fold_convert_loc(location.gcc_location(),
- build_pointer_type(TREE_TYPE(rhs_tree)), space);
- space = save_expr(space);
+Expression*
+Expression::get_interface_type_descriptor(Expression* rhs)
+{
+ go_assert(rhs->type()->interface_type() != NULL);
+ Location location = rhs->location();
- tree ref = build_fold_indirect_ref_loc(location.gcc_location(), space);
- TREE_THIS_NOTRAP(ref) = 1;
- tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR,
- void_type_node, ref, rhs_tree);
+ // The type descriptor is the first field of an empty interface.
+ if (rhs->type()->interface_type()->is_empty())
+ return Expression::make_interface_info(rhs, INTERFACE_INFO_TYPE_DESCRIPTOR,
+ location);
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- space);
+ Expression* mtable =
+ Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location);
- return build2(COMPOUND_EXPR, lhs_type_tree, set,
- build_constructor(lhs_type_tree, init));
-}
+ Expression* descriptor =
+ Expression::make_unary(OPERATOR_MULT, mtable, location);
+ descriptor = Expression::make_field_reference(descriptor, 0, location);
+ Expression* nil = Expression::make_nil(location);
-// Return a tree for the type descriptor of RHS_TREE, which has
-// interface type RHS_TYPE. If RHS_TREE is nil the result will be
-// NULL.
+ Expression* eq =
+ Expression::make_binary(OPERATOR_EQEQ, mtable, nil, location);
+ return Expression::make_conditional(eq, nil, descriptor, location);
+}
-tree
-Expression::get_interface_type_descriptor(Translate_context*,
- Type* rhs_type, tree rhs_tree,
- Location location)
-{
- tree rhs_type_tree = TREE_TYPE(rhs_tree);
- go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
- tree rhs_field = TYPE_FIELDS(rhs_type_tree);
- tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
- NULL_TREE);
- if (rhs_type->interface_type()->is_empty())
- {
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)),
- "__type_descriptor") == 0);
- return v;
- }
-
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods")
- == 0);
- go_assert(POINTER_TYPE_P(TREE_TYPE(v)));
- v = save_expr(v);
- tree v1 = build_fold_indirect_ref_loc(location.gcc_location(), v);
- go_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE);
- tree f = TYPE_FIELDS(TREE_TYPE(v1));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor")
- == 0);
- v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE);
-
- tree eq = fold_build2_loc(location.gcc_location(), EQ_EXPR, boolean_type_node,
- v, fold_convert_loc(location.gcc_location(),
- TREE_TYPE(v),
- null_pointer_node));
- tree n = fold_convert_loc(location.gcc_location(), TREE_TYPE(v1),
- null_pointer_node);
- return fold_build3_loc(location.gcc_location(), COND_EXPR, TREE_TYPE(v1),
- eq, n, v1);
-}
-
-// Return a tree for the conversion of an interface type to an
+// Return an expression for the conversion of an interface type to an
// interface type.
-tree
-Expression::convert_interface_to_interface(Translate_context* context,
- Type *lhs_type, Type *rhs_type,
- tree rhs_tree, bool for_type_guard,
- Location location)
+Expression*
+Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs,
+ bool for_type_guard,
+ Location location)
{
- Gogo* gogo = context->gogo();
Interface_type* lhs_interface_type = lhs_type->interface_type();
bool lhs_is_empty = lhs_interface_type->is_empty();
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
// In the general case this requires runtime examination of the type
// method table to match it up with the interface methods.
@@ -442,169 +329,75 @@ Expression::convert_interface_to_interface(Translate_context* context,
// Get the type descriptor for the right hand side. This will be
// NULL for a nil interface.
+ Expression* rhs_type_expr = Expression::get_interface_type_descriptor(rhs);
+ Expression* lhs_type_expr =
+ Expression::make_type_descriptor(lhs_type, location);
- if (!DECL_P(rhs_tree))
- rhs_tree = save_expr(rhs_tree);
-
- tree rhs_type_descriptor =
- Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
- location);
-
- // The result is going to be a two element constructor.
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc (init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(lhs_type_tree);
- elt->index = field;
-
+ Expression* first_field;
if (for_type_guard)
{
// A type assertion fails when converting a nil interface.
- Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
- location);
- tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
- static tree assert_interface_decl;
- tree call = Gogo::call_builtin(&assert_interface_decl,
- location,
- "__go_assert_interface",
- 2,
- ptr_type_node,
- TREE_TYPE(lhs_type_descriptor),
- lhs_type_descriptor,
- TREE_TYPE(rhs_type_descriptor),
- rhs_type_descriptor);
- if (call == error_mark_node)
- return error_mark_node;
- // This will panic if the interface conversion fails.
- TREE_NOTHROW(assert_interface_decl) = 0;
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- call);
+ first_field =
+ Runtime::make_call(Runtime::ASSERT_INTERFACE, location, 2,
+ lhs_type_expr, rhs_type_expr);
}
else if (lhs_is_empty)
{
- // A convertion to an empty interface always succeeds, and the
+ // A conversion to an empty interface always succeeds, and the
// first field is just the type descriptor of the object.
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__type_descriptor") == 0);
- elt->value = fold_convert_loc(location.gcc_location(),
- TREE_TYPE(field), rhs_type_descriptor);
+ first_field = rhs_type_expr;
}
else
{
// A conversion to a non-empty interface may fail, but unlike a
// type assertion converting nil will always succeed.
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
- == 0);
- Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
- location);
- tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
-
- static tree convert_interface_decl;
- tree call = Gogo::call_builtin(&convert_interface_decl,
- location,
- "__go_convert_interface",
- 2,
- ptr_type_node,
- TREE_TYPE(lhs_type_descriptor),
- lhs_type_descriptor,
- TREE_TYPE(rhs_type_descriptor),
- rhs_type_descriptor);
- if (call == error_mark_node)
- return error_mark_node;
- // This will panic if the interface conversion fails.
- TREE_NOTHROW(convert_interface_decl) = 0;
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- call);
+ first_field =
+ Runtime::make_call(Runtime::CONVERT_INTERFACE, location, 2,
+ lhs_type_expr, rhs_type_expr);
}
// The second field is simply the object pointer.
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
- elt->index = field;
-
- tree rhs_type_tree = TREE_TYPE(rhs_tree);
- go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
- tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
- elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
- NULL_TREE);
-
- return build_constructor(lhs_type_tree, init);
+ Expression* obj =
+ Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, location);
+ return Expression::make_interface_value(lhs_type, first_field, obj, location);
}
-// Return a tree for the conversion of an interface type to a
+// Return an expression for the conversion of an interface type to a
// non-interface type.
-tree
-Expression::convert_interface_to_type(Translate_context* context,
- Type *lhs_type, Type* rhs_type,
- tree rhs_tree, Location location)
+Expression*
+Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
+ Location location)
{
- Gogo* gogo = context->gogo();
- tree rhs_type_tree = TREE_TYPE(rhs_tree);
-
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
// Call a function to check that the type is valid. The function
// will panic with an appropriate runtime type error if the type is
// not valid.
- Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
- location);
- tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
-
- if (!DECL_P(rhs_tree))
- rhs_tree = save_expr(rhs_tree);
-
- tree rhs_type_descriptor =
- Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
- location);
-
- Bexpression* rhs_inter_expr = rhs_type->type_descriptor_pointer(gogo,
- location);
- tree rhs_inter_descriptor = expr_to_tree(rhs_inter_expr);
-
- static tree check_interface_type_decl;
- tree call = Gogo::call_builtin(&check_interface_type_decl,
- location,
- "__go_check_interface_type",
- 3,
- void_type_node,
- TREE_TYPE(lhs_type_descriptor),
- lhs_type_descriptor,
- TREE_TYPE(rhs_type_descriptor),
- rhs_type_descriptor,
- TREE_TYPE(rhs_inter_descriptor),
- rhs_inter_descriptor);
- if (call == error_mark_node)
- return error_mark_node;
- // This call will panic if the conversion is invalid.
- TREE_NOTHROW(check_interface_type_decl) = 0;
+ Expression* lhs_type_expr = Expression::make_type_descriptor(lhs_type,
+ location);
+ Expression* rhs_descriptor =
+ Expression::get_interface_type_descriptor(rhs);
+
+ Type* rhs_type = rhs->type();
+ Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type,
+ location);
+
+ Expression* check_iface = Runtime::make_call(Runtime::CHECK_INTERFACE_TYPE,
+ location, 3, lhs_type_expr,
+ rhs_descriptor, rhs_inter_expr);
// If the call succeeds, pull out the value.
- go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
- tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
- tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
- NULL_TREE);
+ Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT,
+ location);
// If the value is a pointer, then it is the value we want.
// Otherwise it points to the value.
if (lhs_type->points_to() == NULL)
{
- val = fold_convert_loc(location.gcc_location(),
- build_pointer_type(lhs_type_tree), val);
- val = build_fold_indirect_ref_loc(location.gcc_location(), val);
+ obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj,
+ location);
+ obj = Expression::make_unary(OPERATOR_MULT, obj, location);
}
-
- return build2(COMPOUND_EXPR, lhs_type_tree, call,
- fold_convert_loc(location.gcc_location(), lhs_type_tree, val));
+ return Expression::make_compound(check_iface, obj, location);
}
// Convert an expression to a tree. This is implemented by the child
@@ -674,54 +467,71 @@ Expression::backend_numeric_constant_expression(Translate_context* context,
return ret;
}
-// Return a tree which evaluates to true if VAL, of arbitrary integer
-// type, is negative or is more than the maximum value of BOUND_TYPE.
-// If SOFAR is not NULL, it is or'red into the result. The return
-// value may be NULL if SOFAR is NULL.
+// Return an expression which evaluates to true if VAL, of arbitrary integer
+// type, is negative or is more than the maximum value of the Go type "int".
-tree
-Expression::check_bounds(tree val, tree bound_type, tree sofar,
- Location loc)
+Expression*
+Expression::check_bounds(Expression* val, Location loc)
{
- tree val_type = TREE_TYPE(val);
- tree ret = NULL_TREE;
+ Type* val_type = val->type();
+ Type* bound_type = Type::lookup_integer_type("int");
+
+ int val_type_size;
+ bool val_is_unsigned = false;
+ if (val_type->integer_type() != NULL)
+ {
+ val_type_size = val_type->integer_type()->bits();
+ val_is_unsigned = val_type->integer_type()->is_unsigned();
+ }
+ else
+ {
+ if (!val_type->is_numeric_type()
+ || !Type::are_convertible(bound_type, val_type, NULL))
+ {
+ go_assert(saw_errors());
+ return Expression::make_boolean(true, loc);
+ }
+
+ if (val_type->complex_type() != NULL)
+ val_type_size = val_type->complex_type()->bits();
+ else
+ val_type_size = val_type->float_type()->bits();
+ }
- if (!TYPE_UNSIGNED(val_type))
+ Expression* negative_index = Expression::make_boolean(false, loc);
+ Expression* index_overflows = Expression::make_boolean(false, loc);
+ if (!val_is_unsigned)
{
- ret = fold_build2_loc(loc.gcc_location(), LT_EXPR, boolean_type_node, val,
- build_int_cst(val_type, 0));
- if (ret == boolean_false_node)
- ret = NULL_TREE;
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0UL);
+ Expression* zero = Expression::make_integer(&zval, val_type, loc);
+ mpz_clear(zval);
+
+ negative_index = Expression::make_binary(OPERATOR_LT, val, zero, loc);
}
- HOST_WIDE_INT val_type_size = int_size_in_bytes(val_type);
- HOST_WIDE_INT bound_type_size = int_size_in_bytes(bound_type);
- go_assert(val_type_size != -1 && bound_type_size != -1);
+ int bound_type_size = bound_type->integer_type()->bits();
if (val_type_size > bound_type_size
|| (val_type_size == bound_type_size
- && TYPE_UNSIGNED(val_type)
- && !TYPE_UNSIGNED(bound_type)))
- {
- tree max = TYPE_MAX_VALUE(bound_type);
- tree big = fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node,
- val, fold_convert_loc(loc.gcc_location(),
- val_type, max));
- if (big == boolean_false_node)
- ;
- else if (ret == NULL_TREE)
- ret = big;
- else
- ret = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, ret, big);
+ && val_is_unsigned))
+ {
+ mpz_t one;
+ mpz_init_set_ui(one, 1UL);
+
+ // maxval = 2^(bound_type_size - 1) - 1
+ mpz_t maxval;
+ mpz_init(maxval);
+ mpz_mul_2exp(maxval, one, bound_type_size - 1);
+ mpz_sub_ui(maxval, maxval, 1);
+ Expression* max = Expression::make_integer(&maxval, val_type, loc);
+ mpz_clear(one);
+ mpz_clear(maxval);
+
+ index_overflows = Expression::make_binary(OPERATOR_GT, val, max, loc);
}
- if (ret == NULL_TREE)
- return sofar;
- else if (sofar == NULL_TREE)
- return ret;
- else
- return fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node,
- sofar, ret);
+ return Expression::make_binary(OPERATOR_OROR, negative_index, index_overflows,
+ loc);
}
void
@@ -1719,7 +1529,23 @@ String_expression::do_determine_type(const Type_context* context)
tree
String_expression::do_get_tree(Translate_context* context)
{
- return context->gogo()->go_string_constant_tree(this->val_);
+ Gogo* gogo = context->gogo();
+ Btype* btype = Type::make_string_type()->get_backend(gogo);
+
+ Location loc = this->location();
+ std::vector<Bexpression*> init(2);
+ Bexpression* str_cst =
+ gogo->backend()->string_constant_expression(this->val_);
+ init[0] = gogo->backend()->address_expression(str_cst, loc);
+
+ Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+ mpz_t lenval;
+ mpz_init_set_ui(lenval, this->val_.length());
+ init[1] = gogo->backend()->integer_constant_expression(int_btype, lenval);
+ mpz_clear(lenval);
+
+ Bexpression* ret = gogo->backend()->constructor_expression(btype, init, loc);
+ return expr_to_tree(ret);
}
// Write string literal to string dump.
@@ -1826,6 +1652,116 @@ Expression::make_string(const std::string& val, Location location)
return new String_expression(val, location);
}
+// An expression that evaluates to some characteristic of a string.
+// This is used when indexing, bound-checking, or nil checking a string.
+
+class String_info_expression : public Expression
+{
+ public:
+ String_info_expression(Expression* string, String_info string_info,
+ Location location)
+ : Expression(EXPRESSION_STRING_INFO, location),
+ string_(string), string_info_(string_info)
+ { }
+
+ protected:
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new String_info_expression(this->string_->copy(), this->string_info_,
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ void
+ do_issue_nil_check()
+ { this->string_->issue_nil_check(); }
+
+ private:
+ // The string for which we are getting information.
+ Expression* string_;
+ // What information we want.
+ String_info string_info_;
+};
+
+// Return the type of the string info.
+
+Type*
+String_info_expression::do_type()
+{
+ switch (this->string_info_)
+ {
+ case STRING_INFO_DATA:
+ {
+ Type* byte_type = Type::lookup_integer_type("uint8");
+ return Type::make_pointer_type(byte_type);
+ }
+ case STRING_INFO_LENGTH:
+ return Type::lookup_integer_type("int");
+ default:
+ go_unreachable();
+ }
+}
+
+// Return string information in GENERIC.
+
+tree
+String_info_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+
+ Bexpression* bstring = tree_to_expr(this->string_->get_tree(context));
+ Bexpression* ret;
+ switch (this->string_info_)
+ {
+ case STRING_INFO_DATA:
+ case STRING_INFO_LENGTH:
+ ret = gogo->backend()->struct_field_expression(bstring, this->string_info_,
+ this->location());
+ break;
+ default:
+ go_unreachable();
+ }
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation for a type info expression.
+
+void
+String_info_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "stringinfo(";
+ this->string_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ",";
+ ast_dump_context->ostream() <<
+ (this->string_info_ == STRING_INFO_DATA ? "data"
+ : this->string_info_ == STRING_INFO_LENGTH ? "length"
+ : "unknown");
+ ast_dump_context->ostream() << ")";
+}
+
+// Make a string info expression.
+
+Expression*
+Expression::make_string_info(Expression* string, String_info string_info,
+ Location location)
+{
+ return new String_info_expression(string, string_info, location);
+}
+
// Make an integer expression.
class Integer_expression : public Expression
@@ -2826,16 +2762,8 @@ Const_expression::do_check_types(Gogo*)
tree
Const_expression::do_get_tree(Translate_context* context)
{
- Gogo* gogo = context->gogo();
- tree type_tree;
- if (this->type_ == NULL)
- type_tree = NULL_TREE;
- else
- {
- type_tree = type_to_tree(this->type_->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
- }
+ if (this->type_ != NULL && this->type_->is_error())
+ return error_mark_node;
// If the type has been set for this expression, but the underlying
// object is an abstract int or float, we try to get the abstract
@@ -2855,24 +2783,15 @@ Const_expression::do_get_tree(Translate_context* context)
}
}
- tree const_tree = this->constant_->get_tree(gogo, context->function());
- if (this->type_ == NULL
- || const_tree == error_mark_node
- || TREE_TYPE(const_tree) == error_mark_node)
- return const_tree;
-
- tree ret;
- if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(const_tree)))
- ret = fold_convert(type_tree, const_tree);
- else if (TREE_CODE(type_tree) == INTEGER_TYPE)
- ret = fold(convert_to_integer(type_tree, const_tree));
- else if (TREE_CODE(type_tree) == REAL_TYPE)
- ret = fold(convert_to_real(type_tree, const_tree));
- else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
- ret = fold(convert_to_complex(type_tree, const_tree));
- else
- go_unreachable();
- return ret;
+ Gogo* gogo = context->gogo();
+ Bexpression* ret =
+ tree_to_expr(this->constant_->get_tree(gogo, context->function()));
+ if (this->type_ != NULL)
+ {
+ Btype* btype = this->type_->get_backend(gogo);
+ ret = gogo->backend()->convert_expression(btype, ret, this->location());
+ }
+ return expr_to_tree(ret);
}
// Dump ast representation for constant expression.
@@ -3221,8 +3140,10 @@ Expression*
Type_conversion_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- if (this->type()->is_string_type()
- && this->expr_->type()->is_slice_type()
+ if (((this->type()->is_string_type()
+ && this->expr_->type()->is_slice_type())
+ || (this->type()->interface_type() != NULL
+ && this->expr_->type()->interface_type() != NULL))
&& !this->expr_->is_variable())
{
Temporary_statement* temp =
@@ -3325,73 +3246,50 @@ Type_conversion_expression::do_check_types(Gogo*)
tree
Type_conversion_expression::do_get_tree(Translate_context* context)
{
- Gogo* gogo = context->gogo();
- tree type_tree = type_to_tree(this->type_->get_backend(gogo));
- tree expr_tree = this->expr_->get_tree(context);
-
- if (type_tree == error_mark_node
- || expr_tree == error_mark_node
- || TREE_TYPE(expr_tree) == error_mark_node)
- return error_mark_node;
-
- if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree)))
- return fold_convert(type_tree, expr_tree);
-
Type* type = this->type_;
Type* expr_type = this->expr_->type();
- tree ret;
- if (type->interface_type() != NULL || expr_type->interface_type() != NULL)
- ret = Expression::convert_for_assignment(context, type, expr_type,
- expr_tree, this->location());
- else if (type->integer_type() != NULL)
- {
- if (expr_type->integer_type() != NULL
- || expr_type->float_type() != NULL
- || expr_type->is_unsafe_pointer_type())
- ret = fold(convert_to_integer(type_tree, expr_tree));
- else
- go_unreachable();
- }
- else if (type->float_type() != NULL)
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = type->get_backend(gogo);
+ Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+ Location loc = this->location();
+
+ if (Type::are_identical(type, expr_type, false, NULL))
{
- if (expr_type->integer_type() != NULL
- || expr_type->float_type() != NULL)
- ret = fold(convert_to_real(type_tree, expr_tree));
- else
- go_unreachable();
+ Bexpression* bconvert =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(bconvert);
}
- else if (type->complex_type() != NULL)
+ else if (type->interface_type() != NULL
+ || expr_type->interface_type() != NULL)
{
- if (expr_type->complex_type() != NULL)
- ret = fold(convert_to_complex(type_tree, expr_tree));
- else
- go_unreachable();
+ Expression* conversion =
+ Expression::convert_for_assignment(gogo, type, this->expr_,
+ this->location());
+ return conversion->get_tree(context);
}
else if (type->is_string_type()
&& expr_type->integer_type() != NULL)
{
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
- expr_tree = fold_convert(int_type_tree, expr_tree);
- if (tree_fits_shwi_p (expr_tree))
+ mpz_t intval;
+ Numeric_constant nc;
+ if (this->expr_->numeric_constant_value(&nc)
+ && nc.to_int(&intval)
+ && mpz_fits_ushort_p(intval))
{
- HOST_WIDE_INT intval = tree_to_shwi (expr_tree);
std::string s;
- Lex::append_char(intval, true, &s, this->location());
- Expression* se = Expression::make_string(s, this->location());
+ Lex::append_char(mpz_get_ui(intval), true, &s, loc);
+ mpz_clear(intval);
+ Expression* se = Expression::make_string(s, loc);
return se->get_tree(context);
}
Expression* i2s_expr =
- Runtime::make_call(Runtime::INT_TO_STRING, this->location(), 1,
- this->expr_);
- i2s_expr = Expression::make_cast(type, i2s_expr, this->location());
- ret = i2s_expr->get_tree(context);
+ Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_);
+ return Expression::make_cast(type, i2s_expr, loc)->get_tree(context);
}
else if (type->is_string_type() && expr_type->is_slice_type())
{
- Location location = this->location();
Array_type* a = expr_type->array_type();
Type* e = a->element_type()->forwarded();
go_assert(e->integer_type() != NULL);
@@ -3407,46 +3305,50 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
}
Expression* valptr = a->get_value_pointer(gogo, this->expr_);
Expression* len = a->get_length(gogo, this->expr_);
- Expression* a2s_expr = Runtime::make_call(code, location, 2, valptr, len);
- ret = a2s_expr->get_tree(context);
+ return Runtime::make_call(code, loc, 2, valptr, len)->get_tree(context);
}
else if (type->is_slice_type() && expr_type->is_string_type())
{
Type* e = type->array_type()->element_type()->forwarded();
go_assert(e->integer_type() != NULL);
- Expression* s2a_expr;
+ Runtime::Function code;
if (e->integer_type()->is_byte())
- s2a_expr = Runtime::make_call(Runtime::STRING_TO_BYTE_ARRAY,
- this->location(), 1, this->expr_);
+ code = Runtime::STRING_TO_BYTE_ARRAY;
else
{
go_assert(e->integer_type()->is_rune());
- s2a_expr = Runtime::make_call(Runtime::STRING_TO_INT_ARRAY,
- this->location(), 1, this->expr_);
+ code = Runtime::STRING_TO_INT_ARRAY;
}
- s2a_expr = Expression::make_unsafe_cast(type, s2a_expr,
- this->location());
- ret = s2a_expr->get_tree(context);
+ Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_);
+ return Expression::make_unsafe_cast(type, s2a, loc)->get_tree(context);
+ }
+ else if (type->is_numeric_type())
+ {
+ go_assert(Type::are_convertible(type, expr_type, NULL));
+ Bexpression* bconvert =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(bconvert);
}
else if ((type->is_unsafe_pointer_type()
- && expr_type->points_to() != NULL)
- || (expr_type->is_unsafe_pointer_type()
- && type->points_to() != NULL))
- ret = fold_convert(type_tree, expr_tree);
- else if (type->is_unsafe_pointer_type()
- && expr_type->integer_type() != NULL)
- ret = convert_to_pointer(type_tree, expr_tree);
- else if (this->may_convert_function_types_
- && type->function_type() != NULL
- && expr_type->function_type() != NULL)
- ret = fold_convert_loc(this->location().gcc_location(), type_tree,
- expr_tree);
+ && (expr_type->points_to() != NULL
+ || expr_type->integer_type()))
+ || (expr_type->is_unsafe_pointer_type()
+ && type->points_to() != NULL)
+ || (this->may_convert_function_types_
+ && type->function_type() != NULL
+ && expr_type->function_type() != NULL))
+ {
+ Bexpression* bconvert =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(bconvert);
+ }
else
- ret = Expression::convert_for_assignment(context, type, expr_type,
- expr_tree, this->location());
-
- return ret;
+ {
+ Expression* conversion =
+ Expression::convert_for_assignment(gogo, type, this->expr_, loc);
+ return conversion->get_tree(context);
+ }
}
// Output a type conversion in a constant expression.
@@ -3560,58 +3462,57 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
Type* t = this->type_;
Type* et = this->expr_->type();
-
- tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
- tree expr_tree = this->expr_->get_tree(context);
- if (type_tree == error_mark_node || expr_tree == error_mark_node)
- return error_mark_node;
-
- Location loc = this->location();
-
- bool use_view_convert = false;
- if (t->is_slice_type())
+ if (t->array_type() != NULL)
+ go_assert(et->array_type() != NULL
+ && t->is_slice_type() == et->is_slice_type());
+ else if (t->struct_type() != NULL)
{
- go_assert(et->is_slice_type());
- use_view_convert = true;
+ if (t->named_type() != NULL
+ && et->named_type() != NULL
+ && !Type::are_convertible(t, et, NULL))
+ {
+ go_assert(saw_errors());
+ return error_mark_node;
+ }
+
+ go_assert(et->struct_type() != NULL
+ && Type::are_convertible(t, et, NULL));
}
else if (t->map_type() != NULL)
go_assert(et->map_type() != NULL);
else if (t->channel_type() != NULL)
go_assert(et->channel_type() != NULL);
else if (t->points_to() != NULL)
- go_assert(et->points_to() != NULL || et->is_nil_type());
+ go_assert(et->points_to() != NULL
+ || et->channel_type() != NULL
+ || et->map_type() != NULL
+ || et->function_type() != NULL
+ || et->is_nil_type());
else if (et->is_unsafe_pointer_type())
go_assert(t->points_to() != NULL);
- else if (t->interface_type() != NULL && !t->interface_type()->is_empty())
- {
- go_assert(et->interface_type() != NULL
- && !et->interface_type()->is_empty());
- use_view_convert = true;
- }
- else if (t->interface_type() != NULL && t->interface_type()->is_empty())
+ else if (t->interface_type() != NULL)
{
+ bool empty_iface = t->interface_type()->is_empty();
go_assert(et->interface_type() != NULL
- && et->interface_type()->is_empty());
- use_view_convert = true;
+ && et->interface_type()->is_empty() == empty_iface);
}
else if (t->integer_type() != NULL)
- {
- go_assert(et->is_boolean_type()
- || et->integer_type() != NULL
- || et->function_type() != NULL
- || et->points_to() != NULL
- || et->map_type() != NULL
- || et->channel_type() != NULL);
- return convert_to_integer(type_tree, expr_tree);
- }
+ go_assert(et->is_boolean_type()
+ || et->integer_type() != NULL
+ || et->function_type() != NULL
+ || et->points_to() != NULL
+ || et->map_type() != NULL
+ || et->channel_type() != NULL);
else
go_unreachable();
- if (use_view_convert)
- return fold_build1_loc(loc.gcc_location(), VIEW_CONVERT_EXPR, type_tree,
- expr_tree);
- else
- return fold_convert_loc(loc.gcc_location(), type_tree, expr_tree);
+ Gogo* gogo = context->gogo();
+ Btype* btype = t->get_backend(gogo);
+ Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+ Location loc = this->location();
+ Bexpression* ret =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for an unsafe type conversion expression.
@@ -3757,7 +3658,7 @@ class Unary_expression : public Expression
};
// If we are taking the address of a composite literal, and the
-// contents are not constant, then we want to make a heap composite
+// contents are not constant, then we want to make a heap expression
// instead.
Expression*
@@ -4758,9 +4659,19 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
{
case OPERATOR_PLUS:
mpz_add(val, left_val, right_val);
+ if (mpz_sizeinbase(val, 2) > 0x100000)
+ {
+ error_at(location, "constant addition overflow");
+ mpz_set_ui(val, 1);
+ }
break;
case OPERATOR_MINUS:
mpz_sub(val, left_val, right_val);
+ if (mpz_sizeinbase(val, 2) > 0x100000)
+ {
+ error_at(location, "constant subtraction overflow");
+ mpz_set_ui(val, 1);
+ }
break;
case OPERATOR_OR:
mpz_ior(val, left_val, right_val);
@@ -4770,6 +4681,11 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
break;
case OPERATOR_MULT:
mpz_mul(val, left_val, right_val);
+ if (mpz_sizeinbase(val, 2) > 0x100000)
+ {
+ error_at(location, "constant multiplication overflow");
+ mpz_set_ui(val, 1);
+ }
break;
case OPERATOR_DIV:
if (mpz_sgn(right_val) != 0)
@@ -4797,7 +4713,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
else
{
error_at(location, "shift count overflow");
- mpz_set_ui(val, 0);
+ mpz_set_ui(val, 1);
}
break;
}
@@ -4808,7 +4724,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
if (mpz_cmp_ui(right_val, shift) != 0)
{
error_at(location, "shift count overflow");
- mpz_set_ui(val, 0);
+ mpz_set_ui(val, 1);
}
else
{
@@ -6888,7 +6804,7 @@ Bound_method_expression::do_get_tree(Translate_context* context)
vals->push_back(val);
Expression* ret = Expression::make_struct_composite_literal(st, vals, loc);
- ret = Expression::make_heap_composite(ret, loc);
+ ret = Expression::make_heap_expression(ret, loc);
tree ret_tree = ret->get_tree(context);
@@ -7776,27 +7692,33 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
return false;
if (arg_type->is_abstract())
return false;
+ if (this->seen_)
+ return false;
unsigned int ret;
if (this->code_ == BUILTIN_SIZEOF)
{
- if (!arg_type->backend_type_size(this->gogo_, &ret))
+ this->seen_ = true;
+ bool ok = arg_type->backend_type_size(this->gogo_, &ret);
+ this->seen_ = false;
+ if (!ok)
return false;
}
else if (this->code_ == BUILTIN_ALIGNOF)
{
+ bool ok;
+ this->seen_ = true;
if (arg->field_reference_expression() == NULL)
- {
- if (!arg_type->backend_type_align(this->gogo_, &ret))
- return false;
- }
+ ok = arg_type->backend_type_align(this->gogo_, &ret);
else
{
// Calling unsafe.Alignof(s.f) returns the alignment of
// the type of f when it is used as a field in a struct.
- if (!arg_type->backend_type_field_align(this->gogo_, &ret))
- return false;
+ ok = arg_type->backend_type_field_align(this->gogo_, &ret);
}
+ this->seen_ = false;
+ if (!ok)
+ return false;
}
else
go_unreachable();
@@ -7813,6 +7735,9 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
Field_reference_expression* farg = arg->field_reference_expression();
if (farg == NULL)
return false;
+ if (this->seen_)
+ return false;
+
unsigned int total_offset = 0;
while (true)
{
@@ -7823,10 +7748,13 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
if (st->named_type() != NULL)
st->named_type()->convert(this->gogo_);
unsigned int offset;
- if (!st->struct_type()->backend_field_offset(this->gogo_,
- farg->field_index(),
- &offset))
- return false;
+ this->seen_ = true;
+ bool ok = st->struct_type()->backend_field_offset(this->gogo_,
+ farg->field_index(),
+ &offset);
+ this->seen_ = false;
+ if (!ok)
+ return false;
total_offset += offset;
if (farg->implicit() && struct_expr->field_reference_expression() != NULL)
{
@@ -8439,7 +8367,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
{
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 1);
- Expression* arg = *args->begin();
+ Expression* arg = args->front();
Type* arg_type = arg->type();
if (this->seen_)
@@ -8448,31 +8376,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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;
-
if (arg_type->points_to() != NULL)
{
arg_type = arg_type->points_to();
go_assert(arg_type->array_type() != NULL
&& !arg_type->is_slice_type());
- go_assert(POINTER_TYPE_P(TREE_TYPE(arg_tree)));
- arg_tree = build_fold_indirect_ref(arg_tree);
+ arg = Expression::make_unary(OPERATOR_MULT, arg, location);
}
Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
- tree val_tree;
+ Expression* val;
if (this->code_ == BUILTIN_LEN)
{
if (arg_type->is_string_type())
- val_tree = String_type::length_tree(gogo, arg_tree);
+ val = Expression::make_string_info(arg, STRING_INFO_LENGTH,
+ location);
else if (arg_type->array_type() != NULL)
{
if (this->seen_)
@@ -8481,34 +8400,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
this->seen_ = true;
- Expression* len = arg_type->array_type()->get_length(gogo, arg);
- val_tree = len->get_tree(context);
+ val = arg_type->array_type()->get_length(gogo, arg);
this->seen_ = false;
}
else if (arg_type->map_type() != NULL)
- {
- tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
- static tree map_len_fndecl;
- val_tree = Gogo::call_builtin(&map_len_fndecl,
- location,
- "__go_map_len",
- 1,
- int_type_tree,
- arg_type_tree,
- arg_tree);
- }
+ val = Runtime::make_call(Runtime::MAP_LEN, location, 1, arg);
else if (arg_type->channel_type() != NULL)
- {
- tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
- static tree chan_len_fndecl;
- val_tree = Gogo::call_builtin(&chan_len_fndecl,
- location,
- "__go_chan_len",
- 1,
- int_type_tree,
- arg_type_tree,
- arg_tree);
- }
+ val = Runtime::make_call(Runtime::CHAN_LEN, location, 1, arg);
else
go_unreachable();
}
@@ -8522,36 +8420,24 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
this->seen_ = true;
- Expression* cap =
- arg_type->array_type()->get_capacity(gogo, arg);
- val_tree = cap->get_tree(context);
+ val = arg_type->array_type()->get_capacity(gogo, arg);
this->seen_ = false;
}
else if (arg_type->channel_type() != NULL)
- {
- tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
- static tree chan_cap_fndecl;
- val_tree = Gogo::call_builtin(&chan_cap_fndecl,
- location,
- "__go_chan_cap",
- 1,
- int_type_tree,
- arg_type_tree,
- arg_tree);
- }
+ val = Runtime::make_call(Runtime::CHAN_CAP, location, 1, arg);
else
go_unreachable();
}
- return fold_convert_loc(location.gcc_location(), int_type_tree,
- val_tree);
+ return Expression::make_cast(int_type, val,
+ location)->get_tree(context);
}
case BUILTIN_PRINT:
case BUILTIN_PRINTLN:
{
const bool is_ln = this->code_ == BUILTIN_PRINTLN;
- tree stmt_list = NULL_TREE;
+ Expression* print_stmts = NULL;
const Expression_list* call_args = this->args();
if (call_args != NULL)
@@ -8562,139 +8448,91 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
{
if (is_ln && p != call_args->begin())
{
- static tree print_space_fndecl;
- tree call = Gogo::call_builtin(&print_space_fndecl,
- location,
- "__go_print_space",
- 0,
- void_type_node);
- if (call == error_mark_node)
- return error_mark_node;
- append_to_statement_list(call, &stmt_list);
- }
-
- Type* type = (*p)->type();
+ Expression* print_space =
+ Runtime::make_call(Runtime::PRINT_SPACE,
+ this->location(), 0);
- tree arg = (*p)->get_tree(context);
- if (arg == error_mark_node)
- return error_mark_node;
+ print_stmts =
+ Expression::make_compound(print_stmts, print_space,
+ location);
+ }
- tree* pfndecl;
- const char* fnname;
+ Expression* arg = *p;
+ Type* type = arg->type();
+ Runtime::Function code;
if (type->is_string_type())
- {
- static tree print_string_fndecl;
- pfndecl = &print_string_fndecl;
- fnname = "__go_print_string";
- }
+ code = Runtime::PRINT_STRING;
else if (type->integer_type() != NULL
&& type->integer_type()->is_unsigned())
{
- static tree print_uint64_fndecl;
- pfndecl = &print_uint64_fndecl;
- fnname = "__go_print_uint64";
Type* itype = Type::lookup_integer_type("uint64");
- Btype* bitype = itype->get_backend(gogo);
- arg = fold_convert_loc(location.gcc_location(),
- type_to_tree(bitype), arg);
+ arg = Expression::make_cast(itype, arg, location);
+ code = Runtime::PRINT_UINT64;
}
else if (type->integer_type() != NULL)
{
- static tree print_int64_fndecl;
- pfndecl = &print_int64_fndecl;
- fnname = "__go_print_int64";
Type* itype = Type::lookup_integer_type("int64");
- Btype* bitype = itype->get_backend(gogo);
- arg = fold_convert_loc(location.gcc_location(),
- type_to_tree(bitype), arg);
+ arg = Expression::make_cast(itype, arg, location);
+ code = Runtime::PRINT_INT64;
}
else if (type->float_type() != NULL)
{
- static tree print_double_fndecl;
- pfndecl = &print_double_fndecl;
- fnname = "__go_print_double";
- arg = fold_convert_loc(location.gcc_location(),
- double_type_node, arg);
+ Type* dtype = Type::lookup_float_type("float64");
+ arg = Expression::make_cast(dtype, arg, location);
+ code = Runtime::PRINT_DOUBLE;
}
else if (type->complex_type() != NULL)
{
- static tree print_complex_fndecl;
- pfndecl = &print_complex_fndecl;
- fnname = "__go_print_complex";
- arg = fold_convert_loc(location.gcc_location(),
- complex_double_type_node, arg);
+ Type* ctype = Type::lookup_complex_type("complex128");
+ arg = Expression::make_cast(ctype, arg, location);
+ code = Runtime::PRINT_COMPLEX;
}
else if (type->is_boolean_type())
- {
- static tree print_bool_fndecl;
- pfndecl = &print_bool_fndecl;
- fnname = "__go_print_bool";
- }
+ code = Runtime::PRINT_BOOL;
else if (type->points_to() != NULL
|| type->channel_type() != NULL
|| type->map_type() != NULL
|| type->function_type() != NULL)
{
- static tree print_pointer_fndecl;
- pfndecl = &print_pointer_fndecl;
- fnname = "__go_print_pointer";
- arg = fold_convert_loc(location.gcc_location(),
- ptr_type_node, arg);
+ arg = Expression::make_cast(type, arg, location);
+ code = Runtime::PRINT_POINTER;
}
else if (type->interface_type() != NULL)
{
if (type->interface_type()->is_empty())
- {
- static tree print_empty_interface_fndecl;
- pfndecl = &print_empty_interface_fndecl;
- fnname = "__go_print_empty_interface";
- }
+ code = Runtime::PRINT_EMPTY_INTERFACE;
else
- {
- static tree print_interface_fndecl;
- pfndecl = &print_interface_fndecl;
- fnname = "__go_print_interface";
- }
+ code = Runtime::PRINT_INTERFACE;
}
else if (type->is_slice_type())
- {
- static tree print_slice_fndecl;
- pfndecl = &print_slice_fndecl;
- fnname = "__go_print_slice";
- }
+ code = Runtime::PRINT_SLICE;
else
{
go_assert(saw_errors());
return error_mark_node;
}
- tree call = Gogo::call_builtin(pfndecl,
- location,
- fnname,
- 1,
- void_type_node,
- TREE_TYPE(arg),
- arg);
- if (call == error_mark_node)
- return error_mark_node;
- append_to_statement_list(call, &stmt_list);
+ Expression* call = Runtime::make_call(code, location, 1, arg);
+ if (print_stmts == NULL)
+ print_stmts = call;
+ else
+ print_stmts = Expression::make_compound(print_stmts, call,
+ location);
}
}
if (is_ln)
{
- static tree print_nl_fndecl;
- tree call = Gogo::call_builtin(&print_nl_fndecl,
- location,
- "__go_print_nl",
- 0,
- void_type_node);
- if (call == error_mark_node)
- return error_mark_node;
- append_to_statement_list(call, &stmt_list);
+ Expression* print_nl =
+ Runtime::make_call(Runtime::PRINT_NL, location, 0);
+ if (print_stmts == NULL)
+ print_stmts = print_nl;
+ else
+ print_stmts = Expression::make_compound(print_stmts, print_nl,
+ location);
}
- return stmt_list;
+ return print_stmts->get_tree(context);
}
case BUILTIN_PANIC:
@@ -8702,29 +8540,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 1);
Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
Type *empty =
Type::make_empty_interface_type(Linemap::predeclared_location());
- arg_tree = Expression::convert_for_assignment(context, empty,
- arg->type(),
- arg_tree, location);
- static tree panic_fndecl;
- tree call = Gogo::call_builtin(&panic_fndecl,
- location,
- "__go_panic",
- 1,
- void_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
- if (call == error_mark_node)
- return error_mark_node;
- // This function will throw an exception.
- TREE_NOTHROW(panic_fndecl) = 0;
- // This function will not return.
- TREE_THIS_VOLATILE(panic_fndecl) = 1;
- return call;
+ arg = Expression::convert_for_assignment(gogo, empty, arg, location);
+
+ Expression* panic =
+ Runtime::make_call(Runtime::PANIC, location, 1, arg);
+ return panic->get_tree(context);
}
case BUILTIN_RECOVER:
@@ -8734,49 +8556,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 1);
Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
-
Type *empty =
Type::make_empty_interface_type(Linemap::predeclared_location());
- tree empty_tree = type_to_tree(empty->get_backend(context->gogo()));
- Type* nil_type = Type::make_nil_type();
Expression* nil = Expression::make_nil(location);
- tree nil_tree = nil->get_tree(context);
- tree empty_nil_tree = Expression::convert_for_assignment(context,
- empty,
- nil_type,
- nil_tree,
- location);
+ nil = Expression::convert_for_assignment(gogo, empty, nil, location);
// We need to handle a deferred call to recover specially,
// because it changes whether it can recover a panic or not.
// See test7 in test/recover1.go.
- tree call;
- if (this->is_deferred())
- {
- static tree deferred_recover_fndecl;
- call = Gogo::call_builtin(&deferred_recover_fndecl,
- location,
- "__go_deferred_recover",
- 0,
- empty_tree);
- }
- else
- {
- static tree recover_fndecl;
- call = Gogo::call_builtin(&recover_fndecl,
- location,
- "__go_recover",
- 0,
- empty_tree);
- }
- if (call == error_mark_node)
- return error_mark_node;
- return fold_build3_loc(location.gcc_location(), COND_EXPR, empty_tree,
- arg_tree, call, empty_nil_tree);
+ Expression* recover = Runtime::make_call((this->is_deferred()
+ ? Runtime::DEFERRED_RECOVER
+ : Runtime::RECOVER),
+ location, 0);
+ Expression* cond =
+ Expression::make_conditional(arg, recover, nil, location);
+ return cond->get_tree(context);
}
case BUILTIN_CLOSE:
@@ -8784,17 +8579,9 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 1);
Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
- static tree close_fndecl;
- return Gogo::call_builtin(&close_fndecl,
- location,
- "__go_builtin_close",
- 1,
- void_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
+ Expression* close = Runtime::make_call(Runtime::CLOSE, location,
+ 1, arg);
+ return close->get_tree(context);
}
case BUILTIN_SIZEOF:
@@ -8810,8 +8597,12 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
Type* uintptr_type = Type::lookup_integer_type("uintptr");
- tree type = type_to_tree(uintptr_type->get_backend(gogo));
- return build_int_cst(type, val);
+ mpz_t ival;
+ nc.get_int(&ival);
+ Expression* int_cst =
+ Expression::make_integer(&ival, uintptr_type, location);
+ mpz_clear(ival);
+ return int_cst->get_tree(context);
}
case BUILTIN_COPY:
@@ -8821,88 +8612,51 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
Expression* arg1 = args->front();
Expression* arg2 = args->back();
- tree arg1_tree = arg1->get_tree(context);
- tree arg2_tree = arg2->get_tree(context);
- if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
- return error_mark_node;
-
Type* arg1_type = arg1->type();
Array_type* at = arg1_type->array_type();
go_assert(arg1->is_variable());
- Expression* arg1_valptr = at->get_value_pointer(gogo, arg1);
- Expression* arg1_len_expr = at->get_length(gogo, arg1);
- tree arg1_val = arg1_valptr->get_tree(context);
- tree arg1_len = arg1_len_expr->get_tree(context);
- if (arg1_val == error_mark_node || arg1_len == error_mark_node)
- return error_mark_node;
+ Expression* arg1_val = at->get_value_pointer(gogo, arg1);
+ Expression* arg1_len = at->get_length(gogo, arg1);
Type* arg2_type = arg2->type();
- tree arg2_val;
- tree arg2_len;
+ go_assert(arg2->is_variable());
+ Expression* arg2_val;
+ Expression* arg2_len;
if (arg2_type->is_slice_type())
{
at = arg2_type->array_type();
- go_assert(arg2->is_variable());
- Expression* arg2_valptr = at->get_value_pointer(gogo, arg2);
- Expression* arg2_len_expr = at->get_length(gogo, arg2);
- arg2_val = arg2_valptr->get_tree(context);
- arg2_len = arg2_len_expr->get_tree(context);
+ arg2_val = at->get_value_pointer(gogo, arg2);
+ arg2_len = at->get_length(gogo, arg2);
}
else
{
- arg2_tree = save_expr(arg2_tree);
- arg2_val = String_type::bytes_tree(gogo, arg2_tree);
- arg2_len = String_type::length_tree(gogo, arg2_tree);
+ 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);
}
- if (arg2_val == error_mark_node || arg2_len == error_mark_node)
- return error_mark_node;
-
- arg1_len = save_expr(arg1_len);
- arg2_len = save_expr(arg2_len);
- tree len = fold_build3_loc(location.gcc_location(), COND_EXPR,
- TREE_TYPE(arg1_len),
- fold_build2_loc(location.gcc_location(),
- LT_EXPR, boolean_type_node,
- arg1_len, arg2_len),
- arg1_len, arg2_len);
- len = save_expr(len);
+ 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();
Btype* element_btype = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(element_btype);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- tree element_size = TYPE_SIZE_UNIT(element_type_tree);
- tree bytecount = fold_convert_loc(location.gcc_location(),
- TREE_TYPE(element_size), len);
- bytecount = fold_build2_loc(location.gcc_location(), MULT_EXPR,
- TREE_TYPE(element_size),
- bytecount, element_size);
- bytecount = fold_convert_loc(location.gcc_location(), size_type_node,
- bytecount);
-
- arg1_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
- arg1_val);
- arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
- arg2_val);
-
- static tree copy_fndecl;
- tree call = Gogo::call_builtin(&copy_fndecl,
- location,
- "__go_copy",
- 3,
- void_type_node,
- ptr_type_node,
- arg1_val,
- ptr_type_node,
- arg2_val,
- size_type_node,
- bytecount);
- if (call == error_mark_node)
- return error_mark_node;
- return fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(len), call, len);
+ mpz_t size;
+ size_t element_size = gogo->backend()->type_size(element_btype);
+ mpz_init_set_ui(size, element_size);
+ Expression* size_expr = Expression::make_integer(&size, length->type(), location);
+ mpz_clear(size);
+
+ 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_tree(context);
}
case BUILTIN_APPEND:
@@ -8912,67 +8666,40 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
Expression* arg1 = args->front();
Expression* arg2 = args->back();
- tree arg1_tree = arg1->get_tree(context);
- tree arg2_tree = arg2->get_tree(context);
- if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
- return error_mark_node;
-
Array_type* at = arg1->type()->array_type();
Type* element_type = at->element_type()->forwarded();
- tree arg2_val;
- tree arg2_len;
- tree element_size;
+ go_assert(arg2->is_variable());
+ Expression* arg2_val;
+ Expression* arg2_len;
+ mpz_t size;
if (arg2->type()->is_string_type()
&& element_type->integer_type() != NULL
&& element_type->integer_type()->is_byte())
{
- arg2_tree = save_expr(arg2_tree);
- arg2_val = String_type::bytes_tree(gogo, arg2_tree);
- arg2_len = String_type::length_tree(gogo, arg2_tree);
- element_size = size_int(1);
+ arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
+ location);
+ arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
+ location);
+ mpz_init_set_ui(size, 1UL);
}
else
{
- go_assert(arg2->is_variable());
- arg2_val =
- at->get_value_pointer(gogo, arg2)->get_tree(context);
- arg2_len = at->get_length(gogo, arg2)->get_tree(context);
+ arg2_val = at->get_value_pointer(gogo, arg2);
+ arg2_len = at->get_length(gogo, arg2);
Btype* element_btype = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(element_btype);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- element_size = TYPE_SIZE_UNIT(element_type_tree);
+ size_t element_size = gogo->backend()->type_size(element_btype);
+ mpz_init_set_ui(size, element_size);
}
-
- arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
- arg2_val);
- arg2_len = fold_convert_loc(location.gcc_location(), size_type_node,
- arg2_len);
- element_size = fold_convert_loc(location.gcc_location(), size_type_node,
- element_size);
-
- if (arg2_val == error_mark_node
- || arg2_len == error_mark_node
- || element_size == error_mark_node)
- return error_mark_node;
-
- // We rebuild the decl each time since the slice types may
- // change.
- tree append_fndecl = NULL_TREE;
- return Gogo::call_builtin(&append_fndecl,
- location,
- "__go_append",
- 4,
- TREE_TYPE(arg1_tree),
- TREE_TYPE(arg1_tree),
- arg1_tree,
- ptr_type_node,
- arg2_val,
- size_type_node,
- arg2_len,
- size_type_node,
- element_size);
+ Expression* element_size =
+ Expression::make_integer(&size, NULL, location);
+ mpz_clear(size);
+
+ 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_tree(context);
}
case BUILTIN_REAL:
@@ -8981,34 +8708,25 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 1);
Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
- go_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree)));
- if (this->code_ == BUILTIN_REAL)
- return fold_build1_loc(location.gcc_location(), REALPART_EXPR,
- TREE_TYPE(TREE_TYPE(arg_tree)),
- arg_tree);
- else
- return fold_build1_loc(location.gcc_location(), IMAGPART_EXPR,
- TREE_TYPE(TREE_TYPE(arg_tree)),
- arg_tree);
+
+ Bexpression* ret;
+ Bexpression* bcomplex = tree_to_expr(arg->get_tree(context));
+ if (this->code_ == BUILTIN_REAL)
+ ret = gogo->backend()->real_part_expression(bcomplex, location);
+ else
+ ret = gogo->backend()->imag_part_expression(bcomplex, location);
+ return expr_to_tree(ret);
}
case BUILTIN_COMPLEX:
{
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 2);
- tree r = args->front()->get_tree(context);
- tree i = args->back()->get_tree(context);
- if (r == error_mark_node || i == error_mark_node)
- return error_mark_node;
- go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r))
- == TYPE_MAIN_VARIANT(TREE_TYPE(i)));
- go_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r)));
- return fold_build2_loc(location.gcc_location(), COMPLEX_EXPR,
- build_complex_type(TREE_TYPE(r)),
- r, i);
+ Bexpression* breal = tree_to_expr(args->front()->get_tree(context));
+ Bexpression* bimag = tree_to_expr(args->back()->get_tree(context));
+ Bexpression* ret =
+ gogo->backend()->complex_expression(breal, bimag, location);
+ return expr_to_tree(ret);
}
default:
@@ -9382,6 +9100,37 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
this->varargs_are_lowered_ = true;
}
+// Flatten a call with multiple results into a temporary.
+
+Expression*
+Call_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter)
+{
+ size_t rc = this->result_count();
+ if (rc > 1 && this->call_temp_ == NULL)
+ {
+ Struct_field_list* sfl = new Struct_field_list();
+ Function_type* fntype = this->get_function_type();
+ const Typed_identifier_list* results = fntype->results();
+ Location loc = this->location();
+
+ int i = 0;
+ char buf[10];
+ for (Typed_identifier_list::const_iterator p = results->begin();
+ p != results->end();
+ ++p, ++i)
+ {
+ snprintf(buf, sizeof buf, "res%d", i);
+ sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc)));
+ }
+
+ Struct_type* st = Type::make_struct_type(sfl, loc);
+ this->call_temp_ = Statement::make_temporary(st, NULL, loc);
+ inserter->insert(this->call_temp_);
+ }
+
+ return this;
+}
+
// Get the function type. This can return NULL in error cases.
Function_type*
@@ -9703,8 +9452,8 @@ Call_expression::interface_method_function(
tree
Call_expression::do_get_tree(Translate_context* context)
{
- if (this->tree_ != NULL_TREE)
- return this->tree_;
+ if (this->call_ != NULL)
+ return expr_to_tree(this->call_);
Function_type* fntype = this->get_function_type();
if (fntype == NULL)
@@ -9733,11 +9482,12 @@ Call_expression::do_get_tree(Translate_context* context)
has_closure_arg = true;
int nargs;
- tree* args;
+ std::vector<Bexpression*> fn_args;
if (this->args_ == NULL || this->args_->empty())
{
nargs = is_interface_method ? 1 : 0;
- args = nargs == 0 ? NULL : new tree[nargs];
+ if (nargs > 0)
+ fn_args.resize(1);
}
else if (fntype->parameters() == NULL || fntype->parameters()->empty())
{
@@ -9746,8 +9496,8 @@ Call_expression::do_get_tree(Translate_context* context)
&& fntype->is_method()
&& this->args_->size() == 1);
nargs = 1;
- args = new tree[nargs];
- args[0] = this->args_->front()->get_tree(context);
+ fn_args.resize(1);
+ fn_args[0] = tree_to_expr(this->args_->front()->get_tree(context));
}
else
{
@@ -9756,239 +9506,138 @@ Call_expression::do_get_tree(Translate_context* context)
nargs = this->args_->size();
int i = is_interface_method ? 1 : 0;
nargs += i;
- args = new tree[nargs];
+ fn_args.resize(nargs);
Typed_identifier_list::const_iterator pp = params->begin();
Expression_list::const_iterator pe = this->args_->begin();
if (!is_interface_method && fntype->is_method())
{
- args[i] = (*pe)->get_tree(context);
+ fn_args[i] = tree_to_expr((*pe)->get_tree(context));
++pe;
++i;
}
for (; pe != this->args_->end(); ++pe, ++pp, ++i)
{
go_assert(pp != params->end());
- tree arg_val = (*pe)->get_tree(context);
- args[i] = Expression::convert_for_assignment(context,
- pp->type(),
- (*pe)->type(),
- arg_val,
- location);
- if (args[i] == error_mark_node)
- return error_mark_node;
+ Expression* arg =
+ Expression::convert_for_assignment(gogo, pp->type(), *pe,
+ location);
+ fn_args[i] = tree_to_expr(arg->get_tree(context));
}
go_assert(pp == params->end());
go_assert(i == nargs);
}
- tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
- tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo));
- if (fntype_tree == error_mark_node || fnfield_type == error_mark_node)
- return error_mark_node;
- go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
- tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
- if (rettype == error_mark_node)
- return error_mark_node;
-
- tree fn;
- tree closure_tree;
+ Expression* fn;
+ Expression* closure = NULL;
if (func != NULL)
{
Named_object* no = func->named_object();
- fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location));
- if (!has_closure)
- closure_tree = NULL_TREE;
- else
- {
- closure_tree = func->closure()->get_tree(context);
- if (closure_tree == error_mark_node)
- return error_mark_node;
- }
+ fn = Expression::make_func_code_reference(no, location);
+ if (has_closure)
+ closure = func->closure();
}
else if (!is_interface_method)
{
- closure_tree = this->fn_->get_tree(context);
- if (closure_tree == error_mark_node)
- return error_mark_node;
- tree fnc = fold_convert_loc(location.gcc_location(), fntype_tree,
- closure_tree);
- go_assert(POINTER_TYPE_P(TREE_TYPE(fnc))
- && (TREE_CODE(TREE_TYPE(TREE_TYPE(fnc)))
- == RECORD_TYPE));
- tree field = TYPE_FIELDS(TREE_TYPE(TREE_TYPE(fnc)));
- fn = fold_build3_loc(location.gcc_location(), COMPONENT_REF,
- TREE_TYPE(field),
- build_fold_indirect_ref_loc(location.gcc_location(),
- fnc),
- field, NULL_TREE);
- }
+ closure = this->fn_;
+
+ // The backend representation of this function type is a pointer
+ // to a struct whose first field is the actual function to call.
+ Type* pfntype =
+ Type::make_pointer_type(
+ Type::make_pointer_type(Type::make_void_type()));
+ fn = Expression::make_unsafe_cast(pfntype, this->fn_, location);
+ fn = Expression::make_unary(OPERATOR_MULT, fn, location);
+ }
else
{
Expression* first_arg;
- Expression* fn_expr =
- this->interface_method_function(interface_method, &first_arg);
- args[0] = first_arg->get_tree(context);
- fn = fn_expr->get_tree(context);
-
- if (fn == error_mark_node)
- return error_mark_node;
- closure_tree = NULL_TREE;
- }
-
- if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
- return error_mark_node;
-
- tree fndecl = fn;
- if (TREE_CODE(fndecl) == ADDR_EXPR)
- fndecl = TREE_OPERAND(fndecl, 0);
-
- // Add a type cast in case the type of the function is a recursive
- // type which refers to itself. We don't do this for an interface
- // method because 1) an interface method never refers to itself, so
- // we always have a function type here; 2) we pass an extra first
- // argument to an interface method, so fnfield_type is not correct.
- if ((!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) && !is_interface_method)
- fn = fold_convert_loc(location.gcc_location(), fnfield_type, fn);
-
- // This is to support builtin math functions when using 80387 math.
- tree excess_type = NULL_TREE;
- if (optimize
- && TREE_CODE(fndecl) == FUNCTION_DECL
- && DECL_IS_BUILTIN(fndecl)
- && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
- && nargs > 0
- && ((SCALAR_FLOAT_TYPE_P(rettype)
- && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
- || (COMPLEX_FLOAT_TYPE_P(rettype)
- && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0])))))
- {
- excess_type = excess_precision_type(TREE_TYPE(args[0]));
- if (excess_type != NULL_TREE)
- {
- tree excess_fndecl = mathfn_built_in(excess_type,
- DECL_FUNCTION_CODE(fndecl));
- if (excess_fndecl == NULL_TREE)
- excess_type = NULL_TREE;
- else
- {
- fn = build_fold_addr_expr_loc(location.gcc_location(),
- excess_fndecl);
- for (int i = 0; i < nargs; ++i)
- {
- if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i]))
- || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i])))
- args[i] = ::convert(excess_type, args[i]);
- }
- }
- }
+ fn = this->interface_method_function(interface_method, &first_arg);
+ fn_args[0] = tree_to_expr(first_arg->get_tree(context));
}
- if (func == NULL)
- fn = save_expr(fn);
-
if (!has_closure_arg)
- go_assert(closure_tree == NULL_TREE);
+ go_assert(closure == NULL);
else
{
// Pass the closure argument by calling the function function
// __go_set_closure. In the order_evaluations pass we have
// ensured that if any parameters contain call expressions, they
// will have been moved out to temporary variables.
-
- go_assert(closure_tree != NULL_TREE);
- closure_tree = fold_convert_loc(location.gcc_location(), ptr_type_node,
- closure_tree);
- static tree set_closure_fndecl;
- tree set_closure = Gogo::call_builtin(&set_closure_fndecl,
- location,
- "__go_set_closure",
- 1,
- void_type_node,
- ptr_type_node,
- closure_tree);
- if (set_closure == error_mark_node)
- return error_mark_node;
- fn = build2_loc(location.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(fn), set_closure, fn);
+ go_assert(closure != NULL);
+ Expression* set_closure =
+ Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure);
+ fn = Expression::make_compound(set_closure, fn, location);
}
- tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
- fn, nargs, args);
- delete[] args;
-
- SET_EXPR_LOCATION(ret, location.gcc_location());
+ Btype* bft = fntype->get_backend_fntype(gogo);
+ Bexpression* bfn = tree_to_expr(fn->get_tree(context));
+ bfn = gogo->backend()->convert_expression(bft, bfn, location);
+ Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location);
- // If this is a recursive function type which returns itself, as in
- // type F func() F
- // we have used ptr_type_node for the return type. Add a cast here
- // to the correct type.
- if (TREE_TYPE(ret) == ptr_type_node)
+ if (this->results_ != NULL)
{
- tree t = type_to_tree(this->type()->base()->get_backend(gogo));
- ret = fold_convert_loc(location.gcc_location(), t, ret);
- }
+ go_assert(this->call_temp_ != NULL);
+ Expression* call_ref =
+ Expression::make_temporary_reference(this->call_temp_, location);
+ Bexpression* bcall_ref = tree_to_expr(call_ref->get_tree(context));
+ Bstatement* assn_stmt =
+ gogo->backend()->assignment_statement(bcall_ref, call, location);
- if (excess_type != NULL_TREE)
- {
- // Calling convert here can undo our excess precision change.
- // That may or may not be a bug in convert_to_real.
- ret = build1(NOP_EXPR, rettype, ret);
- }
+ this->call_ = this->set_results(context, bcall_ref);
- if (this->results_ != NULL)
- ret = this->set_results(context, ret);
-
- this->tree_ = ret;
+ Bexpression* set_and_call =
+ gogo->backend()->compound_expression(assn_stmt, this->call_,
+ location);
+ return expr_to_tree(set_and_call);
+ }
- return ret;
+ this->call_ = call;
+ return expr_to_tree(this->call_);
}
// Set the result variables if this call returns multiple results.
-tree
-Call_expression::set_results(Translate_context* context, tree call_tree)
+Bexpression*
+Call_expression::set_results(Translate_context* context, Bexpression* call)
{
- tree stmt_list = NULL_TREE;
-
- call_tree = save_expr(call_tree);
-
- if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
- {
- go_assert(saw_errors());
- return call_tree;
- }
+ Gogo* gogo = context->gogo();
+ Bexpression* results = NULL;
Location loc = this->location();
- tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
+
size_t rc = this->result_count();
- for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field))
+ for (size_t i = 0; i < rc; ++i)
{
- go_assert(field != NULL_TREE);
-
Temporary_statement* temp = this->result(i);
if (temp == NULL)
{
go_assert(saw_errors());
- return error_mark_node;
+ return gogo->backend()->error_expression();
}
Temporary_reference_expression* ref =
Expression::make_temporary_reference(temp, loc);
ref->set_is_lvalue();
- tree temp_tree = ref->get_tree(context);
- if (temp_tree == error_mark_node)
- return error_mark_node;
- tree val_tree = build3_loc(loc.gcc_location(), COMPONENT_REF,
- TREE_TYPE(field), call_tree, field, NULL_TREE);
- tree set_tree = build2_loc(loc.gcc_location(), MODIFY_EXPR,
- void_type_node, temp_tree, val_tree);
+ Bexpression* result_ref = tree_to_expr(ref->get_tree(context));
+ Bexpression* call_result =
+ gogo->backend()->struct_field_expression(call, i, loc);
+ Bstatement* assn_stmt =
+ gogo->backend()->assignment_statement(result_ref, call_result, loc);
- append_to_statement_list(set_tree, &stmt_list);
- }
- go_assert(field == NULL_TREE);
+ Bexpression* result =
+ gogo->backend()->compound_expression(assn_stmt, call_result, loc);
- return save_expr(stmt_list);
+ if (results == NULL)
+ results = result;
+ else
+ {
+ Bstatement* expr_stmt = gogo->backend()->expression_statement(result);
+ results =
+ gogo->backend()->compound_expression(expr_stmt, results, loc);
+ }
+ }
+ return results;
}
// Dump ast representation for a call expressin.
@@ -10333,6 +9982,9 @@ class Array_index_expression : public Expression
int
do_traverse(Traverse*);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type();
@@ -10343,9 +9995,6 @@ class Array_index_expression : public Expression
do_check_types(Gogo*);
Expression*
- do_flatten(Gogo*, Named_object*, Statement_inserter*);
-
- Expression*
do_copy()
{
return Expression::make_array_index(this->array_->copy(),
@@ -10586,19 +10235,41 @@ Array_index_expression::do_check_types(Gogo*)
}
}
-// Flatten array indexing by using a temporary variable for slices.
+// Flatten array indexing by using temporary variables for slices and indexes.
Expression*
Array_index_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
Location loc = this->location();
+ Temporary_statement* temp;
if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
{
- Temporary_statement* temp = Statement::make_temporary(NULL, this->array_, loc);
+ temp = Statement::make_temporary(NULL, this->array_, loc);
inserter->insert(temp);
this->array_ = Expression::make_temporary_reference(temp, loc);
}
+ if (!this->start_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->start_, loc);
+ inserter->insert(temp);
+ this->start_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (this->end_ != NULL
+ && !this->end_->is_nil_expression()
+ && !this->end_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->end_, loc);
+ inserter->insert(temp);
+ this->end_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (this->cap_ != NULL && !this->cap_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->cap_, loc);
+ inserter->insert(temp);
+ this->cap_ = Expression::make_temporary_reference(temp, loc);
+ }
+
return this;
}
@@ -10625,9 +10296,6 @@ Array_index_expression::do_is_addressable() const
tree
Array_index_expression::do_get_tree(Translate_context* context)
{
- Gogo* gogo = context->gogo();
- Location loc = this->location();
-
Array_type* array_type = this->array_->type()->array_type();
if (array_type == NULL)
{
@@ -10636,66 +10304,40 @@ Array_index_expression::do_get_tree(Translate_context* context)
}
go_assert(!array_type->is_slice_type() || this->array_->is_variable());
- tree type_tree = type_to_tree(array_type->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
+ Location loc = this->location();
+ Gogo* gogo = context->gogo();
+
+ Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
- tree length_tree = NULL_TREE;
+ // We need to convert the length and capacity to the Go "int" type here
+ // because the length of a fixed-length array could be of type "uintptr"
+ // and gimple disallows binary operations between "uintptr" and other
+ // integer types. FIXME.
+ Bexpression* length = NULL;
if (this->end_ == NULL || this->end_->is_nil_expression())
{
Expression* len = array_type->get_length(gogo, this->array_);
- length_tree = len->get_tree(context);
- if (length_tree == error_mark_node)
- return error_mark_node;
- length_tree = save_expr(length_tree);
+ length = tree_to_expr(len->get_tree(context));
+ length = gogo->backend()->convert_expression(int_btype, length, loc);
}
- tree capacity_tree = NULL_TREE;
+ Bexpression* capacity = NULL;
if (this->end_ != NULL)
{
Expression* cap = array_type->get_capacity(gogo, this->array_);
- capacity_tree = cap->get_tree(context);
- if (capacity_tree == error_mark_node)
- return error_mark_node;
- capacity_tree = save_expr(capacity_tree);
+ capacity = tree_to_expr(cap->get_tree(context));
+ capacity = gogo->backend()->convert_expression(int_btype, capacity, loc);
}
- tree cap_arg = capacity_tree;
+ Bexpression* cap_arg = capacity;
if (this->cap_ != NULL)
{
- cap_arg = this->cap_->get_tree(context);
- if (cap_arg == error_mark_node)
- return error_mark_node;
+ cap_arg = tree_to_expr(this->cap_->get_tree(context));
+ cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
}
- tree length_type = (length_tree != NULL_TREE
- ? TREE_TYPE(length_tree)
- : TREE_TYPE(cap_arg));
-
- tree bad_index = boolean_false_node;
-
- tree start_tree = this->start_->get_tree(context);
- if (start_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(start_tree))
- start_tree = save_expr(start_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
- start_tree = convert_to_integer(length_type, start_tree);
-
- bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
- loc);
-
- start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index,
- fold_build2_loc(loc.gcc_location(),
- (this->end_ == NULL
- ? GE_EXPR
- : GT_EXPR),
- boolean_type_node, start_tree,
- (this->end_ == NULL
- ? length_tree
- : capacity_tree)));
+ if (length == NULL)
+ length = cap_arg;
int code = (array_type->length() != NULL
? (this->end_ == NULL
@@ -10704,168 +10346,124 @@ Array_index_expression::do_get_tree(Translate_context* context)
: (this->end_ == NULL
? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
: RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
- tree crash = gogo->runtime_error(code, loc)->get_tree(context);
+ Bexpression* crash =
+ tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context));
+
+ Expression* bounds_check = Expression::check_bounds(this->start_, loc);
+ Bexpression* bad_index = tree_to_expr(bounds_check->get_tree(context));
+
+ Bexpression* start = tree_to_expr(this->start_->get_tree(context));
+ start = gogo->backend()->convert_expression(int_btype, start, loc);
+ Bexpression* start_too_large =
+ gogo->backend()->binary_expression((this->end_ == NULL
+ ? OPERATOR_GE
+ : OPERATOR_GT),
+ start,
+ (this->end_ == NULL
+ ? length
+ : capacity),
+ loc);
+ bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, start_too_large,
+ bad_index, loc);
if (this->end_ == NULL)
{
// Simple array indexing. This has to return an l-value, so
- // wrap the index check into START_TREE.
- start_tree = build2(COMPOUND_EXPR, TREE_TYPE(start_tree),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- start_tree);
- start_tree = fold_convert_loc(loc.gcc_location(), sizetype, start_tree);
+ // wrap the index check into START.
+ start =
+ gogo->backend()->conditional_expression(int_btype, bad_index,
+ crash, start, loc);
+ Bexpression* ret;
if (array_type->length() != NULL)
{
- // Fixed array.
- tree array_tree = this->array_->get_tree(context);
- if (array_tree == error_mark_node)
- return error_mark_node;
- return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
- start_tree, NULL_TREE, NULL_TREE);
+ Bexpression* array = tree_to_expr(this->array_->get_tree(context));
+ ret = gogo->backend()->array_index_expression(array, start, loc);
}
else
{
- // Open array.
- Expression* valptr =
+ // Slice.
+ Expression* valptr =
array_type->get_value_pointer(gogo, this->array_);
- tree values = valptr->get_tree(context);
- Type* element_type = array_type->element_type();
- Btype* belement_type = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(belement_type);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- tree element_size = TYPE_SIZE_UNIT(element_type_tree);
- tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype,
- start_tree, element_size);
- tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(values), values, offset);
- return build_fold_indirect_ref(ptr);
+ Bexpression* ptr = tree_to_expr(valptr->get_tree(context));
+ ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc);
+ ret = gogo->backend()->indirect_expression(ptr, true, loc);
}
+ return expr_to_tree(ret);
}
// Array slice.
if (this->cap_ != NULL)
{
- if (!DECL_P(cap_arg))
- cap_arg = save_expr(cap_arg);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(cap_arg)))
- cap_arg = convert_to_integer(length_type, cap_arg);
-
- bad_index = Expression::check_bounds(cap_arg, length_type, bad_index,
- loc);
- cap_arg = fold_convert_loc(loc.gcc_location(), length_type, cap_arg);
-
- tree bad_cap = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node,
- fold_build2_loc(loc.gcc_location(),
- LT_EXPR, boolean_type_node,
- cap_arg, start_tree),
- fold_build2_loc(loc.gcc_location(),
- GT_EXPR, boolean_type_node,
- cap_arg, capacity_tree));
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index, bad_cap);
- }
-
- tree end_tree;
+ bounds_check = Expression::check_bounds(this->cap_, loc);
+ Bexpression* bounds_bcheck =
+ tree_to_expr(bounds_check->get_tree(context));
+ bad_index =
+ gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+ bad_index, loc);
+ cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
+
+ Bexpression* cap_too_small =
+ gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc);
+ Bexpression* cap_too_large =
+ gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc);
+ Bexpression* bad_cap =
+ gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small,
+ cap_too_large, loc);
+ bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap,
+ bad_index, loc);
+ }
+
+ Bexpression* end;
if (this->end_->is_nil_expression())
- end_tree = length_tree;
+ end = length;
else
{
- end_tree = this->end_->get_tree(context);
- if (end_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(end_tree))
- end_tree = save_expr(end_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
- end_tree = convert_to_integer(length_type, end_tree);
-
- bad_index = Expression::check_bounds(end_tree, length_type, bad_index,
- loc);
+ bounds_check = Expression::check_bounds(this->end_, loc);
+ Bexpression* bounds_bcheck =
+ tree_to_expr(bounds_check->get_tree(context));
- end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree);
+ bad_index =
+ gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+ bad_index, loc);
- tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node,
- fold_build2_loc(loc.gcc_location(),
- LT_EXPR, boolean_type_node,
- end_tree, start_tree),
- fold_build2_loc(loc.gcc_location(),
- GT_EXPR, boolean_type_node,
- end_tree, cap_arg));
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index, bad_end);
+ end = tree_to_expr(this->end_->get_tree(context));
+ end = gogo->backend()->convert_expression(int_btype, end, loc);
+ Bexpression* end_too_small =
+ gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc);
+ Bexpression* end_too_large =
+ gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc);
+ Bexpression* bad_end =
+ gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small,
+ end_too_large, loc);
+ bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end,
+ bad_index, loc);
}
-
- Type* element_type = array_type->element_type();
- tree element_type_tree = type_to_tree(element_type->get_backend(gogo));
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- tree element_size = TYPE_SIZE_UNIT(element_type_tree);
-
- tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype,
- fold_convert_loc(loc.gcc_location(), sizetype,
- start_tree),
- element_size);
-
Expression* valptr = array_type->get_value_pointer(gogo, this->array_);
- tree value_pointer = valptr->get_tree(context);
- if (value_pointer == error_mark_node)
- return error_mark_node;
+ Bexpression* val = tree_to_expr(valptr->get_tree(context));
+ val = gogo->backend()->pointer_offset_expression(val, start, loc);
- value_pointer = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(value_pointer),
- value_pointer, offset);
+ Bexpression* result_length =
+ gogo->backend()->binary_expression(OPERATOR_MINUS, end, start, loc);
- tree result_length_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
- length_type, end_tree, start_tree);
+ Bexpression* result_capacity =
+ gogo->backend()->binary_expression(OPERATOR_MINUS, cap_arg, start, loc);
- tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
- length_type, cap_arg, start_tree);
-
- tree struct_tree = type_to_tree(this->type()->get_backend(gogo));
- go_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc (init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(struct_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- elt->index = field;
- elt->value = value_pointer;
+ Btype* struct_btype = this->type()->get_backend(gogo);
+ std::vector<Bexpression*> init;
+ init.push_back(val);
+ init.push_back(result_length);
+ init.push_back(result_capacity);
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt->index = field;
- elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field),
- result_length_tree);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field),
- result_capacity_tree);
-
- tree constructor = build_constructor(struct_tree, init);
-
- if (TREE_CONSTANT(value_pointer)
- && TREE_CONSTANT(result_length_tree)
- && TREE_CONSTANT(result_capacity_tree))
- TREE_CONSTANT(constructor) = 1;
+ Bexpression* ctor =
+ gogo->backend()->constructor_expression(struct_btype, init, loc);
+ Bexpression* ret =
+ gogo->backend()->conditional_expression(struct_btype, bad_index,
+ crash, ctor, loc);
- return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(constructor),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- constructor);
+ return expr_to_tree(ret);
}
// Dump ast representation for an array index expression.
@@ -10903,6 +10501,9 @@ class String_index_expression : public Expression
int
do_traverse(Traverse*);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type();
@@ -10963,6 +10564,36 @@ String_index_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+Expression*
+String_index_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Temporary_statement* temp;
+ Location loc = this->location();
+ if (!this->string_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->string_, loc);
+ inserter->insert(temp);
+ this->string_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (!this->start_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->start_, loc);
+ inserter->insert(temp);
+ this->start_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (this->end_ != NULL
+ && !this->end_->is_nil_expression()
+ && !this->end_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->end_, loc);
+ inserter->insert(temp);
+ this->end_ = Expression::make_temporary_reference(temp, loc);
+ }
+
+ return this;
+}
+
// Return the type of a string index.
Type*
@@ -11049,112 +10680,87 @@ tree
String_index_expression::do_get_tree(Translate_context* context)
{
Location loc = this->location();
+ Expression* string_arg = this->string_;
+ if (this->string_->type()->points_to() != NULL)
+ string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc);
- tree string_tree = this->string_->get_tree(context);
- if (string_tree == error_mark_node)
- return error_mark_node;
+ Expression* bad_index = Expression::check_bounds(this->start_, loc);
- if (this->string_->type()->points_to() != NULL)
- string_tree = build_fold_indirect_ref(string_tree);
- if (!DECL_P(string_tree))
- string_tree = save_expr(string_tree);
- tree string_type = TREE_TYPE(string_tree);
+ int code = (this->end_ == NULL
+ ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
+ : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
- tree length_tree = String_type::length_tree(context->gogo(), string_tree);
- length_tree = save_expr(length_tree);
+ Gogo* gogo = context->gogo();
+ Bexpression* crash =
+ tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context));
Type* int_type = Type::lookup_integer_type("int");
- tree length_type = type_to_tree(int_type->get_backend(context->gogo()));
- tree bad_index = boolean_false_node;
+ // It is possible that an error occurred earlier because the start index
+ // cannot be represented as an integer type. In this case, we shouldn't
+ // try casting the starting index into an integer since
+ // Type_conversion_expression will fail to get the backend representation.
+ // FIXME.
+ if (this->start_->type()->integer_type() == NULL
+ && !Type::are_convertible(int_type, this->start_->type(), NULL))
+ {
+ go_assert(saw_errors());
+ return error_mark_node;
+ }
- tree start_tree = this->start_->get_tree(context);
- if (start_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(start_tree))
- start_tree = save_expr(start_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
- start_tree = convert_to_integer(length_type, start_tree);
+ Expression* start = Expression::make_cast(int_type, this->start_, loc);
- bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
- loc);
+ if (this->end_ == NULL)
+ {
+ Expression* length =
+ Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc);
- start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
+ Expression* start_too_large =
+ Expression::make_binary(OPERATOR_GE, start, length, loc);
+ bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
+ bad_index, loc);
+ Expression* bytes =
+ Expression::make_string_info(this->string_, STRING_INFO_DATA, loc);
- int code = (this->end_ == NULL
- ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
- : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
- tree crash = context->gogo()->runtime_error(code, loc)->get_tree(context);
+ Bexpression* bstart = tree_to_expr(start->get_tree(context));
+ Bexpression* ptr = tree_to_expr(bytes->get_tree(context));
+ ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
+ Bexpression* index = gogo->backend()->indirect_expression(ptr, true, loc);
- if (this->end_ == NULL)
+ Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo);
+ Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
+ Bexpression* ret =
+ gogo->backend()->conditional_expression(byte_btype, index_error,
+ crash, index, loc);
+ return expr_to_tree(ret);
+ }
+
+ Expression* end = NULL;
+ if (this->end_->is_nil_expression())
{
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index,
- fold_build2_loc(loc.gcc_location(), GE_EXPR,
- boolean_type_node,
- start_tree, length_tree));
-
- tree bytes_tree = String_type::bytes_tree(context->gogo(), string_tree);
- tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(bytes_tree),
- bytes_tree,
- fold_convert_loc(loc.gcc_location(), sizetype,
- start_tree));
- tree index = build_fold_indirect_ref_loc(loc.gcc_location(), ptr);
-
- return build2(COMPOUND_EXPR, TREE_TYPE(index),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- index);
+ mpz_t neg_one;
+ mpz_init_set_si(neg_one, -1);
+ end = Expression::make_integer(&neg_one, int_type, loc);
+ mpz_clear(neg_one);
}
else
{
- tree end_tree;
- if (this->end_->is_nil_expression())
- end_tree = build_int_cst(length_type, -1);
- else
- {
- end_tree = this->end_->get_tree(context);
- if (end_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(end_tree))
- end_tree = save_expr(end_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
- end_tree = convert_to_integer(length_type, end_tree);
-
- bad_index = Expression::check_bounds(end_tree, length_type,
- bad_index, loc);
-
- end_tree = fold_convert_loc(loc.gcc_location(), length_type,
- end_tree);
- }
-
- static tree strslice_fndecl;
- tree ret = Gogo::call_builtin(&strslice_fndecl,
- loc,
- "__go_string_slice",
- 3,
- string_type,
- string_type,
- string_tree,
- length_type,
- start_tree,
- length_type,
- end_tree);
- if (ret == error_mark_node)
- return error_mark_node;
- // This will panic if the bounds are out of range for the
- // string.
- TREE_NOTHROW(strslice_fndecl) = 0;
-
- if (bad_index == boolean_false_node)
- return ret;
- else
- return build2(COMPOUND_EXPR, TREE_TYPE(ret),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- ret);
+ Expression* bounds_check = Expression::check_bounds(this->end_, loc);
+ bad_index =
+ Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc);
+ end = Expression::make_cast(int_type, this->end_, loc);
}
+
+ Expression* strslice = Runtime::make_call(Runtime::STRING_SLICE, loc, 3,
+ string_arg, start, end);
+ Bexpression* bstrslice = tree_to_expr(strslice->get_tree(context));
+
+ Btype* str_btype = strslice->type()->get_backend(gogo);
+ Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
+ Bexpression* ret =
+ gogo->backend()->conditional_expression(str_btype, index_error,
+ crash, bstrslice, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for a string index expression.
@@ -11199,6 +10805,44 @@ Map_index_expression::do_traverse(Traverse* traverse)
return Expression::traverse(&this->index_, traverse);
}
+// We need to pass in a pointer to the key, so flatten the index into a
+// temporary variable if it isn't already. The value pointer will be
+// dereferenced and checked for nil, so flatten into a temporary to avoid
+// recomputation.
+
+Expression*
+Map_index_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Map_type* mt = this->get_map_type();
+ if (this->index_->type() != mt->key_type())
+ this->index_ = Expression::make_cast(mt->key_type(), this->index_,
+ this->location());
+
+ if (!this->index_->is_variable())
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL, this->index_,
+ this->location());
+ inserter->insert(temp);
+ this->index_ = Expression::make_temporary_reference(temp,
+ this->location());
+ }
+
+ if (this->value_pointer_ == NULL)
+ this->get_value_pointer(this->is_lvalue_);
+ if (!this->value_pointer_->is_variable())
+ {
+ Temporary_statement* temp =
+ Statement::make_temporary(NULL, this->value_pointer_,
+ this->location());
+ inserter->insert(temp);
+ this->value_pointer_ =
+ Expression::make_temporary_reference(temp, this->location());
+ }
+
+ return this;
+}
+
// Return the type of a map index.
Type*
@@ -11258,131 +10902,84 @@ Map_index_expression::do_get_tree(Translate_context* context)
{
Map_type* type = this->get_map_type();
if (type == NULL)
- return error_mark_node;
-
- tree valptr = this->get_value_pointer(context, this->is_lvalue_);
- if (valptr == error_mark_node)
- return error_mark_node;
- valptr = save_expr(valptr);
+ {
+ go_assert(saw_errors());
+ return error_mark_node;
+ }
- tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr));
+ go_assert(this->value_pointer_ != NULL
+ && this->value_pointer_->is_variable());
+ Bexpression* ret;
if (this->is_lvalue_)
- return build_fold_indirect_ref(valptr);
+ {
+ Expression* val =
+ Expression::make_unary(OPERATOR_MULT, this->value_pointer_,
+ this->location());
+ ret = tree_to_expr(val->get_tree(context));
+ }
else if (this->is_in_tuple_assignment_)
{
// Tuple_map_assignment_statement is responsible for using this
// appropriately.
- return valptr;
+ ret = tree_to_expr(this->value_pointer_->get_tree(context));
}
else
{
+ Location loc = this->location();
+
+ Expression* nil_check =
+ Expression::make_binary(OPERATOR_EQEQ, this->value_pointer_,
+ Expression::make_nil(loc), loc);
+ Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(context));
+ Expression* val =
+ Expression::make_unary(OPERATOR_MULT, this->value_pointer_, loc);
+ Bexpression* bval = tree_to_expr(val->get_tree(context));
+
Gogo* gogo = context->gogo();
Btype* val_btype = type->val_type()->get_backend(gogo);
Bexpression* val_zero = gogo->backend()->zero_expression(val_btype);
- return fold_build3(COND_EXPR, val_type_tree,
- fold_build2(EQ_EXPR, boolean_type_node, valptr,
- fold_convert(TREE_TYPE(valptr),
- null_pointer_node)),
- expr_to_tree(val_zero),
- build_fold_indirect_ref(valptr));
+ ret = gogo->backend()->conditional_expression(val_btype, bnil_check,
+ val_zero, bval, loc);
}
+
+ return expr_to_tree(ret);
}
-// Get a tree for the map index. This returns a tree which evaluates
-// to a pointer to a value. The pointer will be NULL if the key is
+// Get an expression for the map index. This returns an expression which
+// evaluates to a pointer to a value. The pointer will be NULL if the key is
// not in the map.
-tree
-Map_index_expression::get_value_pointer(Translate_context* context,
- bool insert)
+Expression*
+Map_index_expression::get_value_pointer(bool insert)
{
- Map_type* type = this->get_map_type();
- if (type == NULL)
- return error_mark_node;
-
- tree map_tree = this->map_->get_tree(context);
- tree index_tree = this->index_->get_tree(context);
- index_tree = Expression::convert_for_assignment(context, type->key_type(),
- this->index_->type(),
- index_tree,
- this->location());
- if (map_tree == error_mark_node || index_tree == error_mark_node)
- return error_mark_node;
-
- if (this->map_->type()->points_to() != NULL)
- map_tree = build_fold_indirect_ref(map_tree);
-
- // We need to pass in a pointer to the key, so stuff it into a
- // variable.
- tree tmp;
- tree make_tmp;
- if (current_function_decl != NULL)
- {
- tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
- DECL_IGNORED_P(tmp) = 0;
- DECL_INITIAL(tmp) = index_tree;
- make_tmp = build1(DECL_EXPR, void_type_node, tmp);
- TREE_ADDRESSABLE(tmp) = 1;
- }
- else
+ if (this->value_pointer_ == NULL)
{
- tmp = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("M"),
- TREE_TYPE(index_tree));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (!TREE_CONSTANT(index_tree))
- make_tmp = fold_build2_loc(this->location().gcc_location(),
- INIT_EXPR, void_type_node,
- tmp, index_tree);
- else
+ Map_type* type = this->get_map_type();
+ if (type == NULL)
{
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- DECL_INITIAL(tmp) = index_tree;
- make_tmp = NULL_TREE;
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
}
- rest_of_decl_compilation(tmp, 1, 0);
- }
- tree tmpref =
- fold_convert_loc(this->location().gcc_location(), const_ptr_type_node,
- build_fold_addr_expr_loc(this->location().gcc_location(),
- tmp));
-
- static tree map_index_fndecl;
- tree call = Gogo::call_builtin(&map_index_fndecl,
- this->location(),
- "__go_map_index",
- 3,
- const_ptr_type_node,
- TREE_TYPE(map_tree),
- map_tree,
- const_ptr_type_node,
- tmpref,
- boolean_type_node,
- (insert
- ? boolean_true_node
- : boolean_false_node));
- if (call == error_mark_node)
- return error_mark_node;
- // This can panic on a map of interface type if the interface holds
- // an uncomparable or unhashable type.
- TREE_NOTHROW(map_index_fndecl) = 0;
- Type* val_type = type->val_type();
- tree val_type_tree = type_to_tree(val_type->get_backend(context->gogo()));
- if (val_type_tree == error_mark_node)
- return error_mark_node;
- tree ptr_val_type_tree = build_pointer_type(val_type_tree);
+ Location loc = this->location();
+ Expression* map_ref = this->map_;
+ if (this->map_->type()->points_to() != NULL)
+ map_ref = Expression::make_unary(OPERATOR_MULT, map_ref, loc);
- tree ret = fold_convert_loc(this->location().gcc_location(),
- ptr_val_type_tree, call);
- if (make_tmp != NULL_TREE)
- ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret);
- return ret;
+ Expression* index_ptr = Expression::make_unary(OPERATOR_AND, this->index_,
+ loc);
+ Expression* map_index =
+ Runtime::make_call(Runtime::MAP_INDEX, loc, 3,
+ map_ref, index_ptr,
+ Expression::make_boolean(insert, loc));
+
+ Type* val_type = type->val_type();
+ this->value_pointer_ =
+ Expression::make_unsafe_cast(Type::make_pointer_type(val_type),
+ map_index, this->location());
+ }
+ return this->value_pointer_;
}
// Dump ast representation for a map index expression
@@ -11841,7 +11438,7 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context)
vals->push_back(this->expr_);
Expression* expr = Expression::make_struct_composite_literal(st, vals, loc);
- expr = Expression::make_heap_composite(expr, loc);
+ expr = Expression::make_heap_expression(expr, loc);
Bexpression* bclosure = tree_to_expr(expr->get_tree(context));
Expression* nil_check =
@@ -12193,15 +11790,13 @@ class Allocation_expression : public Expression
tree
Allocation_expression::do_get_tree(Translate_context* context)
{
- tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
- tree size_tree = TYPE_SIZE_UNIT(type_tree);
- tree space = context->gogo()->allocate_memory(this->type_, size_tree,
- this->location());
- if (space == error_mark_node)
- return error_mark_node;
- return fold_convert(build_pointer_type(type_tree), space);
+ Gogo* gogo = context->gogo();
+ Location loc = this->location();
+ Expression* space = gogo->allocate_memory(this->type_, loc);
+ Bexpression* bspace = tree_to_expr(space->get_tree(context));
+ Btype* pbtype = gogo->backend()->pointer_type(this->type_->get_backend(gogo));
+ Bexpression* ret = gogo->backend()->convert_expression(pbtype, bspace, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for an allocation expression.
@@ -12453,64 +12048,38 @@ Struct_construction_expression::do_get_tree(Translate_context* context)
{
Gogo* gogo = context->gogo();
+ Btype* btype = this->type_->get_backend(gogo);
if (this->vals_ == NULL)
- {
- Btype* btype = this->type_->get_backend(gogo);
- return expr_to_tree(gogo->backend()->zero_expression(btype));
- }
-
- tree type_tree = type_to_tree(this->type_->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
+ return expr_to_tree(gogo->backend()->zero_expression(btype));
- bool is_constant = true;
const Struct_field_list* fields = this->type_->struct_type()->fields();
- vec<constructor_elt, va_gc> *elts;
- vec_alloc (elts, fields->size());
- Struct_field_list::const_iterator pf = fields->begin();
Expression_list::const_iterator pv = this->vals_->begin();
- for (tree field = TYPE_FIELDS(type_tree);
- field != NULL_TREE;
- field = DECL_CHAIN(field), ++pf)
+ std::vector<Bexpression*> init;
+ for (Struct_field_list::const_iterator pf = fields->begin();
+ pf != fields->end();
+ ++pf)
{
- go_assert(pf != fields->end());
-
Btype* fbtype = pf->type()->get_backend(gogo);
-
- tree val;
if (pv == this->vals_->end())
- val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
+ init.push_back(gogo->backend()->zero_expression(fbtype));
else if (*pv == NULL)
{
- val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
+ init.push_back(gogo->backend()->zero_expression(fbtype));
++pv;
}
else
{
- val = Expression::convert_for_assignment(context, pf->type(),
- (*pv)->type(),
- (*pv)->get_tree(context),
- this->location());
+ Expression* val =
+ Expression::convert_for_assignment(gogo, pf->type(),
+ *pv, this->location());
+ init.push_back(tree_to_expr(val->get_tree(context)));
++pv;
}
-
- if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
- return error_mark_node;
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = elts->quick_push(empty);
- elt->index = field;
- elt->value = val;
- if (!TREE_CONSTANT(val))
- is_constant = false;
}
- go_assert(pf == fields->end());
- tree ret = build_constructor(type_tree, elts);
- if (is_constant)
- TREE_CONSTANT(ret) = 1;
- return ret;
+ Bexpression* ret =
+ gogo->backend()->constructor_expression(btype, init, this->location());
+ return expr_to_tree(ret);
}
// Export a struct construction.
@@ -12555,7 +12124,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
// Construct an array. This class is not used directly; instead we
// use the child classes, Fixed_array_construction_expression and
-// Open_array_construction_expression.
+// Slice_construction_expression.
class Array_construction_expression : public Expression
{
@@ -12608,9 +12177,9 @@ protected:
vals()
{ return this->vals_; }
- // Get a constructor tree for the array values.
- tree
- get_constructor_tree(Translate_context* context, tree type_tree);
+ // Get the backend constructor for the array values.
+ Bexpression*
+ get_constructor(Translate_context* context, Btype* btype);
void
do_dump_expression(Ast_dump_context*) const;
@@ -12723,16 +12292,17 @@ Array_construction_expression::do_check_types(Gogo*)
}
}
-// Get a constructor tree for the array values.
+// Get a constructor expression for the array values.
-tree
-Array_construction_expression::get_constructor_tree(Translate_context* context,
- tree type_tree)
+Bexpression*
+Array_construction_expression::get_constructor(Translate_context* context,
+ Btype* array_btype)
{
- vec<constructor_elt, va_gc> *values;
- vec_alloc (values, (this->vals_ == NULL ? 0 : this->vals_->size()));
Type* element_type = this->type_->array_type()->element_type();
- bool is_constant = true;
+
+ std::vector<unsigned long> indexes;
+ std::vector<Bexpression*> vals;
+ Gogo* gogo = context->gogo();
if (this->vals_ != NULL)
{
size_t i = 0;
@@ -12745,45 +12315,32 @@ Array_construction_expression::get_constructor_tree(Translate_context* context,
{
if (this->indexes_ != NULL)
go_assert(pi != this->indexes_->end());
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = values->quick_push(empty);
if (this->indexes_ == NULL)
- elt->index = size_int(i);
+ indexes.push_back(i);
else
- elt->index = size_int(*pi);
-
+ indexes.push_back(*pi);
if (*pv == NULL)
{
- Gogo* gogo = context->gogo();
Btype* ebtype = element_type->get_backend(gogo);
Bexpression *zv = gogo->backend()->zero_expression(ebtype);
- elt->value = expr_to_tree(zv);
+ vals.push_back(zv);
}
else
{
- tree value_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context,
- element_type,
- (*pv)->type(),
- value_tree,
- this->location());
+ Expression* val_expr =
+ Expression::convert_for_assignment(gogo, element_type, *pv,
+ this->location());
+ vals.push_back(tree_to_expr(val_expr->get_tree(context)));
}
- if (elt->value == error_mark_node)
- return error_mark_node;
- if (!TREE_CONSTANT(elt->value))
- is_constant = false;
if (this->indexes_ != NULL)
++pi;
}
if (this->indexes_ != NULL)
go_assert(pi == this->indexes_->end());
}
-
- tree ret = build_constructor(type_tree, values);
- if (is_constant)
- TREE_CONSTANT(ret) = 1;
- return ret;
+ return gogo->backend()->array_constructor_expression(array_btype, indexes,
+ vals, this->location());
}
// Export an array construction.
@@ -12894,43 +12451,47 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context)
{
Type* type = this->type();
Btype* btype = type->get_backend(context->gogo());
- return this->get_constructor_tree(context, type_to_tree(btype));
+ return expr_to_tree(this->get_constructor(context, btype));
}
-// Construct an open array.
+// Construct a slice.
-class Open_array_construction_expression : public Array_construction_expression
+class Slice_construction_expression : public Array_construction_expression
{
public:
- Open_array_construction_expression(Type* type,
- const std::vector<unsigned long>* indexes,
- Expression_list* vals, Location location)
- : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
- type, indexes, vals, location)
+ Slice_construction_expression(Type* type,
+ const std::vector<unsigned long>* indexes,
+ Expression_list* vals, Location location)
+ : Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION,
+ type, indexes, vals, location),
+ valtype_(NULL)
{ go_assert(type->is_slice_type()); }
protected:
- // Note that taking the address of an open array literal is invalid.
+ // Note that taking the address of a slice literal is invalid.
Expression*
do_copy()
{
- return new Open_array_construction_expression(this->type(),
- this->indexes(),
- (this->vals() == NULL
- ? NULL
- : this->vals()->copy()),
- this->location());
+ return new Slice_construction_expression(this->type(), this->indexes(),
+ (this->vals() == NULL
+ ? NULL
+ : this->vals()->copy()),
+ this->location());
}
tree
do_get_tree(Translate_context*);
+
+ private:
+ // The type of the values in this slice.
+ Type* valtype_;
};
-// Return a tree for constructing an open array.
+// Return a tree for constructing a slice.
tree
-Open_array_construction_expression::do_get_tree(Translate_context* context)
+Slice_construction_expression::do_get_tree(Translate_context* context)
{
Array_type* array_type = this->type()->array_type();
if (array_type == NULL)
@@ -12940,49 +12501,43 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
}
Type* element_type = array_type->element_type();
- Btype* belement_type = element_type->get_backend(context->gogo());
- tree element_type_tree = type_to_tree(belement_type);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
+ if (this->valtype_ == NULL)
+ {
+ mpz_t lenval;
+ Expression* length;
+ if (this->vals() == NULL || this->vals()->empty())
+ mpz_init_set_ui(lenval, 0);
+ else
+ {
+ if (this->indexes() == NULL)
+ mpz_init_set_ui(lenval, this->vals()->size());
+ else
+ mpz_init_set_ui(lenval, this->indexes()->back() + 1);
+ }
+ Location loc = this->location();
+ Type* int_type = Type::lookup_integer_type("int");
+ length = Expression::make_integer(&lenval, int_type, loc);
+ mpz_clear(lenval);
+ this->valtype_ = Type::make_array_type(element_type, length);
+ }
tree values;
- tree length_tree;
+ Gogo* gogo = context->gogo();
+ Btype* val_btype = this->valtype_->get_backend(gogo);
if (this->vals() == NULL || this->vals()->empty())
{
// We need to create a unique value.
- tree max = size_int(0);
- tree constructor_type = build_array_type(element_type_tree,
- build_index_type(max));
- if (constructor_type == error_mark_node)
- return error_mark_node;
- vec<constructor_elt, va_gc> *vec;
- vec_alloc(vec, 1);
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = vec->quick_push(empty);
- elt->index = size_int(0);
- Gogo* gogo = context->gogo();
- Btype* btype = element_type->get_backend(gogo);
- elt->value = expr_to_tree(gogo->backend()->zero_expression(btype));
- values = build_constructor(constructor_type, vec);
- if (TREE_CONSTANT(elt->value))
- TREE_CONSTANT(values) = 1;
- length_tree = size_int(0);
+ Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+ Bexpression* zero = gogo->backend()->zero_expression(int_btype);
+ std::vector<unsigned long> index(1, 0);
+ std::vector<Bexpression*> val(1, zero);
+ Bexpression* ctor =
+ gogo->backend()->array_constructor_expression(val_btype, index, val,
+ this->location());
+ values = expr_to_tree(ctor);
}
else
- {
- unsigned long max_index;
- if (this->indexes() == NULL)
- max_index = this->vals()->size() - 1;
- else
- max_index = this->indexes()->back();
- tree max_tree = size_int(max_index);
- tree constructor_type = build_array_type(element_type_tree,
- build_index_type(max_tree));
- if (constructor_type == error_mark_node)
- return error_mark_node;
- values = this->get_constructor_tree(context, constructor_type);
- length_tree = size_int(max_index + 1);
- }
+ values = expr_to_tree(this->get_constructor(context, val_btype));
if (values == error_mark_node)
return error_mark_node;
@@ -13030,10 +12585,9 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
}
else
{
- tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values));
- space = context->gogo()->allocate_memory(element_type, memsize,
- this->location());
- space = save_expr(space);
+ Expression* alloc =
+ context->gogo()->allocate_memory(this->valtype_, this->location());
+ space = save_expr(alloc->get_tree(context));
tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
@@ -13042,7 +12596,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
set = build2(MODIFY_EXPR, void_type_node, ref, values);
}
- // Build a constructor for the open array.
+ // Build a constructor for the slice.
tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
if (type_tree == error_mark_node)
@@ -13059,6 +12613,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
elt->index = field;
elt->value = fold_convert(TREE_TYPE(field), space);
+ tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
elt = init->quick_push(empty);
field = DECL_CHAIN(field);
go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
@@ -13091,7 +12646,7 @@ Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
Location location)
{
go_assert(type->is_slice_type());
- return new Open_array_construction_expression(type, NULL, vals, location);
+ return new Slice_construction_expression(type, NULL, vals, location);
}
// Construct a map.
@@ -13102,13 +12657,16 @@ class Map_construction_expression : public Expression
Map_construction_expression(Type* type, Expression_list* vals,
Location location)
: Expression(EXPRESSION_MAP_CONSTRUCTION, location),
- type_(type), vals_(vals)
+ type_(type), vals_(vals), element_type_(NULL), constructor_temp_(NULL)
{ go_assert(vals == NULL || vals->size() % 2 == 0); }
protected:
int
do_traverse(Traverse* traverse);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type()
{ return this->type_; }
@@ -13140,6 +12698,10 @@ class Map_construction_expression : public Expression
Type* type_;
// The list of values.
Expression_list* vals_;
+ // The type of the key-value pair struct for each map element.
+ Struct_type* element_type_;
+ // A temporary reference to the variable storing the constructor initializer.
+ Temporary_statement* constructor_temp_;
};
// Traversal.
@@ -13155,6 +12717,69 @@ Map_construction_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+// Flatten constructor initializer into a temporary variable since
+// we need to take its address for __go_construct_map.
+
+Expression*
+Map_construction_expression::do_flatten(Gogo* gogo, Named_object*,
+ Statement_inserter* inserter)
+{
+ if (!this->is_error_expression()
+ && this->vals_ != NULL
+ && !this->vals_->empty()
+ && this->constructor_temp_ == NULL)
+ {
+ Map_type* mt = this->type_->map_type();
+ Type* key_type = mt->key_type();
+ Type* val_type = mt->val_type();
+ this->element_type_ = Type::make_builtin_struct_type(2,
+ "__key", key_type,
+ "__val", val_type);
+
+ Expression_list* value_pairs = new Expression_list();
+ Location loc = this->location();
+
+ size_t i = 0;
+ for (Expression_list::const_iterator pv = this->vals_->begin();
+ pv != this->vals_->end();
+ ++pv, ++i)
+ {
+ Expression_list* key_value_pair = new Expression_list();
+ Expression* key =
+ Expression::convert_for_assignment(gogo, key_type, *pv, loc);
+
+ ++pv;
+ Expression* val =
+ Expression::convert_for_assignment(gogo, val_type, *pv, loc);
+
+ key_value_pair->push_back(key);
+ key_value_pair->push_back(val);
+ value_pairs->push_back(
+ Expression::make_struct_composite_literal(this->element_type_,
+ key_value_pair, loc));
+ }
+
+ mpz_t lenval;
+ mpz_init_set_ui(lenval, i);
+ Expression* element_count = Expression::make_integer(&lenval, NULL, loc);
+ mpz_clear(lenval);
+
+ Type* ctor_type =
+ Type::make_array_type(this->element_type_, element_count);
+ Expression* constructor =
+ new Fixed_array_construction_expression(ctor_type, NULL,
+ value_pairs, loc);
+
+ this->constructor_temp_ =
+ Statement::make_temporary(NULL, constructor, loc);
+ constructor->issue_nil_check();
+ this->constructor_temp_->set_is_address_taken();
+ inserter->insert(this->constructor_temp_);
+ }
+
+ return this;
+}
+
// Final type determination.
void
@@ -13216,167 +12841,53 @@ Map_construction_expression::do_check_types(Gogo*)
tree
Map_construction_expression::do_get_tree(Translate_context* context)
{
- Gogo* gogo = context->gogo();
- Location loc = this->location();
-
- Map_type* mt = this->type_->map_type();
-
- // Build a struct to hold the key and value.
- tree struct_type = make_node(RECORD_TYPE);
-
- Type* key_type = mt->key_type();
- tree id = get_identifier("__key");
- tree key_type_tree = type_to_tree(key_type->get_backend(gogo));
- if (key_type_tree == error_mark_node)
- return error_mark_node;
- tree key_field = build_decl(loc.gcc_location(), FIELD_DECL, id,
- key_type_tree);
- DECL_CONTEXT(key_field) = struct_type;
- TYPE_FIELDS(struct_type) = key_field;
-
- Type* val_type = mt->val_type();
- id = get_identifier("__val");
- tree val_type_tree = type_to_tree(val_type->get_backend(gogo));
- if (val_type_tree == error_mark_node)
+ if (this->is_error_expression())
return error_mark_node;
- tree val_field = build_decl(loc.gcc_location(), FIELD_DECL, id,
- val_type_tree);
- DECL_CONTEXT(val_field) = struct_type;
- DECL_CHAIN(key_field) = val_field;
-
- layout_type(struct_type);
+ Location loc = this->location();
- bool is_constant = true;
size_t i = 0;
- tree valaddr;
- tree make_tmp;
-
+ Expression* ventries;
if (this->vals_ == NULL || this->vals_->empty())
- {
- valaddr = null_pointer_node;
- make_tmp = NULL_TREE;
- }
+ ventries = Expression::make_nil(loc);
else
{
- vec<constructor_elt, va_gc> *values;
- vec_alloc(values, this->vals_->size() / 2);
-
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv, ++i)
- {
- bool one_is_constant = true;
-
- vec<constructor_elt, va_gc> *one;
- vec_alloc(one, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = one->quick_push(empty);
- elt->index = key_field;
- tree val_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context, key_type,
- (*pv)->type(),
- val_tree, loc);
- if (elt->value == error_mark_node)
- return error_mark_node;
- if (!TREE_CONSTANT(elt->value))
- one_is_constant = false;
-
- ++pv;
-
- elt = one->quick_push(empty);
- elt->index = val_field;
- val_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context, val_type,
- (*pv)->type(),
- val_tree, loc);
- if (elt->value == error_mark_node)
- return error_mark_node;
- if (!TREE_CONSTANT(elt->value))
- one_is_constant = false;
-
- elt = values->quick_push(empty);
- elt->index = size_int(i);
- elt->value = build_constructor(struct_type, one);
- if (one_is_constant)
- TREE_CONSTANT(elt->value) = 1;
- else
- is_constant = false;
- }
+ go_assert(this->constructor_temp_ != NULL);
+ i = this->vals_->size() / 2;
- tree index_type = build_index_type(size_int(i - 1));
- tree array_type = build_array_type(struct_type, index_type);
- tree init = build_constructor(array_type, values);
- if (is_constant)
- TREE_CONSTANT(init) = 1;
- tree tmp;
- if (current_function_decl != NULL)
- {
- tmp = create_tmp_var(array_type, get_name(array_type));
- DECL_INITIAL(tmp) = init;
- make_tmp = fold_build1_loc(loc.gcc_location(), DECL_EXPR,
- void_type_node, tmp);
- TREE_ADDRESSABLE(tmp) = 1;
- }
- else
- {
- tmp = build_decl(loc.gcc_location(), VAR_DECL,
- create_tmp_var_name("M"), array_type);
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (!TREE_CONSTANT(init))
- make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR,
- void_type_node, tmp, init);
- else
- {
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- DECL_INITIAL(tmp) = init;
- make_tmp = NULL_TREE;
- }
- rest_of_decl_compilation(tmp, 1, 0);
- }
-
- valaddr = build_fold_addr_expr(tmp);
+ Expression* ctor_ref =
+ Expression::make_temporary_reference(this->constructor_temp_, loc);
+ ventries = Expression::make_unary(OPERATOR_AND, ctor_ref, loc);
}
- Bexpression* bdescriptor = mt->map_descriptor_pointer(gogo, loc);
- tree descriptor = expr_to_tree(bdescriptor);
-
- tree type_tree = type_to_tree(this->type_->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
-
- static tree construct_map_fndecl;
- tree call = Gogo::call_builtin(&construct_map_fndecl,
- loc,
- "__go_construct_map",
- 6,
- type_tree,
- TREE_TYPE(descriptor),
- descriptor,
- sizetype,
- size_int(i),
- sizetype,
- TYPE_SIZE_UNIT(struct_type),
- sizetype,
- byte_position(val_field),
- sizetype,
- TYPE_SIZE_UNIT(TREE_TYPE(val_field)),
- const_ptr_type_node,
- fold_convert(const_ptr_type_node, valaddr));
- if (call == error_mark_node)
- return error_mark_node;
-
- tree ret;
- if (make_tmp == NULL)
- ret = call;
- else
- ret = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, type_tree,
- make_tmp, call);
- return ret;
+ Map_type* mt = this->type_->map_type();
+ if (this->element_type_ == NULL)
+ this->element_type_ =
+ Type::make_builtin_struct_type(2,
+ "__key", mt->key_type(),
+ "__val", mt->val_type());
+ Expression* descriptor = Expression::make_map_descriptor(mt, loc);
+
+ Type* uintptr_t = Type::lookup_integer_type("uintptr");
+ mpz_t countval;
+ mpz_init_set_ui(countval, i);
+ Expression* count = Expression::make_integer(&countval, uintptr_t, loc);
+ mpz_clear(countval);
+
+ Expression* entry_size =
+ Expression::make_type_info(this->element_type_, TYPE_INFO_SIZE);
+
+ unsigned int field_index;
+ const Struct_field* valfield =
+ this->element_type_->find_local_field("__val", &field_index);
+ Expression* val_offset =
+ Expression::make_struct_field_offset(this->element_type_, valfield);
+ Expression* val_size =
+ Expression::make_type_info(mt->val_type(), TYPE_INFO_SIZE);
+
+ Expression* map_ctor =
+ Runtime::make_call(Runtime::CONSTRUCT_MAP, loc, 6, descriptor, count,
+ entry_size, val_offset, val_size, ventries);
+ return map_ctor->get_tree(context);
}
// Export an array construction.
@@ -13589,7 +13100,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
}
if (is_pointer)
- ret = Expression::make_heap_composite(ret, this->location());
+ ret = Expression::make_heap_expression(ret, this->location());
return ret;
}
@@ -14031,8 +13542,7 @@ Composite_literal_expression::make_array(
return new Fixed_array_construction_expression(type, indexes, vals,
location);
else
- return new Open_array_construction_expression(type, indexes, vals,
- location);
+ return new Slice_construction_expression(type, indexes, vals, location);
}
// Lower a map composite literal.
@@ -14112,7 +13622,7 @@ Expression::is_composite_literal() const
case EXPRESSION_COMPOSITE_LITERAL:
case EXPRESSION_STRUCT_CONSTRUCTION:
case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
- case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+ case EXPRESSION_SLICE_CONSTRUCTION:
case EXPRESSION_MAP_CONSTRUCTION:
return true;
default:
@@ -14140,10 +13650,10 @@ Expression::is_nonconstant_composite_literal() const
static_cast<const Fixed_array_construction_expression*>(this);
return !pace->is_constant_array();
}
- case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+ case EXPRESSION_SLICE_CONSTRUCTION:
{
- const Open_array_construction_expression *pace =
- static_cast<const Open_array_construction_expression*>(this);
+ const Slice_construction_expression *pace =
+ static_cast<const Slice_construction_expression*>(this);
return !pace->is_constant_array();
}
case EXPRESSION_MAP_CONSTRUCTION:
@@ -14195,6 +13705,21 @@ Type_guard_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+Expression*
+Type_guard_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ if (!this->expr_->is_variable())
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_,
+ this->location());
+ inserter->insert(temp);
+ this->expr_ =
+ Expression::make_temporary_reference(temp, this->location());
+ }
+ return this;
+}
+
// Check types of a type guard expression. The expression must have
// an interface type, but the actual type conversion is checked at run
// time.
@@ -14236,24 +13761,23 @@ Type_guard_expression::do_check_types(Gogo*)
tree
Type_guard_expression::do_get_tree(Translate_context* context)
{
- tree expr_tree = this->expr_->get_tree(context);
- if (expr_tree == error_mark_node)
- return error_mark_node;
+ Expression* conversion;
if (this->type_->interface_type() != NULL)
- return Expression::convert_interface_to_interface(context, this->type_,
- this->expr_->type(),
- expr_tree, true,
- this->location());
+ conversion =
+ Expression::convert_interface_to_interface(this->type_, this->expr_,
+ true, this->location());
else
- return Expression::convert_for_assignment(context, this->type_,
- this->expr_->type(), expr_tree,
- this->location());
+ conversion =
+ Expression::convert_for_assignment(context->gogo(), this->type_,
+ this->expr_, this->location());
+
+ return conversion->get_tree(context);
}
// Dump ast representation for a type guard expression.
void
-Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
+Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
const
{
this->expr_->dump_expression(ast_dump_context);
@@ -14270,16 +13794,16 @@ Expression::make_type_guard(Expression* expr, Type* type,
return new Type_guard_expression(expr, type, location);
}
-// Class Heap_composite_expression.
+// Class Heap_expression.
-// When you take the address of a composite literal, it is allocated
+// When you take the address of an escaping expression, it is allocated
// on the heap. This class implements that.
-class Heap_composite_expression : public Expression
+class Heap_expression : public Expression
{
public:
- Heap_composite_expression(Expression* expr, Location location)
- : Expression(EXPRESSION_HEAP_COMPOSITE, location),
+ Heap_expression(Expression* expr, Location location)
+ : Expression(EXPRESSION_HEAP, location),
expr_(expr)
{ }
@@ -14299,8 +13823,8 @@ class Heap_composite_expression : public Expression
Expression*
do_copy()
{
- return Expression::make_heap_composite(this->expr_->copy(),
- this->location());
+ return Expression::make_heap_expression(this->expr_->copy(),
+ this->location());
}
tree
@@ -14316,38 +13840,45 @@ class Heap_composite_expression : public Expression
do_dump_expression(Ast_dump_context*) const;
private:
- // The composite literal which is being put on the heap.
+ // The expression which is being put on the heap.
Expression* expr_;
};
-// Return a tree which allocates a composite literal on the heap.
+// Return a tree which allocates an expression on the heap.
tree
-Heap_composite_expression::do_get_tree(Translate_context* context)
+Heap_expression::do_get_tree(Translate_context* context)
{
tree expr_tree = this->expr_->get_tree(context);
if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node)
return error_mark_node;
- tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree));
- go_assert(TREE_CODE(expr_size) == INTEGER_CST);
- tree space = context->gogo()->allocate_memory(this->expr_->type(),
- expr_size, this->location());
- space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space);
+
+ Expression* alloc =
+ Expression::make_allocation(this->expr_->type(), this->location());
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->expr_->type()->get_backend(gogo);
+ size_t expr_size = gogo->backend()->type_size(btype);
+ tree space = alloc->get_tree(context);
+ if (expr_size == 0)
+ return space;
+
space = save_expr(space);
tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
space);
TREE_THIS_NOTRAP(ref) = 1;
- tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space),
+ tree ret = build2(COMPOUND_EXPR,
+ type_to_tree(this->type()->get_backend(gogo)),
build2(MODIFY_EXPR, void_type_node, ref, expr_tree),
space);
SET_EXPR_LOCATION(ret, this->location().gcc_location());
return ret;
}
-// Dump ast representation for a heap composite expression.
+// Dump ast representation for a heap expression.
void
-Heap_composite_expression::do_dump_expression(
+Heap_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
ast_dump_context->ostream() << "&(";
@@ -14355,12 +13886,12 @@ Heap_composite_expression::do_dump_expression(
ast_dump_context->ostream() << ")";
}
-// Allocate a composite literal on the heap.
+// Allocate an expression on the heap.
Expression*
-Expression::make_heap_composite(Expression* expr, Location location)
+Expression::make_heap_expression(Expression* expr, Location location)
{
- return new Heap_composite_expression(expr, location);
+ return new Heap_expression(expr, location);
}
// Class Receive_expression.
@@ -14399,6 +13930,32 @@ Receive_expression::do_check_types(Gogo*)
}
}
+// Flattening for receive expressions creates a temporary variable to store
+// received data in for receives.
+
+Expression*
+Receive_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Channel_type* channel_type = this->channel_->type()->channel_type();
+ if (channel_type == NULL)
+ {
+ go_assert(saw_errors());
+ return this;
+ }
+
+ Type* element_type = channel_type->element_type();
+ if (this->temp_receiver_ == NULL)
+ {
+ this->temp_receiver_ = Statement::make_temporary(element_type, NULL,
+ this->location());
+ this->temp_receiver_->set_is_address_taken();
+ inserter->insert(this->temp_receiver_);
+ }
+
+ return this;
+}
+
// Get a tree for a receive expression.
tree
@@ -14412,19 +13969,18 @@ Receive_expression::do_get_tree(Translate_context* context)
go_assert(this->channel_->type()->is_error());
return error_mark_node;
}
-
Expression* td = Expression::make_type_descriptor(channel_type, loc);
- tree td_tree = td->get_tree(context);
-
- Type* element_type = channel_type->element_type();
- Btype* element_type_btype = element_type->get_backend(context->gogo());
- tree element_type_tree = type_to_tree(element_type_btype);
-
- tree channel = this->channel_->get_tree(context);
- if (element_type_tree == error_mark_node || channel == error_mark_node)
- return error_mark_node;
- return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc);
+ Expression* recv_ref =
+ Expression::make_temporary_reference(this->temp_receiver_, loc);
+ Expression* recv_addr =
+ Expression::make_temporary_reference(this->temp_receiver_, loc);
+ recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc);
+ Expression* recv =
+ Runtime::make_call(Runtime::RECEIVE, loc, 3,
+ td, this->channel_, recv_addr);
+ recv = Expression::make_compound(recv, recv_ref, loc);
+ return recv->get_tree(context);
}
// Dump ast representation for a receive expression.
@@ -14725,6 +14281,101 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info,
return new Slice_info_expression(slice, slice_info, location);
}
+// An expression that represents a slice value: a struct with value pointer,
+// length, and capacity fields.
+
+class Slice_value_expression : public Expression
+{
+ public:
+ Slice_value_expression(Type* type, Expression* valptr, Expression* len,
+ Expression* cap, Location location)
+ : Expression(EXPRESSION_SLICE_VALUE, location),
+ type_(type), valptr_(valptr), len_(len), cap_(cap)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type()
+ { return this->type_; }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new Slice_value_expression(this->type_, this->valptr_->copy(),
+ this->len_->copy(), this->cap_->copy(),
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The type of the slice value.
+ Type* type_;
+ // The pointer to the values in the slice.
+ Expression* valptr_;
+ // The length of the slice.
+ Expression* len_;
+ // The capacity of the slice.
+ Expression* cap_;
+};
+
+int
+Slice_value_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+tree
+Slice_value_expression::do_get_tree(Translate_context* context)
+{
+ std::vector<Bexpression*> vals(3);
+ vals[0] = tree_to_expr(this->valptr_->get_tree(context));
+ vals[1] = tree_to_expr(this->len_->get_tree(context));
+ vals[2] = tree_to_expr(this->cap_->get_tree(context));
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->type_->get_backend(gogo);
+ Bexpression* ret =
+ gogo->backend()->constructor_expression(btype, vals, this->location());
+ return expr_to_tree(ret);
+}
+
+void
+Slice_value_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "slicevalue(";
+ ast_dump_context->ostream() << "values: ";
+ this->valptr_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", length: ";
+ this->len_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", capacity: ";
+ this->cap_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_slice_value(Type* at, Expression* valptr, Expression* len,
+ Expression* cap, Location location)
+{
+ go_assert(at->is_slice_type());
+ return new Slice_value_expression(at, valptr, len, cap, location);
+}
// An expression that evaluates to some characteristic of a non-empty interface.
// This is used to access the method table or underlying object of an interface.
@@ -14733,7 +14384,7 @@ class Interface_info_expression : public Expression
{
public:
Interface_info_expression(Expression* iface, Interface_info iface_info,
- Location location)
+ Location location)
: Expression(EXPRESSION_INTERFACE_INFO, location),
iface_(iface), iface_info_(iface_info)
{ }
@@ -14779,9 +14430,12 @@ Interface_info_expression::do_type()
{
case INTERFACE_INFO_METHODS:
{
+ Type* pdt = Type::make_type_descriptor_ptr_type();
+ if (this->iface_->type()->interface_type()->is_empty())
+ return pdt;
+
Location loc = this->location();
Struct_field_list* sfl = new Struct_field_list();
- Type* pdt = Type::make_type_descriptor_ptr_type();
sfl->push_back(
Struct_field(Typed_identifier("__type_descriptor", pdt, loc)));
@@ -14855,11 +14509,13 @@ void
Interface_info_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
+ bool is_empty = this->iface_->type()->interface_type()->is_empty();
ast_dump_context->ostream() << "interfaceinfo(";
this->iface_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ",";
ast_dump_context->ostream() <<
- (this->iface_info_ == INTERFACE_INFO_METHODS ? "methods"
+ (this->iface_info_ == INTERFACE_INFO_METHODS && !is_empty ? "methods"
+ : this->iface_info_ == INTERFACE_INFO_TYPE_DESCRIPTOR ? "type_descriptor"
: this->iface_info_ == INTERFACE_INFO_OBJECT ? "object"
: "unknown");
ast_dump_context->ostream() << ")";
@@ -14874,6 +14530,303 @@ Expression::make_interface_info(Expression* iface, Interface_info iface_info,
return new Interface_info_expression(iface, iface_info, location);
}
+// An expression that represents an interface value. The first field is either
+// a type descriptor for an empty interface or a pointer to the interface method
+// table for a non-empty interface. The second field is always the object.
+
+class Interface_value_expression : public Expression
+{
+ public:
+ Interface_value_expression(Type* type, Expression* first_field,
+ Expression* obj, Location location)
+ : Expression(EXPRESSION_INTERFACE_VALUE, location),
+ type_(type), first_field_(first_field), obj_(obj)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type()
+ { return this->type_; }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new Interface_value_expression(this->type_,
+ this->first_field_->copy(),
+ this->obj_->copy(), this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The type of the interface value.
+ Type* type_;
+ // The first field of the interface (either a type descriptor or a pointer
+ // to the method table.
+ Expression* first_field_;
+ // The underlying object of the interface.
+ Expression* obj_;
+};
+
+int
+Interface_value_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->first_field_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->obj_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+tree
+Interface_value_expression::do_get_tree(Translate_context* context)
+{
+ std::vector<Bexpression*> vals(2);
+ vals[0] = tree_to_expr(this->first_field_->get_tree(context));
+ vals[1] = tree_to_expr(this->obj_->get_tree(context));
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->type_->get_backend(gogo);
+ Bexpression* ret =
+ gogo->backend()->constructor_expression(btype, vals, this->location());
+ return expr_to_tree(ret);
+}
+
+void
+Interface_value_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "interfacevalue(";
+ ast_dump_context->ostream() <<
+ (this->type_->interface_type()->is_empty()
+ ? "type_descriptor: "
+ : "methods: ");
+ this->first_field_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", object: ";
+ this->obj_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_interface_value(Type* type, Expression* first_value,
+ Expression* object, Location location)
+{
+ return new Interface_value_expression(type, first_value, object, location);
+}
+
+// An interface method table for a pair of types: an interface type and a type
+// that implements that interface.
+
+class Interface_mtable_expression : public Expression
+{
+ public:
+ Interface_mtable_expression(Interface_type* itype, Type* type,
+ bool is_pointer, Location location)
+ : Expression(EXPRESSION_INTERFACE_MTABLE, location),
+ itype_(itype), type_(type), is_pointer_(is_pointer),
+ method_table_type_(NULL), bvar_(NULL)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type();
+
+ bool
+ is_immutable() const
+ { return true; }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new Interface_mtable_expression(this->itype_, this->type_,
+ this->is_pointer_, this->location());
+ }
+
+ bool
+ do_is_addressable() const
+ { return true; }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The interface type for which the methods are defined.
+ Interface_type* itype_;
+ // The type to construct the interface method table for.
+ Type* type_;
+ // Whether this table contains the method set for the receiver type or the
+ // pointer receiver type.
+ bool is_pointer_;
+ // The type of the method table.
+ Type* method_table_type_;
+ // The backend variable that refers to the interface method table.
+ Bvariable* bvar_;
+};
+
+int
+Interface_mtable_expression::do_traverse(Traverse* traverse)
+{
+ if (Type::traverse(this->itype_, traverse) == TRAVERSE_EXIT
+ || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+Type*
+Interface_mtable_expression::do_type()
+{
+ if (this->method_table_type_ != NULL)
+ return this->method_table_type_;
+
+ const Typed_identifier_list* interface_methods = this->itype_->methods();
+ go_assert(!interface_methods->empty());
+
+ Struct_field_list* sfl = new Struct_field_list;
+ Typed_identifier tid("__type_descriptor", Type::make_type_descriptor_ptr_type(),
+ this->location());
+ sfl->push_back(Struct_field(tid));
+ for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+ p != interface_methods->end();
+ ++p)
+ sfl->push_back(Struct_field(*p));
+ this->method_table_type_ = Type::make_struct_type(sfl, this->location());
+ return this->method_table_type_;
+}
+
+tree
+Interface_mtable_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+ Bexpression* ret;
+ Location loc = Linemap::predeclared_location();
+ if (this->bvar_ != NULL)
+ {
+ ret = gogo->backend()->var_expression(this->bvar_, this->location());
+ return expr_to_tree(ret);
+ }
+
+ const Typed_identifier_list* interface_methods = this->itype_->methods();
+ go_assert(!interface_methods->empty());
+
+ std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_")
+ + this->itype_->mangled_name(gogo)
+ + "__"
+ + this->type_->mangled_name(gogo));
+
+ // See whether this interface has any hidden methods.
+ bool has_hidden_methods = false;
+ for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+ p != interface_methods->end();
+ ++p)
+ {
+ if (Gogo::is_hidden_name(p->name()))
+ {
+ has_hidden_methods = true;
+ break;
+ }
+ }
+
+ // We already know that the named type is convertible to the
+ // interface. If the interface has hidden methods, and the named
+ // type is defined in a different package, then the interface
+ // conversion table will be defined by that other package.
+ if (has_hidden_methods
+ && this->type_->named_type() != NULL
+ && this->type_->named_type()->named_object()->package() != NULL)
+ {
+ Btype* btype = this->type()->get_backend(gogo);
+ this->bvar_ =
+ gogo->backend()->immutable_struct_reference(mangled_name, btype, loc);
+ ret = gogo->backend()->var_expression(this->bvar_, this->location());
+ return expr_to_tree(ret);
+ }
+
+ // The first element is the type descriptor.
+ Type* td_type;
+ if (!this->is_pointer_)
+ td_type = this->type_;
+ else
+ td_type = Type::make_pointer_type(this->type_);
+
+ // Build an interface method table for a type: a type descriptor followed by a
+ // list of function pointers, one for each interface method. This is used for
+ // interfaces.
+ Expression_list* svals = new Expression_list();
+ svals->push_back(Expression::make_type_descriptor(td_type, loc));
+
+ Named_type* nt = this->type_->named_type();
+ Struct_type* st = this->type_->struct_type();
+ go_assert(nt != NULL || st != NULL);
+
+ for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+ p != interface_methods->end();
+ ++p)
+ {
+ bool is_ambiguous;
+ Method* m;
+ if (nt != NULL)
+ m = nt->method_function(p->name(), &is_ambiguous);
+ else
+ m = st->method_function(p->name(), &is_ambiguous);
+ go_assert(m != NULL);
+ Named_object* no = m->named_object();
+
+ go_assert(no->is_function() || no->is_function_declaration());
+ svals->push_back(Expression::make_func_code_reference(no, loc));
+ }
+
+ Btype* btype = this->type()->get_backend(gogo);
+ Expression* mtable = Expression::make_struct_composite_literal(this->type(),
+ svals, loc);
+ Bexpression* ctor = tree_to_expr(mtable->get_tree(context));
+
+ bool is_public = has_hidden_methods && this->type_->named_type() != NULL;
+ this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false,
+ !is_public, btype, loc);
+ gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false,
+ !is_public, btype, loc, ctor);
+ ret = gogo->backend()->var_expression(this->bvar_, loc);
+ return expr_to_tree(ret);
+}
+
+void
+Interface_mtable_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "__go_"
+ << (this->is_pointer_ ? "pimt__" : "imt_");
+ ast_dump_context->dump_type(this->itype_);
+ ast_dump_context->ostream() << "__";
+ ast_dump_context->dump_type(this->type_);
+}
+
+Expression*
+Expression::make_interface_mtable_ref(Interface_type* itype, Type* type,
+ bool is_pointer, Location location)
+{
+ return new Interface_mtable_expression(itype, type, is_pointer, location);
+}
+
// An expression which evaluates to the offset of a field within a
// struct. This, like Type_info_expression, q.v., is only used to
// initialize fields of a type descriptor.
@@ -15082,12 +15035,14 @@ class Conditional_expression : public Expression
{}
protected:
+ int
+ do_traverse(Traverse*);
+
Type*
do_type();
void
- do_determine_type(const Type_context*)
- { }
+ do_determine_type(const Type_context*);
Expression*
do_copy()
@@ -15111,13 +15066,26 @@ class Conditional_expression : public Expression
Expression* else_;
};
+// Traversal.
+
+int
+Conditional_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->cond_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->then_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->else_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
// Return the type of the conditional expression.
Type*
Conditional_expression::do_type()
{
Type* result_type = Type::make_void_type();
- if (this->then_->type() == this->else_->type())
+ if (Type::are_identical(this->then_->type(), this->else_->type(), false,
+ NULL))
result_type = this->then_->type();
else if (this->then_->is_nil_expression()
|| this->else_->is_nil_expression())
@@ -15127,6 +15095,16 @@ Conditional_expression::do_type()
return result_type;
}
+// Determine type for a conditional expression.
+
+void
+Conditional_expression::do_determine_type(const Type_context* context)
+{
+ this->cond_->determine_type_no_context();
+ this->then_->determine_type(context);
+ this->else_->determine_type(context);
+}
+
// Get the backend representation of a conditional expression.
tree
@@ -15167,6 +15145,108 @@ Expression::make_conditional(Expression* cond, Expression* then,
return new Conditional_expression(cond, then, else_expr, location);
}
+// Compound expressions.
+
+class Compound_expression : public Expression
+{
+ public:
+ Compound_expression(Expression* init, Expression* expr, Location location)
+ : Expression(EXPRESSION_COMPOUND, location), init_(init), expr_(expr)
+ {}
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*);
+
+ Expression*
+ do_copy()
+ {
+ return new Compound_expression(this->init_->copy(), this->expr_->copy(),
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The expression that is evaluated first and discarded.
+ Expression* init_;
+ // The expression that is evaluated and returned.
+ Expression* expr_;
+};
+
+// Traversal.
+
+int
+Compound_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+// Return the type of the compound expression.
+
+Type*
+Compound_expression::do_type()
+{
+ return this->expr_->type();
+}
+
+// Determine type for a compound expression.
+
+void
+Compound_expression::do_determine_type(const Type_context* context)
+{
+ this->init_->determine_type_no_context();
+ this->expr_->determine_type(context);
+}
+
+// Get the backend representation of a compound expression.
+
+tree
+Compound_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+ Bexpression* binit = tree_to_expr(this->init_->get_tree(context));
+ Bstatement* init_stmt = gogo->backend()->expression_statement(binit);
+ Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+ Bexpression* ret = gogo->backend()->compound_expression(init_stmt, bexpr,
+ this->location());
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation of a conditional expression.
+
+void
+Compound_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "(";
+ ast_dump_context->dump_expression(this->init_);
+ ast_dump_context->ostream() << ",";
+ ast_dump_context->dump_expression(this->expr_);
+ ast_dump_context->ostream() << ") ";
+}
+
+// Make a compound expression.
+
+Expression*
+Expression::make_compound(Expression* init, Expression* expr, Location location)
+{
+ return new Compound_expression(init, expr, location);
+}
+
// Import an expression. This comes at the end in order to see the
// various class definitions.