compiler: Add Enclosed_var_expression.
Introduces an abstraction for a variable referenced in a closure. This maintains the underlying expression which accesses a field within a closure variable and gives easy access to the underlying Named_object. Reviewed-on: https://go-review.googlesource.com/22374 From-SVN: r235452
This commit is contained in:
parent
5e851c020a
commit
e64e93877b
4 changed files with 164 additions and 65 deletions
|
@ -1,4 +1,4 @@
|
|||
944c3ca6ac7c204585fd73936894fe05de535b94
|
||||
ba520fdcbea95531ebb9ef3d5be2de405ca90df3
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -782,6 +782,74 @@ Expression::make_var_reference(Named_object* var, Location location)
|
|||
return new Var_expression(var, location);
|
||||
}
|
||||
|
||||
// Class Enclosed_var_expression.
|
||||
|
||||
int
|
||||
Enclosed_var_expression::do_traverse(Traverse*)
|
||||
{
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// Lower the reference to the enclosed variable.
|
||||
|
||||
Expression*
|
||||
Enclosed_var_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||
Statement_inserter* inserter, int)
|
||||
{
|
||||
gogo->lower_expression(function, inserter, &this->reference_);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Flatten the reference to the enclosed variable.
|
||||
|
||||
Expression*
|
||||
Enclosed_var_expression::do_flatten(Gogo* gogo, Named_object* function,
|
||||
Statement_inserter* inserter)
|
||||
{
|
||||
gogo->flatten_expression(function, inserter, &this->reference_);
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
Enclosed_var_expression::do_address_taken(bool escapes)
|
||||
{
|
||||
if (!escapes)
|
||||
{
|
||||
if (this->variable_->is_variable())
|
||||
this->variable_->var_value()->set_non_escaping_address_taken();
|
||||
else if (this->variable_->is_result_variable())
|
||||
this->variable_->result_var_value()->set_non_escaping_address_taken();
|
||||
else
|
||||
go_unreachable();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->variable_->is_variable())
|
||||
this->variable_->var_value()->set_address_taken();
|
||||
else if (this->variable_->is_result_variable())
|
||||
this->variable_->result_var_value()->set_address_taken();
|
||||
else
|
||||
go_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// Ast dump for enclosed variable expression.
|
||||
|
||||
void
|
||||
Enclosed_var_expression::do_dump_expression(Ast_dump_context* adc) const
|
||||
{
|
||||
adc->ostream() << this->variable_->name();
|
||||
}
|
||||
|
||||
// Make a reference to a variable within an enclosing function.
|
||||
|
||||
Expression*
|
||||
Expression::make_enclosing_var_reference(Expression* reference,
|
||||
Named_object* var, Location location)
|
||||
{
|
||||
return new Enclosed_var_expression(reference, var, location);
|
||||
}
|
||||
|
||||
// Class Temporary_reference_expression.
|
||||
|
||||
// The type.
|
||||
|
@ -12814,53 +12882,12 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
|
|||
no = name_expr->var_expression()->named_object();
|
||||
break;
|
||||
|
||||
case EXPRESSION_FUNC_REFERENCE:
|
||||
no = name_expr->func_expression()->named_object();
|
||||
case EXPRESSION_ENCLOSED_VAR_REFERENCE:
|
||||
no = name_expr->enclosed_var_expression()->variable();
|
||||
break;
|
||||
|
||||
case EXPRESSION_UNARY:
|
||||
// If there is a local variable around with the same name as
|
||||
// the field, and this occurs in the closure, then the
|
||||
// parser may turn the field reference into an indirection
|
||||
// through the closure. FIXME: This is a mess.
|
||||
{
|
||||
bad_key = true;
|
||||
Unary_expression* ue = static_cast<Unary_expression*>(name_expr);
|
||||
if (ue->op() == OPERATOR_MULT)
|
||||
{
|
||||
Field_reference_expression* fre =
|
||||
ue->operand()->field_reference_expression();
|
||||
if (fre != NULL)
|
||||
{
|
||||
Struct_type* st =
|
||||
fre->expr()->type()->deref()->struct_type();
|
||||
if (st != NULL)
|
||||
{
|
||||
const Struct_field* sf = st->field(fre->field_index());
|
||||
name = sf->field_name();
|
||||
|
||||
// See below. FIXME.
|
||||
if (!Gogo::is_hidden_name(name)
|
||||
&& name[0] >= 'a'
|
||||
&& name[0] <= 'z')
|
||||
{
|
||||
if (gogo->lookup_global(name.c_str()) != NULL)
|
||||
name = gogo->pack_hidden_name(name, false);
|
||||
}
|
||||
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof buf, "%u", fre->field_index());
|
||||
size_t buflen = strlen(buf);
|
||||
if (name.compare(name.length() - buflen, buflen, buf)
|
||||
== 0)
|
||||
{
|
||||
name = name.substr(0, name.length() - buflen);
|
||||
bad_key = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case EXPRESSION_FUNC_REFERENCE:
|
||||
no = name_expr->func_expression()->named_object();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -13301,6 +13328,7 @@ Expression::is_variable() const
|
|||
case EXPRESSION_VAR_REFERENCE:
|
||||
case EXPRESSION_TEMPORARY_REFERENCE:
|
||||
case EXPRESSION_SET_AND_USE_TEMPORARY:
|
||||
case EXPRESSION_ENCLOSED_VAR_REFERENCE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -29,6 +29,7 @@ class Struct_type;
|
|||
class Struct_field;
|
||||
class Expression_list;
|
||||
class Var_expression;
|
||||
class Enclosed_var_expression;
|
||||
class Temporary_reference_expression;
|
||||
class Set_and_use_temporary_expression;
|
||||
class String_expression;
|
||||
|
@ -85,6 +86,7 @@ class Expression
|
|||
EXPRESSION_BINARY,
|
||||
EXPRESSION_CONST_REFERENCE,
|
||||
EXPRESSION_VAR_REFERENCE,
|
||||
EXPRESSION_ENCLOSED_VAR_REFERENCE,
|
||||
EXPRESSION_TEMPORARY_REFERENCE,
|
||||
EXPRESSION_SET_AND_USE_TEMPORARY,
|
||||
EXPRESSION_SINK,
|
||||
|
@ -166,6 +168,10 @@ class Expression
|
|||
static Expression*
|
||||
make_var_reference(Named_object*, Location);
|
||||
|
||||
// Make a reference to a variable within an enclosing function.
|
||||
static Expression*
|
||||
make_enclosing_var_reference(Expression*, Named_object*, Location);
|
||||
|
||||
// Make a reference to a temporary variable. Temporary variables
|
||||
// are always created by a single statement, which is what we use to
|
||||
// refer to them.
|
||||
|
@ -539,6 +545,20 @@ class Expression
|
|||
var_expression() const
|
||||
{ return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); }
|
||||
|
||||
// If this is a enclosed_variable reference, return the
|
||||
// Enclosed_var_expression structure. Otherwise, return NULL.
|
||||
// This is a controlled dynamic cast.
|
||||
Enclosed_var_expression*
|
||||
enclosed_var_expression()
|
||||
{ return this->convert<Enclosed_var_expression,
|
||||
EXPRESSION_ENCLOSED_VAR_REFERENCE>(); }
|
||||
|
||||
const Enclosed_var_expression*
|
||||
enclosed_var_expression() const
|
||||
{ return this->convert<const Enclosed_var_expression,
|
||||
EXPRESSION_ENCLOSED_VAR_REFERENCE>(); }
|
||||
|
||||
|
||||
// If this is a reference to a temporary variable, return the
|
||||
// Temporary_reference_expression. Otherwise, return NULL.
|
||||
Temporary_reference_expression*
|
||||
|
@ -1258,6 +1278,71 @@ class Var_expression : public Expression
|
|||
Named_object* variable_;
|
||||
};
|
||||
|
||||
// A reference to a variable within an enclosing function.
|
||||
|
||||
class Enclosed_var_expression : public Expression
|
||||
{
|
||||
public:
|
||||
Enclosed_var_expression(Expression* reference, Named_object* variable,
|
||||
Location location)
|
||||
: Expression(EXPRESSION_ENCLOSED_VAR_REFERENCE, location),
|
||||
reference_(reference), variable_(variable)
|
||||
{ }
|
||||
|
||||
// The reference to the enclosed variable. This will be an indirection of the
|
||||
// the field stored within closure variable.
|
||||
Expression*
|
||||
reference() const
|
||||
{ return this->reference_; }
|
||||
|
||||
// The variable being enclosed and referenced.
|
||||
Named_object*
|
||||
variable() const
|
||||
{ return this->variable_; }
|
||||
|
||||
protected:
|
||||
int
|
||||
do_traverse(Traverse*);
|
||||
|
||||
Expression*
|
||||
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||
|
||||
Expression*
|
||||
do_flatten(Gogo*, Named_object*, Statement_inserter*);
|
||||
|
||||
Type*
|
||||
do_type()
|
||||
{ return this->reference_->type(); }
|
||||
|
||||
void
|
||||
do_determine_type(const Type_context* context)
|
||||
{ return this->reference_->determine_type(context); }
|
||||
|
||||
Expression*
|
||||
do_copy()
|
||||
{ return this; }
|
||||
|
||||
bool
|
||||
do_is_addressable() const
|
||||
{ return this->reference_->is_addressable(); }
|
||||
|
||||
void
|
||||
do_address_taken(bool escapes);
|
||||
|
||||
Bexpression*
|
||||
do_get_backend(Translate_context* context)
|
||||
{ return this->reference_->get_backend(context); }
|
||||
|
||||
void
|
||||
do_dump_expression(Ast_dump_context*) const;
|
||||
|
||||
private:
|
||||
// The reference to the enclosed variable.
|
||||
Expression* reference_;
|
||||
// The variable being enclosed.
|
||||
Named_object* variable_;
|
||||
};
|
||||
|
||||
// A reference to a temporary variable.
|
||||
|
||||
class Temporary_reference_expression : public Expression
|
||||
|
|
|
@ -2658,7 +2658,7 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
|
|||
ins.first->index(),
|
||||
location);
|
||||
e = Expression::make_unary(OPERATOR_MULT, e, location);
|
||||
return e;
|
||||
return Expression::make_enclosing_var_reference(e, var, location);
|
||||
}
|
||||
|
||||
// CompositeLit = LiteralType LiteralValue .
|
||||
|
@ -5791,24 +5791,10 @@ Parse::verify_not_sink(Expression* expr)
|
|||
|
||||
// If this can not be a sink, and it is a variable, then we are
|
||||
// using the variable, not just assigning to it.
|
||||
Var_expression* ve = expr->var_expression();
|
||||
if (ve != NULL)
|
||||
this->mark_var_used(ve->named_object());
|
||||
else if (expr->deref()->field_reference_expression() != NULL
|
||||
&& this->gogo_->current_function() != NULL)
|
||||
{
|
||||
// We could be looking at a variable referenced from a closure.
|
||||
// If so, we need to get the enclosed variable and mark it as used.
|
||||
Function* this_function = this->gogo_->current_function()->func_value();
|
||||
Named_object* closure = this_function->closure_var();
|
||||
if (closure != NULL)
|
||||
{
|
||||
unsigned int var_index =
|
||||
expr->deref()->field_reference_expression()->field_index();
|
||||
this->mark_var_used(this_function->enclosing_var(var_index - 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (expr->var_expression() != NULL)
|
||||
this->mark_var_used(expr->var_expression()->named_object());
|
||||
else if (expr->enclosed_var_expression() != NULL)
|
||||
this->mark_var_used(expr->enclosed_var_expression()->variable());
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue