aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2016-04-26 20:37:58 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-04-26 20:37:58 +0000
commite64e93877bfe065068b7111b7aa74d8f7d78df8f (patch)
tree9037b628a43dc83bd08039aa7677c78fda77f011 /gcc/go
parent5e851c020abe8d78f73ace4ff8a3a2e047662865 (diff)
downloadgcc-e64e93877bfe065068b7111b7aa74d8f7d78df8f.zip
gcc-e64e93877bfe065068b7111b7aa74d8f7d78df8f.tar.gz
gcc-e64e93877bfe065068b7111b7aa74d8f7d78df8f.tar.bz2
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
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc118
-rw-r--r--gcc/go/gofrontend/expressions.h85
-rw-r--r--gcc/go/gofrontend/parse.cc24
4 files changed, 164 insertions, 65 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 6b2e105..5f24f22 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -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.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 170d957..05425bc 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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;
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 6c78060..c1e8191 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -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
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 827eb0a..c96ae1d 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -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;
}