aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2011-05-12 18:35:05 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-05-12 18:35:05 +0000
commitacf98146054a121b1da2d76d76bc2c77e03dd301 (patch)
tree82ff0959989caa861c84bff4e6205b529671db90 /gcc/go
parent1d15f620aa4e68f6298491d52ca8cc8d496457a6 (diff)
downloadgcc-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/ChangeLog6
-rw-r--r--gcc/go/go-gcc.cc14
-rw-r--r--gcc/go/gofrontend/backend.h14
-rw-r--r--gcc/go/gofrontend/expressions.cc22
-rw-r--r--gcc/go/gofrontend/gogo.cc16
-rw-r--r--gcc/go/gofrontend/gogo.h45
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