OSDN Git Service

Fix inherited hidden methods that return hidden types.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Sep 2011 17:21:40 +0000 (17:21 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Sep 2011 17:21:40 +0000 (17:21 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178818 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
gcc/go/gofrontend/types.cc

index e646227..bb43dcd 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;
     }
@@ -2592,7 +2628,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 +2655,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 +2726,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)
 {
index 0a87a8b..8206a08 100644 (file)
@@ -204,7 +204,7 @@ class Statement
   make_defer_statement(Call_expression* call, source_location);
 
   // Make a return statement.
-  static Statement*
+  static Return_statement*
   make_return_statement(Expression_list*, source_location);
 
   // Make a break statement.
@@ -482,13 +482,20 @@ class Temporary_statement : public Statement
  public:
   Temporary_statement(Type* type, Expression* init, source_location location)
     : Statement(STATEMENT_TEMPORARY, location),
-      type_(type), init_(init), bvariable_(NULL), is_address_taken_(false)
+      type_(type), init_(init), bvariable_(NULL), are_hidden_fields_ok_(false),
+      is_address_taken_(false)
   { }
 
   // Return the type of the temporary variable.
   Type*
   type() const;
 
+  // Note that it is OK for this return statement to set hidden
+  // fields.
+  void
+  set_hidden_fields_are_ok()
+  { this->are_hidden_fields_ok_ = true; }
+
   // Record that something takes the address of this temporary
   // variable.
   void
@@ -526,6 +533,9 @@ class Temporary_statement : public Statement
   Expression* init_;
   // The backend representation of the temporary variable.
   Bvariable* bvariable_;
+  // True if this statement may pass hidden fields in the return
+  // value.  This is used for generated method stubs.
+  bool are_hidden_fields_ok_;
   // True if something takes the address of this temporary variable.
   bool is_address_taken_;
 };
@@ -570,7 +580,7 @@ class Return_statement : public Statement
  public:
   Return_statement(Expression_list* vals, source_location location)
     : Statement(STATEMENT_RETURN, location),
-      vals_(vals), is_lowered_(false)
+      vals_(vals), are_hidden_fields_ok_(false), is_lowered_(false)
   { }
 
   // The list of values being returned.  This may be NULL.
@@ -578,6 +588,12 @@ class Return_statement : public Statement
   vals() const
   { return this->vals_; }
 
+  // Note that it is OK for this return statement to set hidden
+  // fields.
+  void
+  set_hidden_fields_are_ok()
+  { this->are_hidden_fields_ok_ = true; }
+
  protected:
   int
   do_traverse(Traverse* traverse)
@@ -602,6 +618,9 @@ class Return_statement : public Statement
  private:
   // Return values.  This may be NULL.
   Expression_list* vals_;
+  // True if this statement may pass hidden fields in the return
+  // value.  This is used for generated method stubs.
+  bool are_hidden_fields_ok_;
   // True if this statement has been lowered.
   bool is_lowered_;
 };
index cf404a3..6e87056 100644 (file)
@@ -7414,7 +7414,13 @@ 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));
        }
-      Statement* retstat = Statement::make_return_statement(retvals, location);
+      Return_statement* retstat = Statement::make_return_statement(retvals,
+                                                                  location);
+
+      // We can return values with hidden fields from a stub.  This is
+      // necessary if the method is itself hidden.
+      retstat->set_hidden_fields_are_ok();
+
       gogo->add_statement(retstat);
     }
 }