Use backend interface for return statements.
authorIan Lance Taylor <iant@google.com>
Mon, 4 Apr 2011 23:19:09 +0000 (23:19 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 4 Apr 2011 23:19:09 +0000 (23:19 +0000)
* 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

12 files changed:
gcc/go/ChangeLog
gcc/go/Make-lang.in
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
gcc/go/gofrontend/types.cc

index 5d50db2d560ba49e25a56c389a28503bfaef1c36..b8a11f6d5d1dca718a477b45ca5e9148267091e3 100644 (file)
@@ -1,3 +1,14 @@
+2011-04-04  Ian Lance Taylor  <iant@google.com>
+
+       * 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  <iant@google.com>
 
        * go-gcc.cc: New file.
index 07c884d6cb8890c9e57a376670af1df8f02e1946..67900d7749733901e048b24cc4009007db41ac4f 100644 (file)
@@ -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
index ca2d63b1b665ab7b4973dcfcf1c74e661ec92dc5..2785bf296dc743b3fa671adbf69fbe8389ba3880 100644 (file)
@@ -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<Bexpression*>&,
+                  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<Bexpression*>& 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<Bexpression*>::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)
 {
index babef83274283947d9f7247d40c3800fb2ff647d..959fc7862c061bf178567e26b49c51010f852afb 100644 (file)
@@ -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<Btype*> 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<Bexpression*>&,
+                  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)
index e295c7d6b2966590a568cb289d70c86fed6c2698..a0cfcfcdf7452f55d77e240f7b6fc2ef59508fd4 100644 (file)
@@ -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);
 
index 2f52aa20b6ce0d97af8892d025a9ba0b87684514..bd5945bd7ba6072c98f55643cca282263677c41c 100644 (file)
@@ -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),
index 645014154d5b4eb6a3f4193ea5c878ef3adbd788..5b3ac8cd9c28f9455c4fcf5d6119a2fb440d1031 100644 (file)
@@ -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_);
index b6b1f4d7c1496251a23032a5fa248e1ad7b91a07..87e2da6890b5a5c556e5cf69001c7e25dc878db1 100644 (file)
@@ -822,14 +822,27 @@ class Function
     this->enclosing_ = enclosing;
   }
 
-  // Create the named result variables in the outer block.
+  // The result variables.
+  typedef std::vector<Named_object*> 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_object*> Named_results;
-
   typedef std::vector<std::pair<Named_object*,
                                source_location> > 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.
index 970dc159ed13436a8e42bd8b433ccb7e639fc214..e5ea636b08aa1078753a961c7f2e4078b07d6636 100644 (file)
@@ -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 ] .
index b1e7613eb509f11b9eafbd4c4fdf7255ecbbc23d..3783fb83a519b3b52c89b120d78110e836c2aef3 100644 (file)
@@ -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<Bexpression*> 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.
index 5199981ea64e937036dab7f6f593737c9d6f60c2..986d72b8780e0c0d34d900111d5e07c3aba587a1 100644 (file)
@@ -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.
index 0aef9ce4cc52b4f1f90d18635d69a12a206c2c62..1143376e4b37d1bdc80ede71e0a02e1071780ae7 100644 (file)
@@ -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);
     }
 }