diff options
author | Ian Lance Taylor <iant@google.com> | 2011-05-12 18:35:05 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-05-12 18:35:05 +0000 |
commit | acf98146054a121b1da2d76d76bc2c77e03dd301 (patch) | |
tree | 82ff0959989caa861c84bff4e6205b529671db90 /gcc/go | |
parent | 1d15f620aa4e68f6298491d52ca8cc8d496457a6 (diff) | |
download | gcc-acf98146054a121b1da2d76d76bc2c77e03dd301.zip gcc-acf98146054a121b1da2d76d76bc2c77e03dd301.tar.gz gcc-acf98146054a121b1da2d76d76bc2c77e03dd301.tar.bz2 |
Fix bug with taking address of a variable when address does not escape.
* go-gcc.cc (Gcc_backend::local_variable): Add is_address_taken
parameter.
(Gcc_backend::parameter_variable): Likewise.
From-SVN: r173712
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 14 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 14 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 22 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 16 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 45 |
6 files changed, 91 insertions, 26 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 4136702..63a47c1 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -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. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index f5a6fb5..49f574a 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -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); } diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index d3154c5..fa158be 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -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 diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index c7b8ca0..1061875 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 7d1dd70..c7b847f 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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_); } } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 0c524f0..ed9d1eb 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -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 |