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 The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -782,6 +782,74 @@ Expression::make_var_reference(Named_object* var, Location location) ...@@ -782,6 +782,74 @@ Expression::make_var_reference(Named_object* var, Location location)
return new Var_expression(var, 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. // Class Temporary_reference_expression.
// The type. // The type.
...@@ -12814,53 +12882,12 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) ...@@ -12814,53 +12882,12 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
no = name_expr->var_expression()->named_object(); no = name_expr->var_expression()->named_object();
break; break;
case EXPRESSION_FUNC_REFERENCE: case EXPRESSION_ENCLOSED_VAR_REFERENCE:
no = name_expr->func_expression()->named_object(); no = name_expr->enclosed_var_expression()->variable();
break; break;
case EXPRESSION_UNARY: case EXPRESSION_FUNC_REFERENCE:
// If there is a local variable around with the same name as no = name_expr->func_expression()->named_object();
// 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;
}
}
}
}
}
break; break;
default: default:
...@@ -13301,6 +13328,7 @@ Expression::is_variable() const ...@@ -13301,6 +13328,7 @@ Expression::is_variable() const
case EXPRESSION_VAR_REFERENCE: case EXPRESSION_VAR_REFERENCE:
case EXPRESSION_TEMPORARY_REFERENCE: case EXPRESSION_TEMPORARY_REFERENCE:
case EXPRESSION_SET_AND_USE_TEMPORARY: case EXPRESSION_SET_AND_USE_TEMPORARY:
case EXPRESSION_ENCLOSED_VAR_REFERENCE:
return true; return true;
default: default:
return false; return false;
......
...@@ -29,6 +29,7 @@ class Struct_type; ...@@ -29,6 +29,7 @@ class Struct_type;
class Struct_field; class Struct_field;
class Expression_list; class Expression_list;
class Var_expression; class Var_expression;
class Enclosed_var_expression;
class Temporary_reference_expression; class Temporary_reference_expression;
class Set_and_use_temporary_expression; class Set_and_use_temporary_expression;
class String_expression; class String_expression;
...@@ -85,6 +86,7 @@ class Expression ...@@ -85,6 +86,7 @@ class Expression
EXPRESSION_BINARY, EXPRESSION_BINARY,
EXPRESSION_CONST_REFERENCE, EXPRESSION_CONST_REFERENCE,
EXPRESSION_VAR_REFERENCE, EXPRESSION_VAR_REFERENCE,
EXPRESSION_ENCLOSED_VAR_REFERENCE,
EXPRESSION_TEMPORARY_REFERENCE, EXPRESSION_TEMPORARY_REFERENCE,
EXPRESSION_SET_AND_USE_TEMPORARY, EXPRESSION_SET_AND_USE_TEMPORARY,
EXPRESSION_SINK, EXPRESSION_SINK,
...@@ -166,6 +168,10 @@ class Expression ...@@ -166,6 +168,10 @@ class Expression
static Expression* static Expression*
make_var_reference(Named_object*, Location); 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 // Make a reference to a temporary variable. Temporary variables
// are always created by a single statement, which is what we use to // are always created by a single statement, which is what we use to
// refer to them. // refer to them.
...@@ -539,6 +545,20 @@ class Expression ...@@ -539,6 +545,20 @@ class Expression
var_expression() const var_expression() const
{ return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); } { 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 // If this is a reference to a temporary variable, return the
// Temporary_reference_expression. Otherwise, return NULL. // Temporary_reference_expression. Otherwise, return NULL.
Temporary_reference_expression* Temporary_reference_expression*
...@@ -1258,6 +1278,71 @@ class Var_expression : public Expression ...@@ -1258,6 +1278,71 @@ class Var_expression : public Expression
Named_object* variable_; 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. // A reference to a temporary variable.
class Temporary_reference_expression : public Expression class Temporary_reference_expression : public Expression
......
...@@ -2658,7 +2658,7 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var, ...@@ -2658,7 +2658,7 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
ins.first->index(), ins.first->index(),
location); location);
e = Expression::make_unary(OPERATOR_MULT, e, location); e = Expression::make_unary(OPERATOR_MULT, e, location);
return e; return Expression::make_enclosing_var_reference(e, var, location);
} }
// CompositeLit = LiteralType LiteralValue . // CompositeLit = LiteralType LiteralValue .
...@@ -5791,24 +5791,10 @@ Parse::verify_not_sink(Expression* expr) ...@@ -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 // If this can not be a sink, and it is a variable, then we are
// using the variable, not just assigning to it. // using the variable, not just assigning to it.
Var_expression* ve = expr->var_expression(); if (expr->var_expression() != NULL)
if (ve != NULL) this->mark_var_used(expr->var_expression()->named_object());
this->mark_var_used(ve->named_object()); else if (expr->enclosed_var_expression() != NULL)
else if (expr->deref()->field_reference_expression() != NULL this->mark_var_used(expr->enclosed_var_expression()->variable());
&& 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));
}
}
return expr; 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