Commit 280deda6 by Ian Lance Taylor

Fix inherited hidden methods that return hidden types.

From-SVN: r178818
parent bd1aa4f4
...@@ -402,7 +402,13 @@ Temporary_statement::do_check_types(Gogo*) ...@@ -402,7 +402,13 @@ Temporary_statement::do_check_types(Gogo*)
if (this->type_ != NULL && this->init_ != NULL) if (this->type_ != NULL && this->init_ != NULL)
{ {
std::string reason; 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()) if (reason.empty())
error_at(this->location(), "incompatible types in assignment"); error_at(this->location(), "incompatible types in assignment");
...@@ -504,9 +510,15 @@ class Assignment_statement : public Statement ...@@ -504,9 +510,15 @@ class Assignment_statement : public Statement
Assignment_statement(Expression* lhs, Expression* rhs, Assignment_statement(Expression* lhs, Expression* rhs,
source_location location) source_location location)
: Statement(STATEMENT_ASSIGNMENT, 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: protected:
int int
do_traverse(Traverse* traverse); do_traverse(Traverse* traverse);
...@@ -531,6 +543,9 @@ class Assignment_statement : public Statement ...@@ -531,6 +543,9 @@ class Assignment_statement : public Statement
Expression* lhs_; Expression* lhs_;
// Right hand side--the rvalue. // Right hand side--the rvalue.
Expression* rhs_; 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. // Traversal.
...@@ -579,7 +594,12 @@ Assignment_statement::do_check_types(Gogo*) ...@@ -579,7 +594,12 @@ Assignment_statement::do_check_types(Gogo*)
Type* lhs_type = this->lhs_->type(); Type* lhs_type = this->lhs_->type();
Type* rhs_type = this->rhs_->type(); Type* rhs_type = this->rhs_->type();
std::string reason; 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()) if (reason.empty())
error_at(this->location(), "incompatible types in assignment"); error_at(this->location(), "incompatible types in assignment");
...@@ -820,9 +840,15 @@ class Tuple_assignment_statement : public Statement ...@@ -820,9 +840,15 @@ class Tuple_assignment_statement : public Statement
Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs, Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
source_location location) source_location location)
: Statement(STATEMENT_TUPLE_ASSIGNMENT, 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: protected:
int int
do_traverse(Traverse* traverse); do_traverse(Traverse* traverse);
...@@ -846,6 +872,9 @@ class Tuple_assignment_statement : public Statement ...@@ -846,6 +872,9 @@ class Tuple_assignment_statement : public Statement
Expression_list* lhs_; Expression_list* lhs_;
// Right hand side--a list of rvalues. // Right hand side--a list of rvalues.
Expression_list* rhs_; 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. // Traversal.
...@@ -901,6 +930,8 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -901,6 +930,8 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
Temporary_statement* temp = Statement::make_temporary((*plhs)->type(), Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
*prhs, loc); *prhs, loc);
if (this->are_hidden_fields_ok_)
temp->set_hidden_fields_are_ok();
b->add_statement(temp); b->add_statement(temp);
temps.push_back(temp); temps.push_back(temp);
...@@ -924,6 +955,11 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, ...@@ -924,6 +955,11 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
Expression* ref = Expression::make_temporary_reference(*ptemp, loc); Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
Statement* s = Statement::make_assignment(*plhs, ref, 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); b->add_statement(s);
++ptemp; ++ptemp;
} }
...@@ -2592,7 +2628,12 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, ...@@ -2592,7 +2628,12 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
e->determine_type(&type_context); e->determine_type(&type_context);
std::string reason; 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()); Expression* ve = Expression::make_var_reference(rv, e->location());
lhs->push_back(ve); lhs->push_back(ve);
...@@ -2614,13 +2655,28 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing, ...@@ -2614,13 +2655,28 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
; ;
else if (lhs->size() == 1) else if (lhs->size() == 1)
{ {
b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(), Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
loc)); 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 lhs;
delete rhs; delete rhs;
} }
else 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); b->add_statement(this);
...@@ -2670,7 +2726,7 @@ Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const ...@@ -2670,7 +2726,7 @@ Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
// Make a return statement. // Make a return statement.
Statement* Return_statement*
Statement::make_return_statement(Expression_list* vals, Statement::make_return_statement(Expression_list* vals,
source_location location) source_location location)
{ {
......
...@@ -204,7 +204,7 @@ class Statement ...@@ -204,7 +204,7 @@ class Statement
make_defer_statement(Call_expression* call, source_location); make_defer_statement(Call_expression* call, source_location);
// Make a return statement. // Make a return statement.
static Statement* static Return_statement*
make_return_statement(Expression_list*, source_location); make_return_statement(Expression_list*, source_location);
// Make a break statement. // Make a break statement.
...@@ -482,13 +482,20 @@ class Temporary_statement : public Statement ...@@ -482,13 +482,20 @@ class Temporary_statement : public Statement
public: public:
Temporary_statement(Type* type, Expression* init, source_location location) Temporary_statement(Type* type, Expression* init, source_location location)
: Statement(STATEMENT_TEMPORARY, 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. // Return the type of the temporary variable.
Type* Type*
type() const; 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 // Record that something takes the address of this temporary
// variable. // variable.
void void
...@@ -526,6 +533,9 @@ class Temporary_statement : public Statement ...@@ -526,6 +533,9 @@ class Temporary_statement : public Statement
Expression* init_; Expression* init_;
// The backend representation of the temporary variable. // The backend representation of the temporary variable.
Bvariable* bvariable_; 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. // True if something takes the address of this temporary variable.
bool is_address_taken_; bool is_address_taken_;
}; };
...@@ -570,7 +580,7 @@ class Return_statement : public Statement ...@@ -570,7 +580,7 @@ class Return_statement : public Statement
public: public:
Return_statement(Expression_list* vals, source_location location) Return_statement(Expression_list* vals, source_location location)
: Statement(STATEMENT_RETURN, 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. // The list of values being returned. This may be NULL.
...@@ -578,6 +588,12 @@ class Return_statement : public Statement ...@@ -578,6 +588,12 @@ class Return_statement : public Statement
vals() const vals() const
{ return this->vals_; } { 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: protected:
int int
do_traverse(Traverse* traverse) do_traverse(Traverse* traverse)
...@@ -602,6 +618,9 @@ class Return_statement : public Statement ...@@ -602,6 +618,9 @@ class Return_statement : public Statement
private: private:
// Return values. This may be NULL. // Return values. This may be NULL.
Expression_list* vals_; 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. // True if this statement has been lowered.
bool is_lowered_; bool is_lowered_;
}; };
......
...@@ -7414,7 +7414,13 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, ...@@ -7414,7 +7414,13 @@ Type::build_one_stub_method(Gogo* gogo, Method* method,
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
retvals->push_back(Expression::make_call_result(call, 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); gogo->add_statement(retstat);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment