This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Go patch committed: Generate preinit when needed
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org, gofrontend-dev at googlegroups dot com
- Date: Wed, 19 Jan 2011 12:37:53 -0800
- Subject: Go patch committed: Generate preinit when needed
This patch to the Go frontend fixes the compiler to ensure that an
initialization function is generated whenever a global variable has a
preinit statement. This can happen for something like
var a = f() + g() + h()
in order to enforce the order of evaluation rules. Bootstrapped and ran
Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r a6cd766cbad0 go/gogo.cc
--- a/go/gogo.cc Wed Jan 19 08:54:20 2011 -0800
+++ b/go/gogo.cc Wed Jan 19 12:34:07 2011 -0800
@@ -1395,8 +1395,6 @@
// initialization, we need an initialization function.
if (!variable->is_global())
;
- else if (variable->has_pre_init())
- this->need_init_fn_ = true;
else if (variable->init() == NULL)
;
else if (variable->type()->interface_type() != NULL)
@@ -1604,9 +1602,10 @@
class Shortcuts : public Traverse
{
public:
- Shortcuts()
+ Shortcuts(Gogo* gogo)
: Traverse(traverse_variables
- | traverse_statements)
+ | traverse_statements),
+ gogo_(gogo)
{ }
protected:
@@ -1620,6 +1619,9 @@
// Convert a shortcut operator.
Statement*
convert_shortcut(Block* enclosing, Expression** pshortcut);
+
+ // The IR.
+ Gogo* gogo_;
};
// Remove shortcut operators in a single statement.
@@ -1687,7 +1689,7 @@
return TRAVERSE_CONTINUE;
Statement* snew = this->convert_shortcut(NULL, pshortcut);
- var->add_preinit_statement(snew);
+ var->add_preinit_statement(this->gogo_, snew);
if (pshortcut == &init)
var->set_init(init);
}
@@ -1730,7 +1732,7 @@
delete shortcut;
// Now convert any shortcut operators in LEFT and RIGHT.
- Shortcuts shortcuts;
+ Shortcuts shortcuts(this->gogo_);
retblock->traverse(&shortcuts);
return Statement::make_block_statement(retblock, loc);
@@ -1742,7 +1744,7 @@
void
Gogo::remove_shortcuts()
{
- Shortcuts shortcuts;
+ Shortcuts shortcuts(this);
this->traverse(&shortcuts);
}
@@ -1812,9 +1814,10 @@
class Order_eval : public Traverse
{
public:
- Order_eval()
+ Order_eval(Gogo* gogo)
: Traverse(traverse_variables
- | traverse_statements)
+ | traverse_statements),
+ gogo_(gogo)
{ }
int
@@ -1822,6 +1825,10 @@
int
statement(Block*, size_t*, Statement*);
+
+ private:
+ // The IR.
+ Gogo* gogo_;
};
// Implement the order of evaluation rules for a statement.
@@ -1942,7 +1949,7 @@
Expression** pexpr = *p;
source_location loc = (*pexpr)->location();
Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr, loc);
- var->add_preinit_statement(ts);
+ var->add_preinit_statement(this->gogo_, ts);
*pexpr = Expression::make_temporary_reference(ts, loc);
}
@@ -1954,7 +1961,7 @@
void
Gogo::order_evaluations()
{
- Order_eval order_eval;
+ Order_eval order_eval(this);
this->traverse(&order_eval);
}
@@ -3155,20 +3162,25 @@
// Get the preinit block.
Block*
-Variable::preinit_block()
+Variable::preinit_block(Gogo* gogo)
{
gcc_assert(this->is_global_);
if (this->preinit_ == NULL)
this->preinit_ = new Block(NULL, this->location());
+
+ // If a global variable has a preinitialization statement, then we
+ // need to have an initialization function.
+ gogo->set_need_init_fn();
+
return this->preinit_;
}
// Add a statement to be run before the initialization expression.
void
-Variable::add_preinit_statement(Statement* s)
+Variable::add_preinit_statement(Gogo* gogo, Statement* s)
{
- Block* b = this->preinit_block();
+ Block* b = this->preinit_block(gogo);
b->add_statement(s);
b->set_end_location(s->location());
}
diff -r a6cd766cbad0 go/gogo.h
--- a/go/gogo.h Wed Jan 19 08:54:20 2011 -0800
+++ b/go/gogo.h Wed Jan 19 12:34:07 2011 -0800
@@ -318,6 +318,11 @@
void
record_interface_type(Interface_type*);
+ // Note that we need an initialization function.
+ void
+ set_need_init_fn()
+ { this->need_init_fn_ = true; }
+
// Clear out all names in file scope. This is called when we start
// parsing a new file.
void
@@ -1143,12 +1148,12 @@
// Get the preinit block, a block of statements to be run before the
// initialization expression.
Block*
- preinit_block();
+ preinit_block(Gogo*);
// Add a statement to be run before the initialization expression.
// This is only used for global variables.
void
- add_preinit_statement(Statement*);
+ add_preinit_statement(Gogo*, Statement*);
// Lower the initialization expression after parsing is complete.
void
diff -r a6cd766cbad0 go/parse.cc
--- a/go/parse.cc Wed Jan 19 08:54:20 2011 -0800
+++ b/go/parse.cc Wed Jan 19 12:34:07 2011 -0800
@@ -1657,12 +1657,12 @@
else if (!val_no->is_sink())
{
if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(s);
+ val_no->var_value()->add_preinit_statement(this->gogo_, s);
}
else if (!no->is_sink())
{
if (no->is_variable())
- no->var_value()->add_preinit_statement(s);
+ no->var_value()->add_preinit_statement(this->gogo_, s);
}
else
{
@@ -1670,7 +1670,7 @@
// the map is nil.
Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(),
NULL, location);
- dummy->var_value()->add_preinit_statement(s);
+ dummy->var_value()->add_preinit_statement(this->gogo_, s);
}
return true;
@@ -1724,18 +1724,18 @@
else if (!val_no->is_sink())
{
if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(s);
+ val_no->var_value()->add_preinit_statement(this->gogo_, s);
}
else if (!no->is_sink())
{
if (no->is_variable())
- no->var_value()->add_preinit_statement(s);
+ no->var_value()->add_preinit_statement(this->gogo_, s);
}
else
{
Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(),
NULL, location);
- dummy->var_value()->add_preinit_statement(s);
+ dummy->var_value()->add_preinit_statement(this->gogo_, s);
}
return true;
@@ -1790,17 +1790,17 @@
else if (!val_no->is_sink())
{
if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(s);
+ val_no->var_value()->add_preinit_statement(this->gogo_, s);
}
else if (!no->is_sink())
{
if (no->is_variable())
- no->var_value()->add_preinit_statement(s);
+ no->var_value()->add_preinit_statement(this->gogo_, s);
}
else
{
Named_object* dummy = this->create_dummy_global(type, NULL, location);
- dummy->var_value()->add_preinit_statement(s);
+ dummy->var_value()->add_preinit_statement(this->gogo_, s);
}
return true;