Fix bug with taking address of a variable when address does not escape.
authorIan Lance Taylor <iant@google.com>
Thu, 12 May 2011 18:35:05 +0000 (18:35 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 12 May 2011 18:35:05 +0000 (18:35 +0000)
* go-gcc.cc (Gcc_backend::local_variable): Add is_address_taken
parameter.
(Gcc_backend::parameter_variable): Likewise.

From-SVN: r173712

gcc/go/ChangeLog
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h

index 4136702481bca89e4bc02a4aff9cf1abd03c354d..63a47c1efcd7faf2061eb3d077606da384b95a35 100644 (file)
@@ -1,3 +1,9 @@
+2011-05-12  Ian Lance Taylor  <iant@google.com>
+
+       * go-gcc.cc (Gcc_backend::local_variable): Add is_address_taken
+       parameter.
+       (Gcc_backend::parameter_variable): Likewise.
+
 2011-05-07  Eric Botcazou  <ebotcazou@adacore.com>
 
        * go-lang.c (global_bindings_p): Return bool and simplify.
index f5a6fb579ac002f49abd93e9c145c7b24cc0bf4b..49f574a58fd227689944409c462c1ef1d5eb091b 100644 (file)
@@ -260,11 +260,11 @@ class Gcc_backend : public Backend
   global_variable_set_init(Bvariable*, Bexpression*);
 
   Bvariable*
-  local_variable(Bfunction*, const std::string& name, Btype* type,
+  local_variable(Bfunction*, const std::string&, Btype*, bool,
                 source_location);
 
   Bvariable*
-  parameter_variable(Bfunction*, const std::string& name, Btype* type,
+  parameter_variable(Bfunction*, const std::string&, Btype*, bool,
                     source_location);
 
   Bvariable*
@@ -1074,7 +1074,8 @@ Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr)
 
 Bvariable*
 Gcc_backend::local_variable(Bfunction* function, const std::string& name,
-                           Btype* btype, source_location location)
+                           Btype* btype, bool is_address_taken,
+                           source_location location)
 {
   tree type_tree = btype->get_tree();
   if (type_tree == error_mark_node)
@@ -1084,6 +1085,8 @@ Gcc_backend::local_variable(Bfunction* function, const std::string& name,
                         type_tree);
   DECL_CONTEXT(decl) = function->get_tree();
   TREE_USED(decl) = 1;
+  if (is_address_taken)
+    TREE_ADDRESSABLE(decl) = 1;
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
@@ -1092,7 +1095,8 @@ Gcc_backend::local_variable(Bfunction* function, const std::string& name,
 
 Bvariable*
 Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
-                               Btype* btype, source_location location)
+                               Btype* btype, bool is_address_taken,
+                               source_location location)
 {
   tree type_tree = btype->get_tree();
   if (type_tree == error_mark_node)
@@ -1103,6 +1107,8 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
   DECL_CONTEXT(decl) = function->get_tree();
   DECL_ARG_TYPE(decl) = type_tree;
   TREE_USED(decl) = 1;
+  if (is_address_taken)
+    TREE_ADDRESSABLE(decl) = 1;
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
index d3154c59628c24779618151f6caa914a1d3a8cb7..fa158be5ad141cc8d043ee2eccab376b735261a5 100644 (file)
@@ -317,19 +317,23 @@ class Backend
   // Create a local variable.  The frontend will create the local
   // variables first, and then create the block which contains them.
   // FUNCTION is the function in which the variable is defined.  NAME
-  // is the name of the variable.  TYPE is the type.  LOCATION is
-  // where the variable is defined.  For each local variable the
-  // frontend will call init_statement to set the initial value.
+  // is the name of the variable.  TYPE is the type.  IS_ADDRESS_TAKEN
+  // is true if the address of this variable is taken (this implies
+  // that the address does not escape the function, as otherwise the
+  // variable would be on the heap).  LOCATION is where the variable
+  // is defined.  For each local variable the frontend will call
+  // init_statement to set the initial value.
   virtual Bvariable*
   local_variable(Bfunction* function, const std::string& name, Btype* type,
-                source_location location) = 0;
+                bool is_address_taken, source_location location) = 0;
 
   // Create a function parameter.  This is an incoming parameter, not
   // a result parameter (result parameters are treated as local
   // variables).  The arguments are as for local_variable.
   virtual Bvariable*
   parameter_variable(Bfunction* function, const std::string& name,
-                    Btype* type, source_location location) = 0;
+                    Btype* type, bool is_address_taken,
+                    source_location location) = 0;
 
   // Create a temporary variable.  A temporary variable has no name,
   // just a type.  We pass in FUNCTION and BLOCK in case they are
