From e64e93877bfe065068b7111b7aa74d8f7d78df8f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 26 Apr 2016 20:37:58 +0000 Subject: [PATCH] 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 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 118 +++++++++++++++++++------------ gcc/go/gofrontend/expressions.h | 85 ++++++++++++++++++++++ gcc/go/gofrontend/parse.cc | 24 ++----- 4 files changed, 164 insertions(+), 65 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 6b2e105a2d3..5f24f22aeae 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 170d95703c6..05425bcbc8a 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(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 6c780607f2d..c1e8191f6bd 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(); } + // 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(); } + + const Enclosed_var_expression* + enclosed_var_expression() const + { return this->convert(); } + + // 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 827eb0a120a..c96ae1dacec 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; }