===================================================================
@@ -6473,11 +6473,11 @@ Expression::make_binary(Operator op, Exp
tree
Expression::comparison_tree(Translate_context* context, Type* result_type,
- Operator op, Expression* left_expr,
- Expression* right_expr, Location location)
+ Operator op, Expression* left, Expression* right,
+ Location location)
{
- Type* left_type = left_expr->type();
- Type* right_type = right_expr->type();
+ Type* left_type = left->type();
+ Type* right_type = right->type();
mpz_t zval;
mpz_init_set_ui(zval, 0UL);
@@ -6509,17 +6509,11 @@ Expression::comparison_tree(Translate_co
go_unreachable();
}
- // FIXME: Computing the tree here means it will be computed multiple times,
- // which is wasteful. This is a temporary modification until all tree code
- // here can be replaced with frontend expressions.
- tree left_tree = left_expr->get_tree(context);
- tree right_tree = right_expr->get_tree(context);
if (left_type->is_string_type() && right_type->is_string_type())
{
- Expression* strcmp_call = Runtime::make_call(Runtime::STRCMP, location, 2,
- left_expr, right_expr);
- left_tree = strcmp_call->get_tree(context);
- right_tree = zexpr->get_tree(context);
+ left = Runtime::make_call(Runtime::STRCMP, location, 2,
+ left, right);
+ right = zexpr;
}
else if ((left_type->interface_type() != NULL
&& right_type->interface_type() == NULL
@@ -6532,31 +6526,30 @@ Expression::comparison_tree(Translate_co
if (left_type->interface_type() == NULL)
{
std::swap(left_type, right_type);
- std::swap(left_expr, right_expr);
+ std::swap(left, right);
}
// The right operand is not an interface. We need to take its
// address if it is not a pointer.
Expression* pointer_arg = NULL;
if (right_type->points_to() != NULL)
- pointer_arg = right_expr;
+ pointer_arg = right;
else
{
- go_assert(right_expr->is_addressable());
- pointer_arg = Expression::make_unary(OPERATOR_AND, right_expr,
+ go_assert(right->is_addressable());
+ pointer_arg = Expression::make_unary(OPERATOR_AND, right,
location);
}
- Expression* descriptor_expr = Expression::make_type_descriptor(right_type,
- location);
- Call_expression* iface_valcmp =
+ Expression* descriptor =
+ Expression::make_type_descriptor(right_type, location);
+ left =
Runtime::make_call((left_type->interface_type()->is_empty()
? Runtime::EMPTY_INTERFACE_VALUE_COMPARE
: Runtime::INTERFACE_VALUE_COMPARE),
- location, 3, left_expr, descriptor_expr,
+ location, 3, left, descriptor,
pointer_arg);
- left_tree = iface_valcmp->get_tree(context);
- right_tree = zexpr->get_tree(context);
+ right = zexpr;
}
else if (left_type->interface_type() != NULL
&& right_type->interface_type() != NULL)
@@ -6574,56 +6567,42 @@ Expression::comparison_tree(Translate_co
{
go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
std::swap(left_type, right_type);
- std::swap(left_expr, right_expr);
+ std::swap(left, right);
}
go_assert(!left_type->interface_type()->is_empty());
go_assert(right_type->interface_type()->is_empty());
compare_function = Runtime::INTERFACE_EMPTY_COMPARE;
}
- Call_expression* ifacecmp_call =
- Runtime::make_call(compare_function, location, 2,
- left_expr, right_expr);
-
- left_tree = ifacecmp_call->get_tree(context);
- right_tree = zexpr->get_tree(context);
+ left = Runtime::make_call(compare_function, location, 2, left, right);
+ right = zexpr;
}
if (left_type->is_nil_type()
&& (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ))
{
std::swap(left_type, right_type);
- std::swap(left_tree, right_tree);
- std::swap(left_expr, right_expr);
+ std::swap(left, right);
}
if (right_type->is_nil_type())
{
+ right = Expression::make_nil(location);
if (left_type->array_type() != NULL
&& left_type->array_type()->length() == NULL)
{
Array_type* at = left_type->array_type();
- left_expr = at->get_value_pointer(context->gogo(), left_expr);
- left_tree = left_expr->get_tree(context);
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+ left = at->get_value_pointer(context->gogo(), left);
}
else if (left_type->interface_type() != NULL)
{
// An interface is nil if the first field is nil.
- tree left_type_tree = TREE_TYPE(left_tree);
- go_assert(TREE_CODE(left_type_tree) == RECORD_TYPE);
- tree field = TYPE_FIELDS(left_type_tree);
- left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree,
- field, NULL_TREE);
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
- }
- else
- {
- go_assert(POINTER_TYPE_P(TREE_TYPE(left_tree)));
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+ left = Expression::make_field_reference(left, 0, location);
}
}
+ tree left_tree = left->get_tree(context);
+ tree right_tree = right->get_tree(context);
if (left_tree == error_mark_node || right_tree == error_mark_node)
return error_mark_node;
@@ -9745,21 +9724,13 @@ Call_expression::do_must_eval_in_order()
// Get the function and the first argument to use when calling an
// interface method.
-tree
+Expression*
Call_expression::interface_method_function(
- Translate_context* context,
Interface_field_reference_expression* interface_method,
- tree* first_arg_ptr)
+ Expression** first_arg_ptr)
{
- tree expr = interface_method->expr()->get_tree(context);
- if (expr == error_mark_node)
- return error_mark_node;
- expr = save_expr(expr);
- tree first_arg = interface_method->get_underlying_object_tree(context, expr);
- if (first_arg == error_mark_node)
- return error_mark_node;
- *first_arg_ptr = first_arg;
- return interface_method->get_function_tree(context, expr);
+ *first_arg_ptr = interface_method->get_underlying_object();
+ return interface_method->get_function();
}
// Build the call expression.
@@ -9889,8 +9860,12 @@ Call_expression::do_get_tree(Translate_c
}
else
{
- fn = this->interface_method_function(context, interface_method,
- &args[0]);
+ 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;
@@ -11623,58 +11598,39 @@ Expression::make_field_reference(Express
// Class Interface_field_reference_expression.
-// Return a tree for the pointer to the function to call.
+// Return an expression for the pointer to the function to call.
-tree
-Interface_field_reference_expression::get_function_tree(Translate_context*,
- tree expr)
+Expression*
+Interface_field_reference_expression::get_function()
{
- if (this->expr_->type()->points_to() != NULL)
- expr = build_fold_indirect_ref(expr);
-
- tree expr_type = TREE_TYPE(expr);
- go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
- tree field = TYPE_FIELDS(expr_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
-
- tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
- go_assert(POINTER_TYPE_P(TREE_TYPE(table)));
+ Expression* ref = this->expr_;
+ Location loc = this->location();
+ if (ref->type()->points_to() != NULL)
+ ref = Expression::make_unary(OPERATOR_MULT, ref, loc);
- table = build_fold_indirect_ref(table);
- go_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE);
+ Expression* mtable =
+ Expression::make_interface_info(ref, INTERFACE_INFO_METHODS, loc);
+ Struct_type* mtable_type = mtable->type()->points_to()->struct_type();
std::string name = Gogo::unpack_hidden_name(this->name_);
- for (field = DECL_CHAIN(TYPE_FIELDS(TREE_TYPE(table)));
- field != NULL_TREE;
- field = DECL_CHAIN(field))
- {
- if (name == IDENTIFIER_POINTER(DECL_NAME(field)))
- break;
- }
- go_assert(field != NULL_TREE);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), table, field, NULL_TREE);
+ unsigned int index;
+ const Struct_field* field = mtable_type->find_local_field(name, &index);
+ go_assert(field != NULL);
+ mtable = Expression::make_unary(OPERATOR_MULT, mtable, loc);
+ return Expression::make_field_reference(mtable, index, loc);
}
-// Return a tree for the first argument to pass to the interface
+// Return an expression for the first argument to pass to the interface
// function.
-tree
-Interface_field_reference_expression::get_underlying_object_tree(
- Translate_context*,
- tree expr)
+Expression*
+Interface_field_reference_expression::get_underlying_object()
{
- if (this->expr_->type()->points_to() != NULL)
- expr = build_fold_indirect_ref(expr);
-
- tree expr_type = TREE_TYPE(expr);
- go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(TYPE_FIELDS(expr_type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
+ Expression* expr = this->expr_;
+ if (expr->type()->points_to() != NULL)
+ expr = Expression::make_unary(OPERATOR_MULT, expr, this->location());
+ return Expression::make_interface_info(expr, INTERFACE_INFO_OBJECT,
+ this->location());
}
// Traversal.
@@ -11694,9 +11650,7 @@ Interface_field_reference_expression::do
Statement_inserter* inserter,
int)
{
- if (this->expr_->var_expression() == NULL
- && this->expr_->temporary_reference_expression() == NULL
- && this->expr_->set_and_use_temporary_expression() == NULL)
+ if (!this->expr_->is_variable())
{
Temporary_statement* temp =
Statement::make_temporary(this->expr_->type(), NULL, this->location());
@@ -11923,30 +11877,22 @@ Interface_field_reference_expression::do
Expression* expr = Expression::make_struct_composite_literal(st, vals, loc);
expr = Expression::make_heap_composite(expr, loc);
- tree closure_tree = expr->get_tree(context);
+ Bexpression* bclosure = tree_to_expr(expr->get_tree(context));
+ Expression* nil_check =
+ Expression::make_binary(OPERATOR_EQEQ, this->expr_,
+ Expression::make_nil(loc), loc);
+ Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(context));
- // Note that we are evaluating this->expr_ twice, but that is OK
- // because in the lowering pass we forced it into a temporary
- // variable.
- tree nil_check_tree = Expression::comparison_tree(context,
- Type::lookup_bool_type(),
- OPERATOR_EQEQ,
- this->expr_,
- Expression::make_nil(loc),
- loc);
- Expression* crash_expr =
- context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc);
- tree crash = crash_expr->get_tree(context);
- if (closure_tree == error_mark_node
- || nil_check_tree == error_mark_node
- || crash == error_mark_node)
- return error_mark_node;
- return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(closure_tree),
- build3_loc(loc.gcc_location(), COND_EXPR,
- void_type_node, nil_check_tree, crash,
- NULL_TREE),
- closure_tree);
+ Gogo* gogo = context->gogo();
+ Expression* crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc);
+ Bexpression* bcrash = tree_to_expr(crash->get_tree(context));
+
+ Bexpression* bcond =
+ gogo->backend()->conditional_expression(bnil_check, bcrash, NULL, loc);
+ Bstatement* cond_statement = gogo->backend()->expression_statement(bcond);
+ Bexpression* ret =
+ gogo->backend()->compound_expression(cond_statement, bclosure, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for an interface field reference.
@@ -14754,6 +14700,155 @@ Expression::make_slice_info(Expression*
return new Slice_info_expression(slice, slice_info, 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.
+
+class Interface_info_expression : public Expression
+{
+ public:
+ Interface_info_expression(Expression* iface, Interface_info iface_info,
+ Location location)
+ : Expression(EXPRESSION_INTERFACE_INFO, location),
+ iface_(iface), iface_info_(iface_info)
+ { }
+
+ protected:
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*)
+ { }
+
+ Expression*
+ do_copy()
+ {
+ return new Interface_info_expression(this->iface_->copy(),
+ this->iface_info_, this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ void
+ do_issue_nil_check()
+ { this->iface_->issue_nil_check(); }
+
+ private:
+ // The interface for which we are getting information.
+ Expression* iface_;
+ // What information we want.
+ Interface_info iface_info_;
+};
+
+// Return the type of the interface info.
+
+Type*
+Interface_info_expression::do_type()
+{
+ switch (this->iface_info_)
+ {
+ case INTERFACE_INFO_METHODS:
+ {
+ 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)));
+
+ Interface_type* itype = this->iface_->type()->interface_type();
+ for (Typed_identifier_list::const_iterator p = itype->methods()->begin();
+ p != itype->methods()->end();
+ ++p)
+ {
+ Function_type* ft = p->type()->function_type();
+ go_assert(ft->receiver() == NULL);
+
+ const Typed_identifier_list* params = ft->parameters();
+ Typed_identifier_list* mparams = new Typed_identifier_list();
+ if (params != NULL)
+ mparams->reserve(params->size() + 1);
+ Type* vt = Type::make_pointer_type(Type::make_void_type());
+ mparams->push_back(Typed_identifier("", vt, ft->location()));
+ if (params != NULL)
+ {
+ for (Typed_identifier_list::const_iterator pp = params->begin();
+ pp != params->end();
+ ++pp)
+ mparams->push_back(*pp);
+ }
+
+ Typed_identifier_list* mresults = (ft->results() == NULL
+ ? NULL
+ : ft->results()->copy());
+ Backend_function_type* mft =
+ Type::make_backend_function_type(NULL, mparams, mresults,
+ ft->location());
+
+ std::string fname = Gogo::unpack_hidden_name(p->name());
+ sfl->push_back(Struct_field(Typed_identifier(fname, mft, loc)));
+ }
+
+ return Type::make_pointer_type(Type::make_struct_type(sfl, loc));
+ }
+ case INTERFACE_INFO_OBJECT:
+ return Type::make_pointer_type(Type::make_void_type());
+ default:
+ go_unreachable();
+ }
+}
+
+// Return interface information in GENERIC.
+
+tree
+Interface_info_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+
+ Bexpression* biface = tree_to_expr(this->iface_->get_tree(context));
+ Bexpression* ret;
+ switch (this->iface_info_)
+ {
+ case INTERFACE_INFO_METHODS:
+ case INTERFACE_INFO_OBJECT:
+ ret = gogo->backend()->struct_field_expression(biface, this->iface_info_,
+ this->location());
+ break;
+ default:
+ go_unreachable();
+ }
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation for an interface info expression.
+
+void
+Interface_info_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ 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_OBJECT ? "object"
+ : "unknown");
+ ast_dump_context->ostream() << ")";
+}
+
+// Make an interface info expression.
+
+Expression*
+Expression::make_interface_info(Expression* iface, Interface_info iface_info,
+ Location location)
+{
+ return new Interface_info_expression(iface, iface_info, 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.
===================================================================
@@ -103,6 +103,7 @@ class Expression
EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_TYPE_INFO,
EXPRESSION_SLICE_INFO,
+ EXPRESSION_INTERFACE_INFO,
EXPRESSION_STRUCT_FIELD_OFFSET,
EXPRESSION_MAP_DESCRIPTOR,
EXPRESSION_LABEL_ADDR
@@ -356,6 +357,21 @@ class Expression
static Expression*
make_slice_info(Expression* slice, Slice_info, Location);
+
+ // Make an expression that evaluates to some characteristic of a
+ // interface. For simplicity, the enum values must match the field indexes
+ // of a non-empty interface in the underlying struct.
+ enum Interface_info
+ {
+ // The methods of an interface.
+ INTERFACE_INFO_METHODS,
+ // The first argument to pass to an interface method.
+ INTERFACE_INFO_OBJECT
+ };
+
+ static Expression*
+ make_interface_info(Expression* iface, Interface_info, Location);
+
// Make an expression which evaluates to the offset of a field in a
// struct. This is only used for type descriptors, so there is no
// location parameter.
@@ -1508,10 +1524,9 @@ class Call_expression : public Expressio
bool
check_argument_type(int, const Type*, const Type*, Location, bool);
- tree
- interface_method_function(Translate_context*,
- Interface_field_reference_expression*,
- tree*);
+ Expression*
+ interface_method_function(Interface_field_reference_expression*,
+ Expression**);
tree
set_results(Translate_context*, tree);
@@ -2115,16 +2130,14 @@ class Interface_field_reference_expressi
static Named_object*
create_thunk(Gogo*, Interface_type* type, const std::string& name);
- // Return a tree for the pointer to the function to call, given a
- // tree for the expression.
- tree
- get_function_tree(Translate_context*, tree);
+ // Return an expression for the pointer to the function to call.
+ Expression*
+ get_function();
- // Return a tree for the first argument to pass to the interface
- // function, given a tree for the expression. This is the real
- // object associated with the interface object.
- tree
- get_underlying_object_tree(Translate_context*, tree);
+ // Return an expression for the first argument to pass to the interface
+ // function. This is the real object associated with the interface object.
+ Expression*
+ get_underlying_object();
protected:
int
===================================================================
@@ -284,6 +284,16 @@ class Backend
virtual Bexpression*
struct_field_expression(Bexpression* bstruct, size_t index, Location) = 0;
+ // Create an expression that executes BSTAT before BEXPR.
+ virtual Bexpression*
+ compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0;
+
+ // Return an expression that executes THEN_EXPR if CONDITION is true, or
+ // ELSE_EXPR otherwise. ELSE_EXPR may be NULL.
+ virtual Bexpression*
+ conditional_expression(Bexpression* condition, Bexpression* then_expr,
+ Bexpression* else_expr, Location) = 0;
+
// Statements.
// Create an error statement. This is used for cases which should
===================================================================
@@ -246,6 +246,12 @@ class Gcc_backend : public Backend
Bexpression*
struct_field_expression(Bexpression*, size_t, Location);
+ Bexpression*
+ compound_expression(Bstatement*, Bexpression*, Location);
+
+ Bexpression*
+ conditional_expression(Bexpression*, Bexpression*, Bexpression*, Location);
+
// Statements.
Bstatement*
@@ -1034,6 +1040,41 @@ Gcc_backend::struct_field_expression(Bex
return tree_to_expr(ret);
}
+// Return an expression that executes BSTAT before BEXPR.
+
+Bexpression*
+Gcc_backend::compound_expression(Bstatement* bstat, Bexpression* bexpr,
+ Location location)
+{
+ tree stat = bstat->get_tree();
+ tree expr = bexpr->get_tree();
+ if (stat == error_mark_node || expr == error_mark_node)
+ return this->error_expression();
+ tree ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
+ TREE_TYPE(expr), stat, expr);
+ return this->make_expression(ret);
+}
+
+// Return an expression that executes THEN_EXPR if CONDITION is true, or
+// ELSE_EXPR otherwise.
+
+Bexpression*
+Gcc_backend::conditional_expression(Bexpression* condition,
+ Bexpression* then_expr,
+ Bexpression* else_expr, Location location)
+{
+ tree cond_tree = condition->get_tree();
+ tree then_tree = then_expr->get_tree();
+ tree else_tree = else_expr == NULL ? NULL_TREE : else_expr->get_tree();
+ if (cond_tree == error_mark_node
+ || then_tree == error_mark_node
+ || else_tree == error_mark_node)
+ return this->error_expression();
+ tree ret = build3_loc(location.gcc_location(), COND_EXPR, void_type_node,
+ cond_tree, then_tree, else_tree);
+ return this->make_expression(ret);
+}
+
// An expression as a statement.
Bstatement*