From: Ian Lance Taylor Date: Thu, 12 May 2011 18:35:05 +0000 (+0000) Subject: Fix bug with taking address of a variable when address does not escape. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=acf98146054a121b1da2d76d76bc2c77e03dd301;p=gcc.git 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 --- diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 4136702481b..63a47c1efcd 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,9 @@ +2011-05-12 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::local_variable): Add is_address_taken + parameter. + (Gcc_backend::parameter_variable): Likewise. + 2011-05-07 Eric Botcazou * 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 f5a6fb579ac..49f574a58fd 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 d3154c59628..fa158be5ad1 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 c7b8ca0d411..10618759af4 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 7d1dd70a48c..c7b847fb4d1 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 0c524f029fc..ed9d1eb76f1 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