diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-09-13 17:21:40 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-09-13 17:21:40 +0000 |
commit | a4f79468069de699d23db15e27100d2d00bb7fee (patch) | |
tree | d0f34b93af34f4568ebd1cc7e696bdb5d380cb07 /gcc/go/gofrontend | |
parent | 99c1d5bcdb5832b179cf456e4d2e601a59f7c7f1 (diff) | |
download | gcc-a4f79468069de699d23db15e27100d2d00bb7fee.tar.gz |
Fix inherited hidden methods that return hidden types.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178818 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 74 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 25 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 8 |
3 files changed, 94 insertions, 13 deletions
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index e6462274dff..bb43dcdee43 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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) { diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 0a87a8b733c..8206a08c361 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -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_; }; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index cf404a36496..6e87056be7e 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -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); } } |