index c7b8ca0d41104742f46baafb410081be9e5b3f3d..10618759af44cf39f4beb2bb43d7315189104fb7 100644 (file)
@@ -958,13 +958,23 @@ void
 Var_expression::do_address_taken(bool escapes)
 {
   if (!escapes)
-    ;
-  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();
+    {
+      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
-    go_unreachable();
+    {
+      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();
+    }
 }
 
 // Get the tree for a reference to a variable.
index 7d1dd70a48cbbc91c9fd706275299776afe471c8..c7b847fb4d1ab2002a942194ac2a241ee691c8d7 100644 (file)
@@ -3333,10 +3333,11 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
   : type_(type), init_(init), preinit_(NULL), location_(location),
     backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
     is_receiver_(is_receiver), is_varargs_parameter_(false),
-    is_address_taken_(false), seen_(false), init_is_lowered_(false),
-    type_from_init_tuple_(false), type_from_range_index_(false),
-    type_from_range_value_(false), type_from_chan_element_(false),
-    is_type_switch_var_(false), determined_type_(false)
+    is_address_taken_(false), is_non_escaping_address_taken_(false),
+    seen_(false), init_is_lowered_(false), type_from_init_tuple_(false),
+    type_from_range_index_(false), type_from_range_value_(false),
+    type_from_chan_element_(false), is_type_switch_var_(false),
+    determined_type_(false)
 {
   go_assert(type != NULL || init != NULL);
   go_assert(!is_parameter || init == NULL);
@@ -3722,11 +3723,15 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
            {
              tree fndecl = function->func_value()->get_decl();
              Bfunction* bfunction = tree_to_function(fndecl);
+             bool is_address_taken = (this->is_non_escaping_address_taken_
+                                      && !this->is_in_heap());
              if (is_parameter)
                bvar = backend->parameter_variable(bfunction, n, btype,
+                                                  is_address_taken,
                                                   this->location_);
              else
                bvar = backend->local_variable(bfunction, n, btype,
+                                              is_address_taken,
                                               this->location_);
            }
          this->backend_ = bvar;
@@ -3757,7 +3762,10 @@ Result_variable::get_backend_variable(Gogo* gogo, Named_object* function,
          tree fndecl = function->func_value()->get_decl();
          Bfunction* bfunction = tree_to_function(fndecl);
          std::string n = Gogo::unpack_hidden_name(name);
+         bool is_address_taken = (this->is_non_escaping_address_taken_
+                                  && !this->is_in_heap());
          this->backend_ = backend->local_variable(bfunction, n, btype,
+                                                  is_address_taken,
                                                   this->location_);
        }
     }
index 0c524f029fccf82058fa2281e354063f5e4109f8..ed9d1eb76f111cad2d4bde8f87ee2bcb3496445d 100644 (file)
@@ -1160,6 +1160,22 @@ class Variable
   is_in_heap() const
   { return this->is_address_taken_ && !this->is_global_; }
 
+  // Note that something takes the address of this variable.
+  void
+  set_address_taken()
+  { this->is_address_taken_ = true; }
+
+  // Return whether the address is taken but does not escape.
+  bool
+  is_non_escaping_address_taken() const
+  { return this->is_non_escaping_address_taken_; }
+
+  // Note that something takes the address of this variable such that
+  // the address does not escape the function.
+  void
+  set_non_escaping_address_taken()
+  { this->is_non_escaping_address_taken_ = true; }
+
   // Get the source location of the variable's declaration.
   source_location
   location() const
@@ -1252,11 +1268,6 @@ class Variable
   void
   determine_type();
 
-  // Note that something takes the address of this variable.
-  void
-  set_address_taken()
-  { this->is_address_taken_ = true; }
-
   // Get the backend representation of the variable.
   Bvariable*
   get_backend_variable(Gogo*, Named_object*, const Package*,
@@ -1314,8 +1325,13 @@ class Variable
   bool is_receiver_ : 1;
   // Whether this is the varargs parameter of a function.
   bool is_varargs_parameter_ : 1;
-  // Whether something takes the address of this variable.
+  // Whether something takes the address of this variable.  For a
+  // local variable this implies that the variable has to be on the
+  // heap.
   bool is_address_taken_ : 1;
+  // Whether something takes the address of this variable such that
+  // the address does not escape the function.
+  bool is_non_escaping_address_taken_ : 1;
   // True if we have seen this variable in a traversal.
   bool seen_ : 1;
   // True if we have lowered the initialization expression.
@@ -1343,7 +1359,8 @@ class Result_variable
   Result_variable(Type* type, Function* function, int index,
                  source_location location)
     : type_(type), function_(function), index_(index), location_(location),
-      backend_(NULL), is_address_taken_(false)
+      backend_(NULL), is_address_taken_(false),
+      is_non_escaping_address_taken_(false)
   { }
 
   // Get the type of the result variable.
@@ -1376,6 +1393,17 @@ class Result_variable
   set_address_taken()
   { this->is_address_taken_ = true; }
 
+  // Return whether the address is taken but does not escape.
+  bool
+  is_non_escaping_address_taken() const
+  { return this->is_non_escaping_address_taken_; }
+
+  // Note that something takes the address of this variable such that
+  // the address does not escape the function.
+  void
+  set_non_escaping_address_taken()
+  { this->is_non_escaping_address_taken_ = true; }
+
   // Whether this variable should live in the heap.
   bool
   is_in_heap() const
@@ -1404,6 +1432,9 @@ class Result_variable
   Bvariable* backend_;
   // Whether something takes the address of this variable.
   bool is_address_taken_;
+  // Whether something takes the address of this variable such that
+  // the address does not escape the function.
+  bool is_non_escaping_address_taken_;
 };
 
 // The value we keep for a named constant.  This lets us hold a type