#include "runtime.h"
#include "backend.h"
#include "statements.h"
+#include "ast-dump.h"
// Class Statement.
return this->do_get_backend(context);
}
+// Dump AST representation for a statement to a dump context.
+
+void
+Statement::dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ this->do_dump_statement(ast_dump_context);
+}
+
// Note that this statement is erroneous. This is called by children
// when they discover an error.
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
};
+// Dump the AST representation for an error statement.
+
+void
+Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "Error statement" << std::endl;
+}
+
// Make an error statement.
Statement*
return true;
}
+// Lower the variable's initialization expression.
+
+Statement*
+Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
+ Block*, Statement_inserter* inserter)
+{
+ this->var_->var_value()->lower_init_expression(gogo, function, inserter);
+ return this;
+}
+
// Convert a variable declaration to the backend representation.
Bstatement*
Expression_list* params = new Expression_list();
params->push_back(Expression::make_type(var->type(), loc));
Expression* call = Expression::make_call(func, params, false, loc);
- context->gogo()->lower_expression(context->function(), &call);
+ context->gogo()->lower_expression(context->function(), NULL, &call);
Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
Bstatement* btemp = temp->get_backend(context);
return context->backend()->statement_list(stats);
}
+// Dump the AST representation for a variable declaration.
+
+void
+Variable_declaration_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+
+ go_assert(var_->is_variable());
+ ast_dump_context->ostream() << "var " << this->var_->name() << " ";
+ Variable* var = this->var_->var_value();
+ if (var->has_type())
+ {
+ ast_dump_context->dump_type(var->type());
+ ast_dump_context->ostream() << " ";
+ }
+ if (var->init() != NULL)
+ {
+ ast_dump_context->ostream() << "= ";
+ ast_dump_context->dump_expression(var->init());
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a variable declaration.
Statement*
if (this->type_ != NULL && this->init_ != NULL)
{
std::string reason;
- if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
+ bool ok;
+ if (this->are_hidden_fields_ok_)
+ ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(),
+ &reason);
+ else
+ ok = Type::are_assignable(this->type_, this->init_->type(), &reason);
+ if (!ok)
{
if (reason.empty())
error_at(this->location(), "incompatible types in assignment");
else
bfunction = tree_to_function(function->func_value()->get_decl());
- Btype* btype = tree_to_type(this->type()->get_tree(context->gogo()));
+ Btype* btype = this->type()->get_backend(context->gogo());
Bexpression* binit;
if (this->init_ == NULL)
{
Expression* init = Expression::make_cast(this->type_, this->init_,
this->location());
- context->gogo()->lower_expression(context->function(), &init);
+ context->gogo()->lower_expression(context->function(), NULL, &init);
binit = tree_to_expr(init->get_tree(context));
}
return this->bvariable_;
}
+// Dump the AST represemtation for a temporary statement
+
+void
+Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_temp_variable_name(this);
+ if (this->type_ != NULL)
+ {
+ ast_dump_context->ostream() << " ";
+ ast_dump_context->dump_type(this->type_);
+ }
+ if (this->init_ != NULL)
+ {
+ ast_dump_context->ostream() << " = ";
+ ast_dump_context->dump_expression(this->init_);
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make and initialize a temporary variable in BLOCK.
Temporary_statement*
Assignment_statement(Expression* lhs, Expression* rhs,
source_location location)
: Statement(STATEMENT_ASSIGNMENT, location),
- lhs_(lhs), rhs_(rhs)
+ lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
{ }
+ // Note that it is OK for this assignment statement to set hidden
+ // fields.
+ void
+ set_hidden_fields_are_ok()
+ { this->are_hidden_fields_ok_ = true; }
+
protected:
int
do_traverse(Traverse* traverse);
Bstatement*
do_get_backend(Translate_context*);
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
// Left hand side--the lvalue.
Expression* lhs_;
// Right hand side--the rvalue.
Expression* rhs_;
+ // True if this statement may set hidden fields in the assignment
+ // statement. This is used for generated method stubs.
+ bool are_hidden_fields_ok_;
};
// Traversal.
Type* lhs_type = this->lhs_->type();
Type* rhs_type = this->rhs_->type();
std::string reason;
- if (!Type::are_assignable(lhs_type, rhs_type, &reason))
+ bool ok;
+ if (this->are_hidden_fields_ok_)
+ ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason);
+ else
+ ok = Type::are_assignable(lhs_type, rhs_type, &reason);
+ if (!ok)
{
if (reason.empty())
error_at(this->location(), "incompatible types in assignment");
this->location());
}
+// Dump the AST representation for an assignment statement.
+
+void
+Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
+ const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->lhs_);
+ ast_dump_context->ostream() << " = " ;
+ ast_dump_context->dump_expression(this->rhs_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make an assignment statement.
Statement*
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
// The operator (OPERATOR_PLUSEQ, etc.).
Statement*
Assignment_operation_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing)
+ Block* enclosing, Statement_inserter*)
{
source_location loc = this->location();
op = OPERATOR_BITCLEAR;
break;
default:
- gcc_unreachable();
+ go_unreachable();
}
Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
}
}
+// Dump the AST representation for an assignment operation statement
+
+void
+Assignment_operation_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->lhs_);
+ ast_dump_context->dump_operator(this->op_);
+ ast_dump_context->dump_expression(this->rhs_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make an assignment operation statement.
Statement*
Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
source_location location)
: Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
- lhs_(lhs), rhs_(rhs)
+ lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
{ }
+ // Note that it is OK for this assignment statement to set hidden
+ // fields.
+ void
+ set_hidden_fields_are_ok()
+ { this->are_hidden_fields_ok_ = true; }
+
protected:
int
do_traverse(Traverse* traverse);
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
// Left hand side--a list of lvalues.
Expression_list* lhs_;
// Right hand side--a list of rvalues.
Expression_list* rhs_;
+ // True if this statement may set hidden fields in the assignment
+ // statement. This is used for generated method stubs.
+ bool are_hidden_fields_ok_;
};
// Traversal.
// up into a set of single assignments.
Statement*
-Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+ Statement_inserter*)
{
source_location loc = this->location();
Block* b = new Block(enclosing, loc);
-
+
// First move out any subexpressions on the left hand side. The
// right hand side will be evaluated in the required order anyhow.
Move_ordered_evals moe(b);
Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
*prhs, loc);
+ if (this->are_hidden_fields_ok_)
+ temp->set_hidden_fields_are_ok();
b->add_statement(temp);
temps.push_back(temp);
Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
Statement* s = Statement::make_assignment(*plhs, ref, loc);
+ if (this->are_hidden_fields_ok_)
+ {
+ Assignment_statement* as = static_cast<Assignment_statement*>(s);
+ as->set_hidden_fields_are_ok();
+ }
b->add_statement(s);
++ptemp;
}
return Statement::make_block_statement(b, loc);
}
+// Dump the AST representation for a tuple assignment statement.
+
+void
+Tuple_assignment_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression_list(this->lhs_);
+ ast_dump_context->ostream() << " = ";
+ ast_dump_context->dump_expression_list(this->rhs_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a tuple assignment statement.
Statement*
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
// Lvalue which receives the value from the map.
Statement*
Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing)
+ Block* enclosing, Statement_inserter*)
{
source_location loc = this->location();
b->add_statement(present_temp);
// present_temp = mapaccess2(MAP, &key_temp, &val_temp)
- Expression* ref = Expression::make_temporary_reference(key_temp, loc);
+ Temporary_reference_expression* ref =
+ Expression::make_temporary_reference(key_temp, loc);
Expression* a1 = Expression::make_unary(OPERATOR_AND, ref, loc);
ref = Expression::make_temporary_reference(val_temp, loc);
Expression* a2 = Expression::make_unary(OPERATOR_AND, ref, loc);
map_index->map(), a1, a2);
ref = Expression::make_temporary_reference(present_temp, loc);
+ ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, call, loc);
b->add_statement(s);
return Statement::make_block_statement(b, loc);
}
+// Dump the AST representation for a tuple map assignment statement.
+
+void
+Tuple_map_assignment_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->val_);
+ ast_dump_context->ostream() << ", ";
+ ast_dump_context->dump_expression(this->present_);
+ ast_dump_context->ostream() << " = ";
+ ast_dump_context->dump_expression(this->map_index_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a map assignment statement which returns a pair of values.
Statement*
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
// A reference to the map index which should be set or deleted.
// Lower a map assignment to a function call.
Statement*
-Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+ Statement_inserter*)
{
source_location loc = this->location();
return Statement::make_block_statement(b, loc);
}
+// Dump the AST representation for a map assignment statement.
+
+void
+Map_assignment_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->map_index_);
+ ast_dump_context->ostream() << " = ";
+ ast_dump_context->dump_expression(this->val_);
+ ast_dump_context->ostream() << ", ";
+ ast_dump_context->dump_expression(this->should_set_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a statement which assigns a pair of entries to a map.
Statement*
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
// Lvalue which receives the value from the channel.
Statement*
Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing)
+ Block* enclosing,
+ Statement_inserter*)
{
source_location loc = this->location();
b->add_statement(closed_temp);
// closed_temp = chanrecv[23](channel, &val_temp)
- Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+ Temporary_reference_expression* ref =
+ Expression::make_temporary_reference(val_temp, loc);
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
Expression* call = Runtime::make_call((this->for_select_
? Runtime::CHANRECV3
: Runtime::CHANRECV2),
loc, 2, this->channel_, p2);
ref = Expression::make_temporary_reference(closed_temp, loc);
+ ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, call, loc);
b->add_statement(s);
return Statement::make_block_statement(b, loc);
}
+// Dump the AST representation for a tuple receive statement.
+
+void
+Tuple_receive_assignment_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->val_);
+ ast_dump_context->ostream() << ", ";
+ ast_dump_context->dump_expression(this->closed_);
+ ast_dump_context->ostream() << " <- ";
+ ast_dump_context->dump_expression(this->channel_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a nonblocking receive statement.
Statement*
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
Call_expression*
Statement*
Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing)
+ Block* enclosing,
+ Statement_inserter*)
{
source_location loc = this->location();
b->add_statement(s);
}
+// Dump the AST representation for a tuple type guard statement.
+
+void
+Tuple_type_guard_assignment_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->val_);
+ ast_dump_context->ostream() << ", ";
+ ast_dump_context->dump_expression(this->ok_);
+ ast_dump_context->ostream() << " = ";
+ ast_dump_context->dump_expression(this->expr_);
+ ast_dump_context->ostream() << " . ";
+ ast_dump_context->dump_type(this->type_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make an assignment from a type guard to a pair of variables.
Statement*
expr_(expr)
{ }
+ Expression*
+ expr()
+ { return this->expr_; }
+
protected:
int
do_traverse(Traverse* traverse)
Bstatement*
do_get_backend(Translate_context* context);
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
Expression* expr_;
};
return context->backend()->expression_statement(tree_to_expr(expr_tree));
}
+// Dump the AST representation for an expression statement
+
+void
+Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
+ const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(expr_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make an expression statement from an Expression.
Statement*
Bstatement*
do_get_backend(Translate_context* context);
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
Block* block_;
};
return context->backend()->block_statement(bblock);
}
+// Dump the AST for a block statement
+
+void
+Block_statement::do_dump_statement(Ast_dump_context*) const
+{
+ // block statement braces are dumped when traversing.
+}
+
// Make a block statement.
Statement*
bool
do_traverse_assignments(Traverse_assignments*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
Statement*
- do_lower(Gogo*, Named_object*, Block*);
+ do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
+
+ void
+ do_dump_statement(Ast_dump_context*) const;
private:
// The l-value to increment or decrement.
// Lower to += or -=.
Statement*
-Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*)
+Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
{
source_location loc = this->location();
return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
}
+// Dump the AST representation for a inc/dec statement.
+
+void
+Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(expr_);
+ ast_dump_context->ostream() << (is_inc_? "++": "--") << std::endl;
+}
+
// Make an increment statement.
Statement*
// Class Thunk_statement. This is the base class for go and defer
// statements.
-const char* const Thunk_statement::thunk_field_fn = "fn";
-
-const char* const Thunk_statement::thunk_field_receiver = "receiver";
-
// Constructor.
Thunk_statement::Thunk_statement(Statement_classification classification,
// If this calls something which is not a simple function, then we
// need a thunk.
Expression* fn = this->call_->call_expression()->fn();
- if (fn->bound_method_expression() != NULL
- || fn->interface_field_reference_expression() != NULL)
+ if (fn->interface_field_reference_expression() != NULL)
return false;
return true;
this->report_error("expected call expression");
return;
}
- Function_type* fntype = ce->get_function_type();
- if (fntype != NULL && fntype->is_method())
- {
- Expression* fn = ce->fn();
- if (fn->bound_method_expression() == NULL
- && fn->interface_field_reference_expression() == NULL)
- this->report_error(_("no object for method call"));
- }
}
// The Traverse class used to find and simplify thunk statements.
this->traverse(&thunk_traverse);
}
+// Return true if the thunk function is a constant, which means that
+// it does not need to be passed to the thunk routine.
+
+bool
+Thunk_statement::is_constant_function() const
+{
+ Call_expression* ce = this->call_->call_expression();
+ Function_type* fntype = ce->get_function_type();
+ if (fntype == NULL)
+ {
+ go_assert(saw_errors());
+ return false;
+ }
+ if (fntype->is_builtin())
+ return true;
+ Expression* fn = ce->fn();
+ if (fn->func_expression() != NULL)
+ return fn->func_expression()->closure() == NULL;
+ if (fn->interface_field_reference_expression() != NULL)
+ return true;
+ return false;
+}
+
// Simplify complex thunk statements into simple ones. A complicated
// thunk statement is one which takes anything other than zero
// parameters or a single pointer parameter. We rewrite it into code
return false;
Expression* fn = ce->fn();
- Bound_method_expression* bound_method = fn->bound_method_expression();
Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression();
- const bool is_method = bound_method != NULL || interface_method != NULL;
source_location location = this->location();
std::string thunk_name = Gogo::thunk_name();
// Build the thunk.
- this->build_thunk(gogo, thunk_name, fntype);
+ this->build_thunk(gogo, thunk_name);
// Generate code to call the thunk.
// argument to the thunk.
Expression_list* vals = new Expression_list();
- if (fntype->is_builtin())
- ;
- else if (!is_method)
+ if (!this->is_constant_function())
vals->push_back(fn);
- else if (interface_method != NULL)
- vals->push_back(interface_method->expr());
- else if (bound_method != NULL)
- {
- vals->push_back(bound_method->method());
- Expression* first_arg = bound_method->first_argument();
-
- // We always pass a pointer when calling a method.
- if (first_arg->type()->points_to() == NULL)
- first_arg = Expression::make_unary(OPERATOR_AND, first_arg, location);
- // If we are calling a method which was inherited from an
- // embedded struct, and the method did not get a stub, then the
- // first type may be wrong.
- Type* fatype = bound_method->first_argument_type();
- if (fatype != NULL)
- {
- if (fatype->points_to() == NULL)
- fatype = Type::make_pointer_type(fatype);
- Type* unsafe = Type::make_pointer_type(Type::make_void_type());
- first_arg = Expression::make_cast(unsafe, first_arg, location);
- first_arg = Expression::make_cast(fatype, first_arg, location);
- }
-
- vals->push_back(first_arg);
- }
- else
- gcc_unreachable();
+ if (interface_method != NULL)
+ vals->push_back(interface_method->expr());
if (ce->args() != NULL)
{
else if (this->classification() == STATEMENT_DEFER)
s = Statement::make_defer_statement(call, location);
else
- gcc_unreachable();
+ go_unreachable();
// The current block should end with the go statement.
go_assert(block->statements()->size() >= 1);
Call_expression* ce = this->call_->call_expression();
Expression* fn = ce->fn();
+ if (!this->is_constant_function())
+ {
+ // The function to call.
+ fields->push_back(Struct_field(Typed_identifier("fn", fntype,
+ location)));
+ }
+
+ // If this thunk statement calls a method on an interface, we pass
+ // the interface object to the thunk.
Interface_field_reference_expression* interface_method =
fn->interface_field_reference_expression();
if (interface_method != NULL)
{
- // If this thunk statement calls a method on an interface, we
- // pass the interface object to the thunk.
- Typed_identifier tid(Thunk_statement::thunk_field_fn,
- interface_method->expr()->type(),
+ Typed_identifier tid("object", interface_method->expr()->type(),
location);
fields->push_back(Struct_field(tid));
}
- else if (!fntype->is_builtin())
- {
- // The function to call.
- Typed_identifier tid(Go_statement::thunk_field_fn, fntype, location);
- fields->push_back(Struct_field(tid));
- }
- else if (ce->is_recover_call())
+
+ // The predeclared recover function has no argument. However, we
+ // add an argument when building recover thunks. Handle that here.
+ if (ce->is_recover_call())
{
- // The predeclared recover function has no argument. However,
- // we add an argument when building recover thunks. Handle that
- // here.
fields->push_back(Struct_field(Typed_identifier("can_recover",
Type::lookup_bool_type(),
location)));
}
- if (fn->bound_method_expression() != NULL)
- {
- go_assert(fntype->is_method());
- Type* rtype = fntype->receiver()->type();
- // We always pass the receiver as a pointer.
- if (rtype->points_to() == NULL)
- rtype = Type::make_pointer_type(rtype);
- Typed_identifier tid(Thunk_statement::thunk_field_receiver, rtype,
- location);
- fields->push_back(Struct_field(tid));
- }
-
const Expression_list* args = ce->args();
if (args != NULL)
{
// artificial, function.
void
-Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
- Function_type* fntype)
+Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
{
source_location location = this->location();
Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
location);
+ gogo->start_block(location);
+
// For a defer statement, start with a call to
// __go_set_defer_retaddr. */
- Label* retaddr_label = NULL;
+ Label* retaddr_label = NULL;
if (may_call_recover)
{
retaddr_label = gogo->add_label_reference("retaddr");
thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
location);
- Bound_method_expression* bound_method = ce->fn()->bound_method_expression();
Interface_field_reference_expression* interface_method =
ce->fn()->interface_field_reference_expression();
Expression* func_to_call;
unsigned int next_index;
- if (!fntype->is_builtin())
- {
- func_to_call = Expression::make_field_reference(thunk_parameter,
- 0, location);
- next_index = 1;
- }
- else
+ if (this->is_constant_function())
{
- go_assert(bound_method == NULL && interface_method == NULL);
func_to_call = ce->fn();
next_index = 0;
}
-
- if (bound_method != NULL)
+ else
{
- Expression* r = Expression::make_field_reference(thunk_parameter, 1,
- location);
- // The main program passes in a function pointer from the
- // interface expression, so here we can make a bound method in
- // all cases.
- func_to_call = Expression::make_bound_method(r, func_to_call,
- location);
- next_index = 2;
+ func_to_call = Expression::make_field_reference(thunk_parameter,
+ 0, location);
+ next_index = 1;
}
- else if (interface_method != NULL)
+
+ if (interface_method != NULL)
{
// The main program passes the interface object.
+ go_assert(next_index == 0);
+ Expression* r = Expression::make_field_reference(thunk_parameter, 0,
+ location);
const std::string& name(interface_method->name());
- func_to_call = Expression::make_interface_field_reference(func_to_call,
- name,
+ func_to_call = Expression::make_interface_field_reference(r, name,
location);
+ next_index = 1;
}
Expression_list* call_params = new Expression_list();
call_params = NULL;
}
- Expression* call = Expression::make_call(func_to_call, call_params, false,
- location);
- // We need to lower in case this is a builtin function.
- call = call->lower(gogo, function, -1);
- Call_expression* call_ce = call->call_expression();
- if (call_ce != NULL && may_call_recover)
- call_ce->set_is_deferred();
+ Call_expression* call = Expression::make_call(func_to_call, call_params,
+ false, location);
- Statement* call_statement = Statement::make_statement(call);
+ // This call expression was already lowered before entering the
+ // thunk statement. Don't try to lower varargs again, as that will
+ // cause confusion for, e.g., method calls which already have a
+ // receiver parameter.
+ call->set_varargs_are_lowered();
- // We already ran the determine_types pass, so we need to run it
- // just for this statement now.
- call_statement->determine_types();
-
- // Sanity check.
- call->check_types(gogo);
-
- if (call_ce != NULL && recover_arg != NULL)
- call_ce->set_recover_arg(recover_arg);
+ Statement* call_statement = Statement::make_statement(call);
gogo->add_statement(call_statement);
gogo->add_statement(Statement::make_return_statement(vals, location));
}
+ Block* b = gogo->finish_block(location);
+
+ gogo->add_block(b, location);
+
+ gogo->lower_block(function, b);
+
+ // We already ran the determine_types pass, so we need to run it
+ // just for the call statement now. The other types are known.
+ call_statement->determine_types();
+
+ if (may_call_recover || recover_arg != NULL)
+ {
+ // Dig up the call expression, which may have been changed
+ // during lowering.
+ go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
+ Expression_statement* es =
+ static_cast<Expression_statement*>(call_statement);
+ Call_expression* ce = es->expr()->call_expression();
+ go_assert(ce != NULL);
+ if (may_call_recover)
+ ce->set_is_deferred();
+ if (recover_arg != NULL)
+ ce->set_recover_arg(recover_arg);
+ }
+
// That is all the thunk has to do.
gogo->finish_function(location);
}
return context->backend()->expression_statement(call_bexpr);
}
+// Dump the AST representation for go statement.
+
+void
+Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "go ";
+ ast_dump_context->dump_expression(this->call());
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a go statement.
Statement*
return context->backend()->expression_statement(call_bexpr);
}
+// Dump the AST representation for defer statement.
+
+void
+Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "defer ";
+ ast_dump_context->dump_expression(this->call());
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a defer statement.
Statement*
// Lower a return statement. If we are returning a function call
// which returns multiple values which match the current function,
-// split up the call's results. If the function has named result
-// variables, and the return statement lists explicit values, then
-// implement it by assigning the values to the result variables and
-// changing the statement to not list any values. This lets
-// panic/recover work correctly.
+// split up the call's results. If the return statement lists
+// explicit values, implement this statement by assigning the values
+// to the result variables and change this statement to a naked
+// return. This lets panic/recover work correctly.
Statement*
-Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing)
+Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
+ Statement_inserter*)
{
if (this->is_lowered_)
return this;
e->determine_type(&type_context);
std::string reason;
- if (Type::are_assignable(rvtype, e->type(), &reason))
+ bool ok;
+ if (this->are_hidden_fields_ok_)
+ ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason);
+ else
+ ok = Type::are_assignable(rvtype, e->type(), &reason);
+ if (ok)
{
Expression* ve = Expression::make_var_reference(rv, e->location());
lhs->push_back(ve);
;
else if (lhs->size() == 1)
{
- b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
- loc));
+ Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
+ loc);
+ if (this->are_hidden_fields_ok_)
+ {
+ Assignment_statement* as = static_cast<Assignment_statement*>(s);
+ as->set_hidden_fields_are_ok();
+ }
+ b->add_statement(s);
delete lhs;
delete rhs;
}
else
- b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
+ {
+ Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
+ if (this->are_hidden_fields_ok_)
+ {
+ Tuple_assignment_statement* tas =
+ static_cast<Tuple_assignment_statement*>(s);
+ tas->set_hidden_fields_are_ok();
+ }
+ b->add_statement(s);
+ }
b->add_statement(this);
retvals, loc);
}
+// Dump the AST representation for a return statement.
+
+void
+Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "return " ;
+ ast_dump_context->dump_expression_list(this->vals_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a return statement.
-Statement*
+Return_statement*
Statement::make_return_statement(Expression_list* vals,
source_location location)
{
do_get_backend(Translate_context* context)
{ return this->label_->get_goto(context, this->location()); }
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
// The label that this branches to.
Unnamed_label* label_;
bool is_break_;
};
+// Dump the AST representation for a break/continue statement
+
+void
+Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
+ if (this->label_ != NULL)
+ {
+ ast_dump_context->ostream() << " ";
+ ast_dump_context->dump_label_name(this->label_);
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a break statement.
Statement*
Bstatement*
do_get_backend(Translate_context*);
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
Label* label_;
};
return context->backend()->goto_statement(blabel, this->location());
}
+// Dump the AST representation for a goto statement.
+
+void
+Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "goto " << this->label_->name() << std::endl;
+}
+
// Make a goto statement.
Statement*
do_get_backend(Translate_context* context)
{ return this->label_->get_goto(context, this->location()); }
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
Unnamed_label* label_;
};
+// Dump the AST representation for an unnamed goto statement
+
+void
+Goto_unnamed_statement::do_dump_statement(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "goto ";
+ ast_dump_context->dump_label_name(this->label_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a goto statement to an unnamed label.
Statement*
return context->backend()->label_definition_statement(blabel);
}
+// Dump the AST for a label definition statement.
+
+void
+Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << this->label_->name() << ":" << std::endl;
+}
+
// Make a label statement.
Statement*
do_get_backend(Translate_context* context)
{ return this->label_->get_definition(context); }
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
// The label.
Unnamed_label* label_;
};
+// Dump the AST representation for an unnamed label definition statement.
+
+void
+Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
+ const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_label_name(this->label_);
+ ast_dump_context->ostream() << ":" << std::endl;
+}
+
// Make an unnamed label statement.
Statement*
Bstatement*
do_get_backend(Translate_context*);
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
Expression* cond_;
Block* then_block_;
else_block, this->location());
}
+// Dump the AST representation for an if statement
+
+void
+If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "if ";
+ ast_dump_context->dump_expression(this->cond_);
+ ast_dump_context->ostream() << std::endl;
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->dump_block(this->then_block_);
+ if (this->else_block_ != NULL)
+ {
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "else" << std::endl;
+ ast_dump_context->dump_block(this->else_block_);
+ }
+ }
+}
+
// Make an if statement.
Statement*
mpz_t ival;
mpz_init(ival);
if (!pe->integer_constant_value(true, ival, &itype))
- gcc_unreachable();
+ go_unreachable();
size_t ret = mpz_get_ui(ival);
mpz_clear(ival);
return ret;
mpz_init(bval);
if (!a->integer_constant_value(true, aval, &atype)
|| !b->integer_constant_value(true, bval, &btype))
- gcc_unreachable();
+ go_unreachable();
bool ret = mpz_cmp(aval, bval) == 0;
mpz_clear(aval);
mpz_clear(bval);
return context->backend()->compound_statement(statements, break_stat);
}
+// Dump the AST representation for a case clause
+
+void
+Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
+ const
+{
+ ast_dump_context->print_indent();
+ if (this->is_default_)
+ {
+ ast_dump_context->ostream() << "default:";
+ }
+ else
+ {
+ ast_dump_context->ostream() << "case ";
+ ast_dump_context->dump_expression_list(this->cases_);
+ ast_dump_context->ostream() << ":" ;
+ }
+ ast_dump_context->dump_block(this->statements_);
+ if (this->is_fallthrough_)
+ {
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << " (fallthrough)" << std::endl;
+ }
+}
+
// Class Case_clauses.
// Traversal.
if (default_case != NULL)
default_case->lower(b, val_temp, default_start_label,
default_finish_label);
-
}
// Determine types.
}
}
+// Dump the AST representation for case clauses (from a switch statement)
+
+void
+Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
+{
+ for (Clauses::const_iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ p->dump_clause(ast_dump_context);
+}
+
// A constant switch statement. A Switch_statement is lowered to this
// when all the cases are constants.
Bstatement*
do_get_backend(Translate_context*);
+ void
+ do_dump_statement(Ast_dump_context*) const;
+
private:
// The value to switch on.
Expression* val_;
return context->backend()->compound_statement(switch_statement, ldef);
}
+// Dump the AST representation for a constant switch statement.
+
+void
+Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
+ const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "switch ";
+ ast_dump_context->dump_expression(this->val_);
+
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->ostream() << " {" << std::endl;
+ this->clauses_->dump_clauses(ast_dump_context);
+ ast_dump_context->ostream() << "}";
+ }
+
+ ast_dump_context->ostream() << std::endl;
+}
+
// Class Switch_statement.
// Traversal.
// of if statements.
Statement*
-Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+ Statement_inserter*)
{
source_location loc = this->location();
return this->break_label_;
}
+// Dump the AST representation for a switch statement.
+
+void
+Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "switch ";
+ if (this->val_ != NULL)
+ {
+ ast_dump_context->dump_expression(this->val_);
+ }
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->ostream() << " {" << std::endl;
+ this->clauses_->dump_clauses(ast_dump_context);
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "}";
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a switch statement.
Switch_statement*
}
}
+// Dump the AST representation for a type case clause
+
+void
+Type_case_clauses::Type_case_clause::dump_clause(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ if (this->is_default_)
+ {
+ ast_dump_context->ostream() << "default:";
+ }
+ else
+ {
+ ast_dump_context->ostream() << "case ";
+ ast_dump_context->dump_type(this->type_);
+ ast_dump_context->ostream() << ":" ;
+ }
+ ast_dump_context->dump_block(this->statements_);
+ if (this->is_fallthrough_)
+ {
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << " (fallthrough)" << std::endl;
+ }
+}
+
// Class Type_case_clauses.
// Traversal.
default_case->lower(b, descriptor_temp, break_label, NULL);
}
+// Dump the AST representation for case clauses (from a switch statement)
+
+void
+Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
+{
+ for (Type_clauses::const_iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ p->dump_clause(ast_dump_context);
+}
+
// Class Type_switch_statement.
// Traversal.
// equality testing.
Statement*
-Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+ Statement_inserter*)
{
const source_location loc = this->location();
? Runtime::EFACETYPE
: Runtime::IFACETYPE),
loc, 1, ref);
- Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
- loc);
+ Temporary_reference_expression* lhs =
+ Expression::make_temporary_reference(descriptor_temp, loc);
+ lhs->set_is_lvalue();
Statement* s = Statement::make_assignment(lhs, call, loc);
b->add_statement(s);
}
return this->break_label_;
}
+// Dump the AST representation for a type switch statement
+
+void
+Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
+ const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "switch " << this->var_->name() << " = ";
+ ast_dump_context->dump_expression(this->expr_);
+ ast_dump_context->ostream() << " .(type)";
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->ostream() << " {" << std::endl;
+ this->clauses_->dump_clauses(ast_dump_context);
+ ast_dump_context->ostream() << "}";
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a type switch statement.
Type_switch_statement*
call = Runtime::make_call(code, loc, 3, this->channel_, val,
Expression::make_boolean(this->for_select_, loc));
- context->gogo()->lower_expression(context->function(), &call);
+ context->gogo()->lower_expression(context->function(), NULL, &call);
Bexpression* bcall = tree_to_expr(call->get_tree(context));
Bstatement* s = context->backend()->expression_statement(bcall);
return context->backend()->compound_statement(btemp, s);
}
+// Dump the AST representation for a send statement
+
+void
+Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->dump_expression(this->channel_);
+ ast_dump_context->ostream() << " <- ";
+ ast_dump_context->dump_expression(this->val_);
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a send statement.
Send_statement*
return context->backend()->block_statement(bblock);
}
+// Dump the AST representation for a select case clause
+
+void
+Select_clauses::Select_clause::dump_clause(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ if (this->is_default_)
+ {
+ ast_dump_context->ostream() << "default:";
+ }
+ else
+ {
+ ast_dump_context->ostream() << "case " ;
+ if (this->is_send_)
+ {
+ ast_dump_context->dump_expression(this->channel_);
+ ast_dump_context->ostream() << " <- " ;
+ ast_dump_context->dump_expression(this->val_);
+ }
+ else
+ {
+ if (this->val_ != NULL)
+ ast_dump_context->dump_expression(this->val_);
+ if (this->closed_ != NULL)
+ {
+ // FIXME: can val_ == NULL and closed_ ! = NULL?
+ ast_dump_context->ostream() << " , " ;
+ ast_dump_context->dump_expression(this->closed_);
+ }
+ if (this->closedvar_ != NULL ||
+ this->var_ != NULL)
+ ast_dump_context->ostream() << " := " ;
+
+ ast_dump_context->ostream() << " <- " ;
+ ast_dump_context->dump_expression(this->channel_);
+ }
+ ast_dump_context->ostream() << ":" ;
+ }
+ ast_dump_context->dump_block(this->statements_);
+}
+
// Class Select_clauses.
// Traversal.
Expression* nil2 = nil1->copy();
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
zero, default_arg, nil1, nil2);
- context->gogo()->lower_expression(context->function(), &call);
+ context->gogo()->lower_expression(context->function(), NULL, &call);
Bexpression* bcall = tree_to_expr(call->get_tree(context));
s = context->backend()->expression_statement(bcall);
}
Expression* chans = Expression::make_composite_literal(chan_array_type, 0,
false, chan_init,
location);
- context->gogo()->lower_expression(context->function(), &chans);
+ context->gogo()->lower_expression(context->function(), NULL, &chans);
Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type,
chans,
location);
0, false,
is_send_init,
location);
- context->gogo()->lower_expression(context->function(), &is_sends);
+ context->gogo()->lower_expression(context->function(), NULL, &is_sends);
Temporary_statement* is_send_temp =
Statement::make_temporary(is_send_array_type, is_sends, location);
statements.push_back(is_send_temp->get_backend(context));
Expression* call = Runtime::make_call(Runtime::SELECT, location, 4,
ecount->copy(), default_arg,
chan_arg, is_send_arg);
- context->gogo()->lower_expression(context->function(), &call);
+ context->gogo()->lower_expression(context->function(), NULL, &call);
Bexpression* bcall = tree_to_expr(call->get_tree(context));
std::vector<std::vector<Bexpression*> > cases;
? clause->location()
: clause->statements()->end_location());
Bstatement* g = bottom_label->get_goto(context, gloc);
-
+
if (s == NULL)
(*clauses)[index] = g;
else
(*clauses)[index] = context->backend()->compound_statement(s, g);
}
+// Dump the AST representation for select clauses.
+
+void
+Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
+{
+ for (Clauses::const_iterator p = this->clauses_.begin();
+ p != this->clauses_.end();
+ ++p)
+ p->dump_clause(ast_dump_context);
+}
+
// Class Select_statement.
// Return the break label for this switch statement, creating it if
Statement*
Select_statement::do_lower(Gogo* gogo, Named_object* function,
- Block* enclosing)
+ Block* enclosing, Statement_inserter*)
{
if (this->is_lowered_)
return this;
this->location());
}
+// Dump the AST representation for a select statement.
+
+void
+Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "select";
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->ostream() << " {" << std::endl;
+ this->clauses_->dump_clauses(ast_dump_context);
+ ast_dump_context->ostream() << "}";
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a select statement.
Select_statement*
// complex statements make it easier to handle garbage collection.
Statement*
-For_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
+For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+ Statement_inserter*)
{
Statement* s;
source_location loc = this->location();
this->continue_label_ = continue_label;
}
+// Dump the AST representation for a for statement.
+
+void
+For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+ if (this->init_ != NULL && ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->print_indent();
+ ast_dump_context->indent();
+ ast_dump_context->ostream() << "// INIT " << std::endl;
+ ast_dump_context->dump_block(this->init_);
+ ast_dump_context->unindent();
+ }
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "for ";
+ if (this->cond_ != NULL)
+ ast_dump_context->dump_expression(this->cond_);
+
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->ostream() << " {" << std::endl;
+ ast_dump_context->dump_block(this->statements_);
+ if (this->init_ != NULL)
+ {
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "// POST " << std::endl;
+ ast_dump_context->dump_block(this->post_);
+ }
+ ast_dump_context->unindent();
+
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "}";
+ }
+
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a for statement.
For_statement*
// statements.
Statement*
-For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing)
+For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
+ Statement_inserter*)
{
Type* range_type = this->range_->type();
if (range_type->points_to() != NULL
else
{
this->report_error(_("range clause must have "
- "array, slice, setring, map, or channel type"));
+ "array, slice, string, map, or channel type"));
return Statement::make_error_statement(this->location());
}
{
range_temp = Statement::make_temporary(NULL, this->range_, loc);
temp_block->add_statement(range_temp);
+ this->range_ = NULL;
}
Temporary_statement* index_temp = Statement::make_temporary(index_type,
index_temp, value_temp, &init, &cond, &iter_init,
&post);
else
- gcc_unreachable();
+ go_unreachable();
if (iter_init != NULL)
body->add_statement(Statement::make_block_statement(iter_init, loc));
Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
mpz_clear(zval);
- ref = Expression::make_temporary_reference(index_temp, loc);
- Statement* s = Statement::make_assignment(ref, zexpr, loc);
+ Temporary_reference_expression* tref =
+ Expression::make_temporary_reference(index_temp, loc);
+ tref->set_is_lvalue();
+ Statement* s = Statement::make_assignment(tref, zexpr, loc);
init->add_statement(s);
*pinit = init;
Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
Expression* index = Expression::make_index(ref, ref2, NULL, loc);
- ref = Expression::make_temporary_reference(value_temp, loc);
- s = Statement::make_assignment(ref, index, loc);
+ tref = Expression::make_temporary_reference(value_temp, loc);
+ tref->set_is_lvalue();
+ s = Statement::make_assignment(tref, index, loc);
iter_init->add_statement(s);
}
// index_temp++
Block* post = new Block(enclosing, loc);
- ref = Expression::make_temporary_reference(index_temp, loc);
- s = Statement::make_inc_statement(ref);
+ tref = Expression::make_temporary_reference(index_temp, loc);
+ tref->set_is_lvalue();
+ s = Statement::make_inc_statement(tref);
post->add_statement(s);
*ppost = post;
}
mpz_init_set_ui(zval, 0UL);
Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
- Expression* ref = Expression::make_temporary_reference(index_temp, loc);
+ Temporary_reference_expression* ref =
+ Expression::make_temporary_reference(index_temp, loc);
+ ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, zexpr, loc);
init->add_statement(s);
if (value_temp == NULL)
{
ref = Expression::make_temporary_reference(next_index_temp, loc);
+ ref->set_is_lvalue();
s = Statement::make_assignment(ref, call, loc);
}
else
{
Expression_list* lhs = new Expression_list();
- lhs->push_back(Expression::make_temporary_reference(next_index_temp,
- loc));
- lhs->push_back(Expression::make_temporary_reference(value_temp, loc));
+
+ ref = Expression::make_temporary_reference(next_index_temp, loc);
+ ref->set_is_lvalue();
+ lhs->push_back(ref);
+
+ ref = Expression::make_temporary_reference(value_temp, loc);
+ ref->set_is_lvalue();
+ lhs->push_back(ref);
Expression_list* rhs = new Expression_list();
rhs->push_back(Expression::make_call_result(call, 0));
Block* post = new Block(enclosing, loc);
- Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
+ Temporary_reference_expression* lhs =
+ Expression::make_temporary_reference(index_temp, loc);
+ lhs->set_is_lvalue();
Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
s = Statement::make_assignment(lhs, rhs, loc);
iter_init->add_statement(ok_temp);
Expression* cref = this->make_range_ref(range_object, range_temp, loc);
- Expression* iref = Expression::make_temporary_reference(index_temp, loc);
- Expression* oref = Expression::make_temporary_reference(ok_temp, loc);
+ Temporary_reference_expression* iref =
+ Expression::make_temporary_reference(index_temp, loc);
+ iref->set_is_lvalue();
+ Temporary_reference_expression* oref =
+ Expression::make_temporary_reference(ok_temp, loc);
+ oref->set_is_lvalue();
Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
false, loc);
iter_init->add_statement(s);
return this->continue_label_;
}
+// Dump the AST representation for a for range statement.
+
+void
+For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
+{
+
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "for ";
+ ast_dump_context->dump_expression(this->index_var_);
+ if (this->value_var_ != NULL)
+ {
+ ast_dump_context->ostream() << ", ";
+ ast_dump_context->dump_expression(this->value_var_);
+ }
+
+ ast_dump_context->ostream() << " = range ";
+ ast_dump_context->dump_expression(this->range_);
+ if (ast_dump_context->dump_subblocks())
+ {
+ ast_dump_context->ostream() << " {" << std::endl;
+
+ ast_dump_context->indent();
+
+ ast_dump_context->dump_block(this->statements_);
+
+ ast_dump_context->unindent();
+ ast_dump_context->print_indent();
+ ast_dump_context->ostream() << "}";
+ }
+ ast_dump_context->ostream() << std::endl;
+}
+
// Make a for statement with a range clause.
For_range_statement*