summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-09-13 17:21:40 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-09-13 17:21:40 +0000
commita4f79468069de699d23db15e27100d2d00bb7fee (patch)
treed0f34b93af34f4568ebd1cc7e696bdb5d380cb07 /gcc/go/gofrontend
parent99c1d5bcdb5832b179cf456e4d2e601a59f7c7f1 (diff)
downloadgcc-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.cc74
-rw-r--r--gcc/go/gofrontend/statements.h25
-rw-r--r--gcc/go/gofrontend/types.cc8
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);
}
}