From 9403944776d0a804dbb1253430633d04aef74c51 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 4 Apr 2011 23:19:09 +0000 Subject: Use backend interface for return statements. * go-gcc.cc: #include "tree-iterator.h", "gimple.h", and "gogo.h". (class Bfunction): Define. (Gcc_backend::assignment_statement): Rename from assignment. Check for errors. (Gcc_backend::return_statement): New function. (tree_to_function): New function. * Make-lang.in (go/go-gcc.o): Depend on tree-iterator.h, $(GIMPLE_H), and $(GO_GOGO_H). From-SVN: r171959 --- gcc/go/ChangeLog | 11 ++ gcc/go/Make-lang.in | 3 +- gcc/go/go-gcc.cc | 96 +++++++++++++- gcc/go/gofrontend/backend.h | 13 +- gcc/go/gofrontend/expressions.cc | 3 +- gcc/go/gofrontend/gogo-tree.cc | 27 +--- gcc/go/gofrontend/gogo.cc | 59 +++++---- gcc/go/gofrontend/gogo.h | 27 +++- gcc/go/gofrontend/parse.cc | 5 +- gcc/go/gofrontend/statements.cc | 274 ++++++++++----------------------------- gcc/go/gofrontend/statements.h | 20 +-- gcc/go/gofrontend/types.cc | 5 +- 12 files changed, 254 insertions(+), 289 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 5d50db2..b8a11f6 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,14 @@ +2011-04-04 Ian Lance Taylor + + * go-gcc.cc: #include "tree-iterator.h", "gimple.h", and "gogo.h". + (class Bfunction): Define. + (Gcc_backend::assignment_statement): Rename from assignment. + Check for errors. + (Gcc_backend::return_statement): New function. + (tree_to_function): New function. + * Make-lang.in (go/go-gcc.o): Depend on tree-iterator.h, + $(GIMPLE_H), and $(GO_GOGO_H). + 2011-04-03 Ian Lance Taylor * go-gcc.cc: New file. diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index 07c884d..67900d7 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -236,7 +236,8 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \ GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend -go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) go/gofrontend/backend.h +go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \ + $(GIMPLE_H) $(GO_GOGO_H) go/gofrontend/backend.h $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION) go/%.o: go/gofrontend/%.cc diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index ca2d63b..2785bf2 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -30,11 +30,14 @@ extern "C" #endif #include "tree.h" +#include "tree-iterator.h" +#include "gimple.h" #ifndef ENABLE_BUILD_WITH_CXX } #endif +#include "gogo.h" #include "backend.h" // A class wrapping a tree. @@ -79,6 +82,14 @@ class Bstatement : public Gcc_tree { } }; +class Bfunction : public Gcc_tree +{ + public: + Bfunction(tree t) + : Gcc_tree(t) + { } +}; + // This file implements the interface between the Go frontend proper // and the gcc IR. This implements specific instantiations of // abstract classes defined by the Go frontend proper. The Go @@ -149,8 +160,12 @@ class Gcc_backend : public Backend // Create an assignment statement. Bstatement* - assignment(Bexpression* lhs, Bexpression* rhs, - source_location location); + assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location); + + // Create a return statement. + Bstatement* + return_statement(Bfunction*, const std::vector&, + source_location); private: // Make a Bstatement from a tree. @@ -162,13 +177,76 @@ class Gcc_backend : public Backend // Assignment. Bstatement* -Gcc_backend::assignment(Bexpression* lhs, Bexpression* rhs, - source_location location) +Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs, + source_location location) { + tree lhs_tree = lhs->get_tree(); + tree rhs_tree = rhs->get_tree(); + if (lhs_tree == error_mark_node || rhs_tree == error_mark_node) + return this->make_statement(error_mark_node); return this->make_statement(fold_build2_loc(location, MODIFY_EXPR, void_type_node, - lhs->get_tree(), - rhs->get_tree())); + lhs_tree, rhs_tree)); +} + +// Return. + +Bstatement* +Gcc_backend::return_statement(Bfunction* bfunction, + const std::vector& vals, + source_location location) +{ + tree fntree = bfunction->get_tree(); + if (fntree == error_mark_node) + return this->make_statement(error_mark_node); + tree result = DECL_RESULT(fntree); + if (result == error_mark_node) + return this->make_statement(error_mark_node); + tree ret; + if (vals.empty()) + ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, NULL_TREE); + else if (vals.size() == 1) + { + tree val = vals.front()->get_tree(); + if (val == error_mark_node) + return this->make_statement(error_mark_node); + tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, + result, vals.front()->get_tree()); + ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, set); + } + else + { + // To return multiple values, copy the values into a temporary + // variable of the right structure type, and then assign the + // temporary variable to the DECL_RESULT in the return + // statement. + tree stmt_list = NULL_TREE; + tree rettype = TREE_TYPE(result); + tree rettmp = create_tmp_var(rettype, "RESULT"); + tree field = TYPE_FIELDS(rettype); + for (std::vector::const_iterator p = vals.begin(); + p != vals.end(); + p++, field = DECL_CHAIN(field)) + { + gcc_assert(field != NULL_TREE); + tree ref = fold_build3_loc(location, COMPONENT_REF, TREE_TYPE(field), + rettmp, field, NULL_TREE); + tree val = (*p)->get_tree(); + if (val == error_mark_node) + return this->make_statement(error_mark_node); + tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, + ref, (*p)->get_tree()); + append_to_statement_list(set, &stmt_list); + } + gcc_assert(field == NULL_TREE); + tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, + result, rettmp); + tree ret_expr = fold_build1_loc(location, RETURN_EXPR, void_type_node, + set); + append_to_statement_list(ret_expr, &stmt_list); + ret = stmt_list; + } + return this->make_statement(ret); } // The single backend. @@ -192,6 +270,12 @@ tree_to_expr(tree t) return new Bexpression(t); } +Bfunction* +tree_to_function(tree t) +{ + return new Bfunction(t); +} + tree statement_to_tree(Bstatement* bs) { diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index babef83..959fc78 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -24,6 +24,9 @@ class Bexpression; // The backend representation of a statement. class Bstatement; +// The backend representation of a function definition. +class Bfunction; + // A list of backend types. typedef std::vector Btypes; @@ -103,7 +106,14 @@ class Backend // Create an assignment statement. virtual Bstatement* - assignment(Bexpression* lhs, Bexpression* rhs, source_location location) = 0; + assignment_statement(Bexpression* lhs, Bexpression* rhs, + source_location) = 0; + + // Create a return statement, passing the representation of the + // function and the list of values to return. + virtual Bstatement* + return_statement(Bfunction*, const std::vector&, + source_location) = 0; }; // The backend interface has to define this function. @@ -114,6 +124,7 @@ extern Backend* go_get_backend(); // interface. extern Bexpression* tree_to_expr(tree); +extern Bfunction* tree_to_function(tree); extern tree statement_to_tree(Bstatement*); #endif // !defined(GO_BACKEND_H) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index e295c7d..a0cfcfcd 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -10415,8 +10415,7 @@ Selector_expression::lower_method_expression(Gogo* gogo) for (size_t i = 0; i < count; ++i) retvals->push_back(Expression::make_call_result(call, i)); } - s = Statement::make_return_statement(no->func_value()->type()->results(), - retvals, location); + s = Statement::make_return_statement(retvals, location); } gogo->add_statement(s); diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 2f52aa20..bd5945b 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -1761,27 +1761,16 @@ Function::return_value(Gogo* gogo, Named_object* named_function, if (results == NULL || results->empty()) return NULL_TREE; - // In the case of an exception handler created for functions with - // defer statements, the result variables may be unnamed. - bool is_named = !results->front().name().empty(); - if (is_named) + gcc_assert(this->results_ != NULL); + if (this->results_->size() != results->size()) { - gcc_assert(this->named_results_ != NULL); - if (this->named_results_->size() != results->size()) - { - gcc_assert(saw_errors()); - return error_mark_node; - } + gcc_assert(saw_errors()); + return error_mark_node; } tree retval; if (results->size() == 1) - { - if (is_named) - return this->named_results_->front()->get_tree(gogo, named_function); - else - return results->front().type()->get_init_tree(gogo, false); - } + return this->results_->front()->get_tree(gogo, named_function); else { tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_)); @@ -1794,11 +1783,7 @@ Function::return_value(Gogo* gogo, Named_object* named_function, { gcc_assert(field != NULL); tree val; - if (is_named) - val = (*this->named_results_)[index]->get_tree(gogo, - named_function); - else - val = pr->type()->get_init_tree(gogo, false); + val = (*this->results_)[index]->get_tree(gogo, named_function); tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, build3(COMPONENT_REF, TREE_TYPE(field), retval, field, NULL_TREE), diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 6450141..5b3ac8c 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -642,7 +642,7 @@ Gogo::start_function(const std::string& name, Function_type* type, } } - function->create_named_result_variables(this); + function->create_result_variables(this); const std::string* pname; std::string nested_name; @@ -2195,8 +2195,7 @@ Build_recover_thunks::function(Named_object* orig_no) for (size_t i = 0; i < rc; ++i) vals->push_back(Expression::make_call_result(call, i)); } - s = Statement::make_return_statement(new_func->type()->results(), - vals, location); + s = Statement::make_return_statement(vals, location); } s->determine_types(); gogo->add_statement(s); @@ -2252,8 +2251,8 @@ Build_recover_thunks::function(Named_object* orig_no) new_func->traverse(&convert_recover); // Update the function pointers in any named results. - new_func->update_named_result_variables(); - orig_func->update_named_result_variables(); + new_func->update_result_variables(); + orig_func->update_result_variables(); return TRAVERSE_CONTINUE; } @@ -2619,26 +2618,27 @@ Gogo::convert_named_types_in_bindings(Bindings* bindings) Function::Function(Function_type* type, Function* enclosing, Block* block, source_location location) - : type_(type), enclosing_(enclosing), named_results_(NULL), + : type_(type), enclosing_(enclosing), results_(NULL), closure_var_(NULL), block_(block), location_(location), fndecl_(NULL), - defer_stack_(NULL), calls_recover_(false), is_recover_thunk_(false), - has_recover_thunk_(false) + defer_stack_(NULL), results_are_named_(false), calls_recover_(false), + is_recover_thunk_(false), has_recover_thunk_(false) { } // Create the named result variables. void -Function::create_named_result_variables(Gogo* gogo) +Function::create_result_variables(Gogo* gogo) { const Typed_identifier_list* results = this->type_->results(); - if (results == NULL - || results->empty() - || results->front().name().empty()) + if (results == NULL || results->empty()) return; - this->named_results_ = new Named_results(); - this->named_results_->reserve(results->size()); + if (!results->front().name().empty()) + this->results_are_named_ = true; + + this->results_ = new Results(); + this->results_->reserve(results->size()); Block* block = this->block_; int index = 0; @@ -2647,18 +2647,29 @@ Function::create_named_result_variables(Gogo* gogo) ++p, ++index) { std::string name = p->name(); - if (Gogo::is_sink_name(name)) + if (name.empty() || Gogo::is_sink_name(name)) { - static int unnamed_result_counter; + static int result_counter; char buf[100]; - snprintf(buf, sizeof buf, "_$%d", unnamed_result_counter); - ++unnamed_result_counter; + snprintf(buf, sizeof buf, "$ret%d", result_counter); + ++result_counter; name = gogo->pack_hidden_name(buf, false); } Result_variable* result = new Result_variable(p->type(), this, index); Named_object* no = block->bindings()->add_result_variable(name, result); if (no->is_result_variable()) - this->named_results_->push_back(no); + this->results_->push_back(no); + else + { + static int dummy_result_count; + char buf[100]; + snprintf(buf, sizeof buf, "$dret%d", dummy_result_count); + ++dummy_result_count; + name = gogo->pack_hidden_name(buf, false); + no = block->bindings()->add_result_variable(name, result); + gcc_assert(no->is_result_variable()); + this->results_->push_back(no); + } } } @@ -2666,13 +2677,13 @@ Function::create_named_result_variables(Gogo* gogo) // calls recover. void -Function::update_named_result_variables() +Function::update_result_variables() { - if (this->named_results_ == NULL) + if (this->results_ == NULL) return; - for (Named_results::iterator p = this->named_results_->begin(); - p != this->named_results_->end(); + for (Results::iterator p = this->results_->begin(); + p != this->results_->end(); ++p) (*p)->result_var_value()->set_function(this); } @@ -2819,7 +2830,7 @@ void Function::swap_for_recover(Function *x) { gcc_assert(this->enclosing_ == x->enclosing_); - std::swap(this->named_results_, x->named_results_); + std::swap(this->results_, x->results_); std::swap(this->closure_var_, x->closure_var_); std::swap(this->block_, x->block_); gcc_assert(this->location_ == x->location_); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index b6b1f4d..87e2da6 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -822,14 +822,27 @@ class Function this->enclosing_ = enclosing; } - // Create the named result variables in the outer block. + // The result variables. + typedef std::vector Results; + + // Create the result variables in the outer block. void - create_named_result_variables(Gogo*); + create_result_variables(Gogo*); // Update the named result variables when cloning a function which // calls recover. void - update_named_result_variables(); + update_result_variables(); + + // Return the result variables. + Results* + result_variables() + { return this->results_; } + + // Whether the result variables have names. + bool + results_are_named() const + { return this->results_are_named_; } // Add a new field to the closure variable. void @@ -992,8 +1005,6 @@ class Function void build_defer_wrapper(Gogo*, Named_object*, tree*, tree*); - typedef std::vector Named_results; - typedef std::vector > Closure_fields; @@ -1002,8 +1013,8 @@ class Function // The enclosing function. This is NULL when there isn't one, which // is the normal case. Function* enclosing_; - // The named result variables, if any. - Named_results* named_results_; + // The result variables, if any. + Results* results_; // If there is a closure, this is the list of variables which appear // in the closure. This is created by the parser, and then resolved // to a real type when we lower parse trees. @@ -1022,6 +1033,8 @@ class Function // A variable holding the defer stack variable. This is NULL unless // we actually need a defer stack. tree defer_stack_; + // True if the result variables are named. + bool results_are_named_; // True if this function calls the predeclared recover function. bool calls_recover_; // True if this a thunk built for a function which calls recover. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 970dc15..e5ea636 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -3732,10 +3732,7 @@ Parse::return_stat() Expression_list* vals = NULL; if (this->expression_may_start_here()) vals = this->expression_list(NULL, false); - const Function* function = this->gogo_->current_function()->func_value(); - const Typed_identifier_list* results = function->type()->results(); - this->gogo_->add_statement(Statement::make_return_statement(results, vals, - location)); + this->gogo_->add_statement(Statement::make_return_statement(vals, location)); } // IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" Statement ] . diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index b1e7613..3783fb8 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -561,9 +561,10 @@ Assignment_statement::do_get_tree(Translate_context* context) if (rhs_tree == error_mark_node) return error_mark_node; - Bstatement* ret = context->backend()->assignment(tree_to_expr(lhs_tree), - tree_to_expr(rhs_tree), - this->location()); + Bstatement* ret; + ret = context->backend()->assignment_statement(tree_to_expr(lhs_tree), + tree_to_expr(rhs_tree), + this->location()); return statement_to_tree(ret); } @@ -2289,10 +2290,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_boolean(false, location)); - const Typed_identifier_list* results = - function->func_value()->type()->results(); - gogo->add_statement(Statement::make_return_statement(results, vals, - location)); + gogo->add_statement(Statement::make_return_statement(vals, location)); } // That is all the thunk has to do. @@ -2442,69 +2440,76 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign) // panic/recover work correctly. Statement* -Return_statement::do_lower(Gogo*, Named_object*, Block* enclosing) +Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing) { - if (this->vals_ == NULL) + if (this->is_lowered_) return this; - const Typed_identifier_list* results = this->results_; - if (results == NULL || results->empty()) - return this; + Expression_list* vals = this->vals_; + this->vals_ = NULL; + this->is_lowered_ = true; + + source_location loc = this->location(); + + size_t vals_count = vals == NULL ? 0 : vals->size(); + Function::Results* results = function->func_value()->result_variables(); + size_t results_count = results == NULL ? 0 : results->size(); + + if (vals_count == 0) + { + if (results_count > 0 && !function->func_value()->results_are_named()) + { + this->report_error(_("not enough arguments to return")); + return this; + } + return this; + } + + if (results_count == 0) + { + this->report_error(_("return with value in function " + "with no return type")); + return this; + } // If the current function has multiple return values, and we are // returning a single call expression, split up the call expression. - size_t results_count = results->size(); if (results_count > 1 - && this->vals_->size() == 1 - && this->vals_->front()->call_expression() != NULL) + && vals->size() == 1 + && vals->front()->call_expression() != NULL) { - Call_expression* call = this->vals_->front()->call_expression(); - size_t count = results->size(); - Expression_list* vals = new Expression_list; - for (size_t i = 0; i < count; ++i) + Call_expression* call = vals->front()->call_expression(); + delete vals; + vals = new Expression_list; + for (size_t i = 0; i < results_count; ++i) vals->push_back(Expression::make_call_result(call, i)); - delete this->vals_; - this->vals_ = vals; + vals_count = results_count; } - if (results->front().name().empty()) - return this; - - if (results_count != this->vals_->size()) + if (vals_count < results_count) { - // Presumably an error which will be reported in check_types. + this->report_error(_("not enough arguments to return")); return this; } - // Assign to named return values and then return them. - - source_location loc = this->location(); - const Block* top = enclosing; - while (top->enclosing() != NULL) - top = top->enclosing(); + if (vals_count > results_count) + { + this->report_error(_("too many values in return statement")); + return this; + } - const Bindings *bindings = top->bindings(); Block* b = new Block(enclosing, loc); Expression_list* lhs = new Expression_list(); Expression_list* rhs = new Expression_list(); - Expression_list::const_iterator pe = this->vals_->begin(); + Expression_list::const_iterator pe = vals->begin(); int i = 1; - for (Typed_identifier_list::const_iterator pr = results->begin(); + for (Function::Results::const_iterator pr = results->begin(); pr != results->end(); ++pr, ++pe, ++i) { - Named_object* rv = bindings->lookup_local(pr->name()); - if (rv == NULL || !rv->is_result_variable()) - { - // Presumably an error. - delete b; - delete lhs; - delete rhs; - return this; - } - + Named_object* rv = *pr; Expression* e = *pe; // Check types now so that we give a good error message. The @@ -2546,187 +2551,48 @@ Return_statement::do_lower(Gogo*, Named_object*, Block* enclosing) else b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc)); - b->add_statement(Statement::make_return_statement(this->results_, NULL, - loc)); - - return Statement::make_block_statement(b, loc); -} - -// Determine types. - -void -Return_statement::do_determine_types() -{ - if (this->vals_ == NULL) - return; - const Typed_identifier_list* results = this->results_; - - Typed_identifier_list::const_iterator pt; - if (results != NULL) - pt = results->begin(); - for (Expression_list::iterator pe = this->vals_->begin(); - pe != this->vals_->end(); - ++pe) - { - if (results == NULL || pt == results->end()) - (*pe)->determine_type_no_context(); - else - { - Type_context context(pt->type(), false); - (*pe)->determine_type(&context); - ++pt; - } - } -} - -// Check types. + b->add_statement(this); -void -Return_statement::do_check_types(Gogo*) -{ - const Typed_identifier_list* results = this->results_; - if (this->vals_ == NULL) - { - if (results != NULL - && !results->empty() - && results->front().name().empty()) - { - // The result parameters are not named, which means that we - // need to supply values for them. - this->report_error(_("not enough arguments to return")); - } - return; - } + delete vals; - if (results == NULL) - { - this->report_error(_("return with value in function " - "with no return type")); - return; - } - - int i = 1; - Typed_identifier_list::const_iterator pt = results->begin(); - for (Expression_list::const_iterator pe = this->vals_->begin(); - pe != this->vals_->end(); - ++pe, ++pt, ++i) - { - if (pt == results->end()) - { - this->report_error(_("too many values in return statement")); - return; - } - std::string reason; - if (!Type::are_assignable(pt->type(), (*pe)->type(), &reason)) - { - if (reason.empty()) - error_at(this->location(), - "incompatible type for return value %d", - i); - else - error_at(this->location(), - "incompatible type for return value %d (%s)", - i, reason.c_str()); - this->set_is_error(); - } - else if (pt->type()->is_error() || (*pe)->type()->is_error()) - this->set_is_error(); - } - - if (pt != results->end()) - this->report_error(_("not enough arguments to return")); + return Statement::make_block_statement(b, loc); } -// Build a RETURN_EXPR tree. +// Convert a return statement to the backend representation. tree Return_statement::do_get_tree(Translate_context* context) { Function* function = context->function()->func_value(); tree fndecl = function->get_decl(); - if (fndecl == error_mark_node || DECL_RESULT(fndecl) == error_mark_node) - return error_mark_node; - - const Typed_identifier_list* results = this->results_; - if (this->vals_ == NULL) - { - tree stmt_list = NULL_TREE; - tree retval = function->return_value(context->gogo(), - context->function(), - this->location(), - &stmt_list); - tree set; - if (retval == NULL_TREE) - set = NULL_TREE; - else if (retval == error_mark_node) - return error_mark_node; - else - set = fold_build2_loc(this->location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(fndecl), retval); - append_to_statement_list(this->build_stmt_1(RETURN_EXPR, set), - &stmt_list); - return stmt_list; - } - else if (this->vals_->size() == 1) - { - gcc_assert(!VOID_TYPE_P(TREE_TYPE(TREE_TYPE(fndecl)))); - tree val = (*this->vals_->begin())->get_tree(context); - gcc_assert(results != NULL && results->size() == 1); - val = Expression::convert_for_assignment(context, - results->begin()->type(), - (*this->vals_->begin())->type(), - val, this->location()); - if (val == error_mark_node) - return error_mark_node; - tree set = build2(MODIFY_EXPR, void_type_node, - DECL_RESULT(fndecl), val); - SET_EXPR_LOCATION(set, this->location()); - return this->build_stmt_1(RETURN_EXPR, set); - } - else + Function::Results* results = function->result_variables(); + std::vector retvals; + if (results != NULL && !results->empty()) { - gcc_assert(!VOID_TYPE_P(TREE_TYPE(TREE_TYPE(fndecl)))); - tree stmt_list = NULL_TREE; - tree rettype = TREE_TYPE(DECL_RESULT(fndecl)); - tree retvar = create_tmp_var(rettype, "RESULT"); - gcc_assert(results != NULL && results->size() == this->vals_->size()); - Expression_list::const_iterator pv = this->vals_->begin(); - Typed_identifier_list::const_iterator pr = results->begin(); - for (tree field = TYPE_FIELDS(rettype); - field != NULL_TREE; - ++pv, ++pr, field = DECL_CHAIN(field)) + retvals.reserve(results->size()); + for (Function::Results::const_iterator p = results->begin(); + p != results->end(); + p++) { - gcc_assert(pv != this->vals_->end()); - tree val = (*pv)->get_tree(context); - val = Expression::convert_for_assignment(context, pr->type(), - (*pv)->type(), val, - this->location()); - if (val == error_mark_node) - return error_mark_node; - tree set = build2(MODIFY_EXPR, void_type_node, - build3(COMPONENT_REF, TREE_TYPE(field), - retvar, field, NULL_TREE), - val); - SET_EXPR_LOCATION(set, this->location()); - append_to_statement_list(set, &stmt_list); + tree rv = (*p)->get_tree(context->gogo(), context->function()); + retvals.push_back(tree_to_expr(rv)); } - tree set = build2(MODIFY_EXPR, void_type_node, DECL_RESULT(fndecl), - retvar); - append_to_statement_list(this->build_stmt_1(RETURN_EXPR, set), - &stmt_list); - return stmt_list; } + + Bstatement* ret; + ret = context->backend()->return_statement(tree_to_function(fndecl), + retvals, this->location()); + return statement_to_tree(ret); } // Make a return statement. Statement* -Statement::make_return_statement(const Typed_identifier_list* results, - Expression_list* vals, +Statement::make_return_statement(Expression_list* vals, source_location location) { - return new Return_statement(results, vals, location); + return new Return_statement(vals, location); } // A break or continue statement. diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 5199981..986d72b 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -200,8 +200,7 @@ class Statement // Make a return statement. static Statement* - make_return_statement(const Typed_identifier_list*, Expression_list*, - source_location); + make_return_statement(Expression_list*, source_location); // Make a break statement. static Statement* @@ -556,10 +555,9 @@ class Variable_declaration_statement : public Statement class Return_statement : public Statement { public: - Return_statement(const Typed_identifier_list* results, Expression_list* vals, - source_location location) + Return_statement(Expression_list* vals, source_location location) : Statement(STATEMENT_RETURN, location), - results_(results), vals_(vals) + vals_(vals), is_lowered_(false) { } // The list of values being returned. This may be NULL. @@ -578,12 +576,6 @@ class Return_statement : public Statement Statement* do_lower(Gogo*, Named_object*, Block*); - void - do_determine_types(); - - void - do_check_types(Gogo*); - bool do_may_fall_through() const { return false; } @@ -592,12 +584,10 @@ class Return_statement : public Statement do_get_tree(Translate_context*); private: - // The result types of the function we are returning from. This is - // here because in some of the traversals it is inconvenient to get - // it. - const Typed_identifier_list* results_; // Return values. This may be NULL. Expression_list* vals_; + // True if this statement has been lowered. + bool is_lowered_; }; // A send statement. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0aef9ce..1143376 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -7924,10 +7924,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, for (size_t i = 0; i < count; ++i) retvals->push_back(Expression::make_call_result(call, i)); } - const Function* function = gogo->current_function()->func_value(); - const Typed_identifier_list* results = function->type()->results(); - Statement* retstat = Statement::make_return_statement(results, retvals, - location); + Statement* retstat = Statement::make_return_statement(retvals, location); gogo->add_statement(retstat); } } -- cgit v1.1