compiler: Use backend interface for interface info and field expressions.
* go-gcc.cc (Gcc_backend::compound_expression): New function. (Gcc_backend::conditional_expression): New function. From-SVN: r206615
This commit is contained in:
parent
3f3bd8aa27
commit
eb6eb86237
|
@ -1,3 +1,8 @@
|
|||
2014-01-14 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc (Gcc_backend::compound_expression): New function.
|
||||
(Gcc_backend::conditional_expression): New function.
|
||||
|
||||
2014-01-02 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
Update copyright years
|
||||
|
|
|
@ -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(Bexpression* bstruct, size_t index,
|
|||
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*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -6473,11 +6473,11 @@ Expression::make_binary(Operator op, Expression* left, Expression* right,
|
|||
|
||||
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_context* context, Type* result_type,
|
|||
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_context* context, Type* result_type,
|
|||
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_context* context, Type* result_type,
|
|||
{
|
||||
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() const
|
|||
// 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_context* context)
|
|||
}
|
||||
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(Expression* expr, unsigned int field_index,
|
|||
|
||||
// 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);
|
||||
Expression* ref = this->expr_;
|
||||
Location loc = this->location();
|
||||
if (ref->type()->points_to() != NULL)
|
||||
ref = Expression::make_unary(OPERATOR_MULT, ref, loc);
|
||||
|
||||
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)));
|
||||
|
||||
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_lower(Gogo*, Named_object*,
|
|||
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_get_tree(Translate_context* context)
|
|||
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* slice, Slice_info slice_info,
|
|||
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 Expression
|
|||
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_expression : public Expression
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue