This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Go patch committed: Use backend interface for return statements


This patch uses the new backend interface for return statements.  To
simplify this, the frontend now always creates result parameters, even
if they have no names.  Lowering a return statement now assigns the
values to the result parameters.  This permits a return statement to
just copy the values to DECL_RESULT and run a RETURN_EXPR.  I was able
to remove the results_ field from Return_statement.  Bootstrapped and
ran Go testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


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).


Index: gcc/go/Make-lang.in
===================================================================
--- gcc/go/Make-lang.in	(revision 171917)
+++ gcc/go/Make-lang.in	(working copy)
@@ -236,7 +236,8 @@ go/go-lang.o: go/go-lang.c $(CONFIG_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: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 171917)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -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: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 171917)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -642,7 +642,7 @@ Gogo::start_function(const std::string& 
 	}
     }
 
-  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_obj
 	  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_obj
   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(Bi
 
 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(
        ++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(
 // 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: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 171917)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -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: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 171846)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -7924,10 +7924,7 @@ Type::build_one_stub_method(Gogo* gogo, 
 	  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);
     }
 }
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc	(revision 171846)
+++ gcc/go/gofrontend/parse.cc	(working copy)
@@ -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: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 171846)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -10415,8 +10415,7 @@ Selector_expression::lower_method_expres
 	  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: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc	(revision 171917)
+++ gcc/go/gofrontend/statements.cc	(working copy)
@@ -561,9 +561,10 @@ Assignment_statement::do_get_tree(Transl
   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,
 
       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_assignment
 // 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_
   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
-    {
-      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))
+  Function::Results* results = function->result_variables();
+  std::vector<Bexpression*> retvals;
+  if (results != NULL && !results->empty())
+    {
+      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: gcc/go/gofrontend/gogo-tree.cc
===================================================================
--- gcc/go/gofrontend/gogo-tree.cc	(revision 171846)
+++ gcc/go/gofrontend/gogo-tree.cc	(working copy)
@@ -1761,27 +1761,16 @@ Function::return_value(Gogo* gogo, Named
   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
 	{
 	  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: gcc/go/gofrontend/statements.h
===================================================================
--- gcc/go/gofrontend/statements.h	(revision 171846)
+++ gcc/go/gofrontend/statements.h	(working copy)
@@ -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 : p
 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 Statemen
   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 Statemen
   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: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 171917)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]