This patch by Chris Manghane adds Enclosed_var_expression to the Go
frontend.  This represents a reference from a function literal to a
variable defined in the enclosing function.  This simplifies the
existing code, and provides a base for future work.  Bootstrapped and
ran Go testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 235383)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -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.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 235383)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -782,6 +782,74 @@ Expression::make_var_reference(Named_obj
   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_stru
          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;
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h     (revision 235383)
+++ gcc/go/gofrontend/expressions.h     (working copy)
@@ -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
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc  (revision 234304)
+++ gcc/go/gofrontend/parse.cc  (working copy)
@@ -2658,7 +2658,7 @@ Parse::enclosing_var_reference(Named_obj
                                                   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;
 }
 

Reply via email to