Commit e64e9387 by Ian Lance Taylor

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
parent 5e851c02
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;
}
......
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