This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]