aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-05-03 16:09:25 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-05-03 16:09:25 +0000
commit29f31724efd80a8f337946238487a392ac37675b (patch)
treee30052c2b86730e52e97177bfe987b98a830a055 /gcc/go/gofrontend
parent0fe5522f8b18c88338bf33765ab0bf85580eb75c (diff)
downloadgcc-29f31724efd80a8f337946238487a392ac37675b.zip
gcc-29f31724efd80a8f337946238487a392ac37675b.tar.gz
gcc-29f31724efd80a8f337946238487a392ac37675b.tar.bz2
compiler: Fix order of initialization bug with global var a, b = f().
From-SVN: r187103
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc54
-rw-r--r--gcc/go/gofrontend/gogo.cc5
-rw-r--r--gcc/go/gofrontend/gogo.h26
-rw-r--r--gcc/go/gofrontend/parse.cc18
4 files changed, 85 insertions, 18 deletions
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index 7f73238..9dea885 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -590,10 +590,11 @@ Find_var::expression(Expression** pexpr)
return TRAVERSE_CONTINUE;
}
-// Return true if EXPR refers to VAR.
+// Return true if EXPR, PREINIT, or DEP refers to VAR.
static bool
-expression_requires(Expression* expr, Block* preinit, Named_object* var)
+expression_requires(Expression* expr, Block* preinit, Named_object* dep,
+ Named_object* var)
{
Find_var::Seen_objects seen_objects;
Find_var find_var(var, &seen_objects);
@@ -601,7 +602,15 @@ expression_requires(Expression* expr, Block* preinit, Named_object* var)
Expression::traverse(&expr, &find_var);
if (preinit != NULL)
preinit->traverse(&find_var);
-
+ if (dep != NULL)
+ {
+ Expression* init = dep->var_value()->init();
+ if (init != NULL)
+ Expression::traverse(&init, &find_var);
+ if (dep->var_value()->has_pre_init())
+ dep->var_value()->preinit()->traverse(&find_var);
+ }
+
return find_var.found();
}
@@ -658,7 +667,7 @@ typedef std::list<Var_init> Var_inits;
// variable V2 then we initialize V1 after V2.
static void
-sort_var_inits(Var_inits* var_inits)
+sort_var_inits(Gogo* gogo, Var_inits* var_inits)
{
Var_inits ready;
while (!var_inits->empty())
@@ -667,6 +676,7 @@ sort_var_inits(Var_inits* var_inits)
Named_object* var = p1->var();
Expression* init = var->var_value()->init();
Block* preinit = var->var_value()->preinit();
+ Named_object* dep = gogo->var_depends_on(var->var_value());
// Start walking through the list to see which variables VAR
// needs to wait for. We can skip P1->WAITING variables--that
@@ -678,20 +688,22 @@ sort_var_inits(Var_inits* var_inits)
for (; p2 != var_inits->end(); ++p2)
{
- if (expression_requires(init, preinit, p2->var()))
+ Named_object* p2var = p2->var();
+ if (expression_requires(init, preinit, dep, p2var))
{
// Check for cycles.
- if (expression_requires(p2->var()->var_value()->init(),
- p2->var()->var_value()->preinit(),
+ if (expression_requires(p2var->var_value()->init(),
+ p2var->var_value()->preinit(),
+ gogo->var_depends_on(p2var->var_value()),
var))
{
error_at(var->location(),
("initialization expressions for %qs and "
"%qs depend upon each other"),
var->message_name().c_str(),
- p2->var()->message_name().c_str());
+ p2var->message_name().c_str());
inform(p2->var()->location(), "%qs defined here",
- p2->var()->message_name().c_str());
+ p2var->message_name().c_str());
p2 = var_inits->end();
}
else
@@ -714,9 +726,11 @@ sort_var_inits(Var_inits* var_inits)
// VAR does not depends upon any other initialization expressions.
// Check for a loop of VAR on itself. We only do this if
- // INIT is not NULL; when INIT is NULL, it means that
- // PREINIT sets VAR, which we will interpret as a loop.
- if (init != NULL && expression_requires(init, preinit, var))
+ // INIT is not NULL and there is no dependency; when INIT is
+ // NULL, it means that PREINIT sets VAR, which we will
+ // interpret as a loop.
+ if (init != NULL && dep == NULL
+ && expression_requires(init, preinit, NULL, var))
error_at(var->location(),
"initialization expression for %qs depends upon itself",
var->message_name().c_str());
@@ -783,7 +797,7 @@ Gogo::write_globals()
}
// There is nothing useful we can output for constants which
- // have ideal or non-integeral type.
+ // have ideal or non-integral type.
if (no->is_const())
{
Type* type = no->const_value()->type();
@@ -834,7 +848,9 @@ Gogo::write_globals()
;
else if (TREE_CONSTANT(init))
{
- if (expression_requires(no->var_value()->init(), NULL, no))
+ if (expression_requires(no->var_value()->init(), NULL,
+ this->var_depends_on(no->var_value()),
+ no))
error_at(no->location(),
"initialization expression for %qs depends "
"upon itself",
@@ -879,6 +895,14 @@ Gogo::write_globals()
else
var_inits.push_back(Var_init(no, var_init_tree));
}
+ else if (this->var_depends_on(no->var_value()) != NULL)
+ {
+ // This variable is initialized from something that is
+ // not in its init or preinit. This variable needs to
+ // participate in dependency analysis sorting, in case
+ // some other variable depends on this one.
+ var_inits.push_back(Var_init(no, integer_zero_node));
+ }
if (!is_sink && no->var_value()->type()->has_pointer())
var_gc.push_back(no);
@@ -896,7 +920,7 @@ Gogo::write_globals()
// workable order.
if (!var_inits.empty())
{
- sort_var_inits(&var_inits);
+ sort_var_inits(this, &var_inits);
for (Var_inits::const_iterator p = var_inits.begin();
p != var_inits.end();
++p)
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 7bc0b55..15c814b 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -32,6 +32,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
imported_unsafe_(false),
packages_(),
init_functions_(),
+ var_deps_(),
need_init_fn_(false),
init_fn_name_(),
imported_init_fns_(),
@@ -3820,6 +3821,10 @@ void
Variable::lower_init_expression(Gogo* gogo, Named_object* function,
Statement_inserter* inserter)
{
+ Named_object* dep = gogo->var_depends_on(this);
+ if (dep != NULL && dep->is_variable())
+ dep->var_value()->lower_init_expression(gogo, function, inserter);
+
if (this->init_ != NULL && !this->init_is_lowered_)
{
if (this->seen_)
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 9c5f8cb..4990bf2 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -384,6 +384,23 @@ class Gogo
void
clear_file_scope();
+ // Record that VAR1 must be initialized after VAR2. This is used
+ // when VAR2 does not appear in VAR1's INIT or PREINIT.
+ void
+ record_var_depends_on(Variable* var1, Named_object* var2)
+ {
+ go_assert(this->var_deps_.find(var1) == this->var_deps_.end());
+ this->var_deps_[var1] = var2;
+ }
+
+ // Return the variable that VAR depends on, or NULL if none.
+ Named_object*
+ var_depends_on(Variable* var) const
+ {
+ Var_deps::const_iterator p = this->var_deps_.find(var);
+ return p != this->var_deps_.end() ? p->second : NULL;
+ }
+
// Queue up a type-specific function to be written out. This is
// used when a type-specific function is needed when not at the top
// level.
@@ -639,8 +656,9 @@ class Gogo
// Type used to map package names to packages.
typedef std::map<std::string, Package*> Packages;
- // Type used to map special names in the sys package.
- typedef std::map<std::string, std::string> Sys_names;
+ // Type used to map variables to the function calls that set them.
+ // This is used for initialization dependency analysis.
+ typedef std::map<Variable*, Named_object*> Var_deps;
// Type used to queue writing a type specific function.
struct Specific_type_function
@@ -683,6 +701,10 @@ class Gogo
Packages packages_;
// The functions named "init", if there are any.
std::vector<Named_object*> init_functions_;
+ // A mapping from variables to the function calls that initialize
+ // them, if it is not stored in the variable's init or preinit.
+ // This is used for dependency analysis.
+ Var_deps var_deps_;
// Whether we need a magic initialization function.
bool need_init_fn_;
// The name of the magic initialization function.
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 7a567a1..6567a42 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -1667,6 +1667,7 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
// the right number of values, but it might. Declare the variables,
// and then assign the results of the call to them.
+ Named_object* first_var = NULL;
unsigned int index = 0;
bool any_new = false;
for (Typed_identifier_list::const_iterator pv = vars->begin();
@@ -1674,7 +1675,22 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
++pv, ++index)
{
Expression* init = Expression::make_call_result(call, index);
- this->init_var(*pv, type, init, is_coloneq, false, &any_new);
+ Named_object* no = this->init_var(*pv, type, init, is_coloneq, false,
+ &any_new);
+
+ if (this->gogo_->in_global_scope() && no->is_variable())
+ {
+ if (first_var == NULL)
+ first_var = no;
+ else
+ {
+ // The subsequent vars have an implicit dependency on
+ // the first one, so that everything gets initialized in
+ // the right order and so that we detect cycles
+ // correctly.
+ this->gogo_->record_var_depends_on(no->var_value(), first_var);
+ }
+ }
}
if (is_coloneq && !any_new)