OSDN Git Service

Fix defer when not calling recover in function with named results.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / statements.cc
index e646227..82be112 100644 (file)
@@ -402,7 +402,13 @@ Temporary_statement::do_check_types(Gogo*)
   if (this->type_ != NULL && this->init_ != NULL)
     {
       std::string reason;
-      if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
+      bool ok;
+      if (this->are_hidden_fields_ok_)
+       ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(),
+                                           &reason);
+      else
+       ok = Type::are_assignable(this->type_, this->init_->type(), &reason);
+      if (!ok)
        {
          if (reason.empty())
            error_at(this->location(), "incompatible types in assignment");
@@ -504,9 +510,15 @@ class Assignment_statement : public Statement
   Assignment_statement(Expression* lhs, Expression* rhs,
                       source_location location)
     : Statement(STATEMENT_ASSIGNMENT, location),
-      lhs_(lhs), rhs_(rhs)
+      lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
   { }
 
+  // Note that it is OK for this assignment statement to set hidden
+  // fields.
+  void
+  set_hidden_fields_are_ok()
+  { this->are_hidden_fields_ok_ = true; }
+
  protected:
   int
   do_traverse(Traverse* traverse);
@@ -531,6 +543,9 @@ class Assignment_statement : public Statement
   Expression* lhs_;
   // Right hand side--the rvalue.
   Expression* rhs_;
+  // True if this statement may set hidden fields in the assignment
+  // statement.  This is used for generated method stubs.
+  bool are_hidden_fields_ok_;
 };
 
 // Traversal.
@@ -579,7 +594,12 @@ Assignment_statement::do_check_types(Gogo*)
   Type* lhs_type = this->lhs_->type();
   Type* rhs_type = this->rhs_->type();
   std::string reason;
-  if (!Type::are_assignable(lhs_type, rhs_type, &reason))
+  bool ok;
+  if (this->are_hidden_fields_ok_)
+    ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason);
+  else
+    ok = Type::are_assignable(lhs_type, rhs_type, &reason);
+  if (!ok)
     {
       if (reason.empty())
        error_at(this->location(), "incompatible types in assignment");
@@ -820,9 +840,15 @@ class Tuple_assignment_statement : public Statement
   Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
                             source_location location)
     : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
-      lhs_(lhs), rhs_(rhs)
+      lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
   { }
 
+  // Note that it is OK for this assignment statement to set hidden
+  // fields.
+  void
+  set_hidden_fields_are_ok()
+  { this->are_hidden_fields_ok_ = true; }
+
  protected:
   int
   do_traverse(Traverse* traverse);
@@ -846,6 +872,9 @@ class Tuple_assignment_statement : public Statement
   Expression_list* lhs_;
   // Right hand side--a list of rvalues.
   Expression_list* rhs_;
+  // True if this statement may set hidden fields in the assignment
+  // statement.  This is used for generated method stubs.
+  bool are_hidden_fields_ok_;
 };
 
 // Traversal.
@@ -901,6 +930,8 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
 
       Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
                                                            *prhs, loc);
+      if (this->are_hidden_fields_ok_)
+       temp->set_hidden_fields_are_ok();
       b->add_statement(temp);
       temps.push_back(temp);
 
@@ -924,6 +955,11 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
 
       Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
       Statement* s = Statement::make_assignment(*plhs, ref, loc);
+      if (this->are_hidden_fields_ok_)
+       {
+         Assignment_statement* as = static_cast<Assignment_statement*>(s);
+         as->set_hidden_fields_are_ok();
+       }
       b->add_statement(s);
       ++ptemp;
     }
@@ -2503,11 +2539,10 @@ Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
 
 // Lower a return statement.  If we are returning a function call
 // which returns multiple values which match the current function,
-// split up the call's results.  If the function has named result
-// variables, and the return statement lists explicit values, then
-// implement it by assigning the values to the result variables and
-// changing the statement to not list any values.  This lets
-// panic/recover work correctly.
+// split up the call's results.  If the return statement lists
+// explicit values, implement this statement by assigning the values
+// to the result variables and change this statement to a naked
+// return.  This lets panic/recover work correctly.
 
 Statement*
 Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
@@ -2592,7 +2627,12 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
       e->determine_type(&type_context);
 
       std::string reason;
-      if (Type::are_assignable(rvtype, e->type(), &reason))
+      bool ok;
+      if (this->are_hidden_fields_ok_)
+       ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason);
+      else
+       ok = Type::are_assignable(rvtype, e->type(), &reason);
+      if (ok)
        {
          Expression* ve = Expression::make_var_reference(rv, e->location());
          lhs->push_back(ve);
@@ -2614,13 +2654,28 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
     ;
   else if (lhs->size() == 1)
     {
-      b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
-                                                 loc));
+      Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
+                                               loc);
+      if (this->are_hidden_fields_ok_)
+       {
+         Assignment_statement* as = static_cast<Assignment_statement*>(s);
+         as->set_hidden_fields_are_ok();
+       }
+      b->add_statement(s);
       delete lhs;
       delete rhs;
     }
   else
-    b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
+    {
+      Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
+      if (this->are_hidden_fields_ok_)
+       {
+         Tuple_assignment_statement* tas =
+           static_cast<Tuple_assignment_statement*>(s);
+         tas->set_hidden_fields_are_ok();
+       }
+      b->add_statement(s);
+    }
 
   b->add_statement(this);
 
@@ -2670,7 +2725,7 @@ Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
 
 // Make a return statement.
 
-Statement*
+Return_statement*
 Statement::make_return_statement(Expression_list* vals,
                                 source_location location)
 {