OSDN Git Service

Rewrite conversion of named types to backend representation.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / gogo.cc
index 9e51b63..bb2fcab 100644 (file)
@@ -19,7 +19,7 @@
 
 // Class Gogo.
 
-Gogo::Gogo(int int_type_size, int float_type_size, int pointer_size)
+Gogo::Gogo(int int_type_size, int pointer_size)
   : package_(NULL),
     functions_(),
     globals_(new Bindings(NULL)),
@@ -33,7 +33,9 @@ Gogo::Gogo(int int_type_size, int float_type_size, int pointer_size)
     init_fn_name_(),
     imported_init_fns_(),
     unique_prefix_(),
-    interface_types_()
+    unique_prefix_specified_(false),
+    interface_types_(),
+    named_types_are_converted_(false)
 {
   const source_location loc = BUILTINS_LOCATION;
 
@@ -86,12 +88,6 @@ Gogo::Gogo(int int_type_size, int float_type_size, int pointer_size)
                                               pointer_size,
                                               RUNTIME_TYPE_KIND_UINTPTR));
 
-  this->add_named_type(Type::make_float_type("float", float_type_size,
-                                            RUNTIME_TYPE_KIND_FLOAT));
-
-  this->add_named_type(Type::make_complex_type("complex", float_type_size * 2,
-                                              RUNTIME_TYPE_KIND_COMPLEX));
-
   this->add_named_type(Type::make_named_bool_type());
 
   this->add_named_type(Type::make_named_string_type());
@@ -199,10 +195,10 @@ Gogo::Gogo(int int_type_size, int float_type_size, int pointer_size)
   append_type->set_is_builtin();
   this->globals_->add_function_declaration("append", NULL, append_type, loc);
 
-  Function_type* cmplx_type = Type::make_function_type(NULL, NULL, NULL, loc);
-  cmplx_type->set_is_varargs();
-  cmplx_type->set_is_builtin();
-  this->globals_->add_function_declaration("cmplx", NULL, cmplx_type, loc);
+  Function_type* complex_type = Type::make_function_type(NULL, NULL, NULL, loc);
+  complex_type->set_is_varargs();
+  complex_type->set_is_builtin();
+  this->globals_->add_function_declaration("complex", NULL, complex_type, loc);
 
   Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc);
   real_type->set_is_varargs();
@@ -212,7 +208,7 @@ Gogo::Gogo(int int_type_size, int float_type_size, int pointer_size)
   Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc);
   imag_type->set_is_varargs();
   imag_type->set_is_builtin();
-  this->globals_->add_function_declaration("imag", NULL, cmplx_type, loc);
+  this->globals_->add_function_declaration("imag", NULL, imag_type, loc);
 
   this->define_builtin_function_trees();
 
@@ -265,7 +261,7 @@ Gogo::set_package_name(const std::string& package_name,
   // package name (e.g., P.x), but we no longer do.
   // this->globals_->add_package(package_name, this->package_);
 
-  if (package_name == "main")
+  if (this->is_main_package())
     {
       // Declare "main" as a function which takes no parameters and
       // returns no value.
@@ -276,6 +272,15 @@ Gogo::set_package_name(const std::string& package_name,
     }
 }
 
+// Return whether this is the "main" package.  This is not true if
+// -fgo-prefix was used.
+
+bool
+Gogo::is_main_package() const
+{
+  return this->package_name() == "main" && !this->unique_prefix_specified_;
+}
+
 // Import a package.
 
 void
@@ -330,8 +335,17 @@ Gogo::import_package(const std::string& filename,
   Import imp(stream, location);
   imp.register_builtin_types(this);
   Package* package = imp.import(this, local_name, is_local_name_exported);
-  this->imports_.insert(std::make_pair(filename, package));
-  package->set_is_imported();
+  if (package != NULL)
+    {
+      if (package->name() == this->package_name()
+         && package->unique_prefix() == this->unique_prefix())
+       error_at(location,
+                ("imported package uses same package name and prefix "
+                 "as package being compiled (see -fgo-prefix option)"));
+
+      this->imports_.insert(std::make_pair(filename, package));
+      package->set_is_imported();
+    }
 
   delete stream;
 }
@@ -669,10 +683,15 @@ Gogo::start_function(const std::string& name, Function_type* type,
   else if (!type->is_method())
     {
       ret = this->package_->bindings()->add_function(*pname, NULL, function);
-      if (!ret->is_function())
+      if (!ret->is_function() || ret->func_value() != function)
        {
-         // Redefinition error.
-         ret = Named_object::make_function(name, NULL, function);
+         // Redefinition error.  Invent a name to avoid knockon
+         // errors.
+         static int redefinition_count;
+         char buf[30];
+         snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
+         ++redefinition_count;
+         ret = this->package_->bindings()->add_function(buf, NULL, function);
        }
     }
   else
@@ -1101,11 +1120,6 @@ class Verify_types : public Traverse
 int
 Verify_types::type(Type* t)
 {
-  // Don't verify types defined in other packages.
-  Named_type* nt = t->named_type();
-  if (nt != NULL && nt->named_object()->package() != NULL)
-    return TRAVERSE_SKIP_COMPONENTS;
-
   if (!t->verify())
     return TRAVERSE_SKIP_COMPONENTS;
   return TRAVERSE_CONTINUE;
@@ -1126,7 +1140,8 @@ class Lower_parse_tree : public Traverse
 {
  public:
   Lower_parse_tree(Gogo* gogo, Named_object* function)
-    : Traverse(traverse_constants
+    : Traverse(traverse_variables
+              | traverse_constants
               | traverse_functions
               | traverse_statements
               | traverse_expressions),
@@ -1134,6 +1149,9 @@ class Lower_parse_tree : public Traverse
   { }
 
   int
+  variable(Named_object*);
+
+  int
   constant(Named_object*, bool);
 
   int
@@ -1154,6 +1172,18 @@ class Lower_parse_tree : public Traverse
   int iota_value_;
 };
 
+// Lower variables.  We handle variables specially to break loops in
+// which a variable initialization expression refers to itself.  The
+// loop breaking is in lower_init_expression.
+
+int
+Lower_parse_tree::variable(Named_object* no)
+{
+  if (no->is_variable())
+    no->var_value()->lower_init_expression(this->gogo_, this->function_);
+  return TRAVERSE_CONTINUE;
+}
+
 // Lower constants.  We handle constants specially so that we can set
 // the right value for the predeclared constant iota.  This works in
 // conjunction with the way we lower Const_expression objects.
@@ -1386,8 +1416,6 @@ Gogo::determine_types()
          // 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)
@@ -1595,9 +1623,10 @@ Find_shortcut::expression(Expression** pexpr)
 class Shortcuts : public Traverse
 {
  public:
-  Shortcuts()
+  Shortcuts(Gogo* gogo)
     : Traverse(traverse_variables
-              | traverse_statements)
+              | traverse_statements),
+      gogo_(gogo)
   { }
 
  protected:
@@ -1611,6 +1640,9 @@ class Shortcuts : public Traverse
   // Convert a shortcut operator.
   Statement*
   convert_shortcut(Block* enclosing, Expression** pshortcut);
+
+  // The IR.
+  Gogo* gogo_;
 };
 
 // Remove shortcut operators in a single statement.
@@ -1678,7 +1710,7 @@ Shortcuts::variable(Named_object* no)
        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);
     }
@@ -1721,7 +1753,7 @@ Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut)
   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);
@@ -1733,7 +1765,7 @@ Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut)
 void
 Gogo::remove_shortcuts()
 {
-  Shortcuts shortcuts;
+  Shortcuts shortcuts(this);
   this->traverse(&shortcuts);
 }
 
@@ -1803,9 +1835,10 @@ Find_eval_ordering::expression(Expression** expression_pointer)
 class Order_eval : public Traverse
 {
  public:
-  Order_eval()
+  Order_eval(Gogo* gogo)
     : Traverse(traverse_variables
-              | traverse_statements)
+              | traverse_statements),
+      gogo_(gogo)
   { }
 
   int
@@ -1813,6 +1846,10 @@ class Order_eval : public Traverse
 
   int
   statement(Block*, size_t*, Statement*);
+
+ private:
+  // The IR.
+  Gogo* gogo_;
 };
 
 // Implement the order of evaluation rules for a statement.
@@ -1933,7 +1970,7 @@ Order_eval::variable(Named_object* no)
       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);
     }
 
@@ -1945,7 +1982,7 @@ Order_eval::variable(Named_object* no)
 void
 Gogo::order_evaluations()
 {
-  Order_eval order_eval;
+  Order_eval order_eval(this);
   this->traverse(&order_eval);
 }
 
@@ -2062,7 +2099,7 @@ Build_recover_thunks::function(Named_object* orig_no)
       for (Typed_identifier_list::const_iterator p = orig_results->begin();
           p != orig_results->end();
           ++p)
-       new_results->push_back(*p);
+       new_results->push_back(Typed_identifier("", p->type(), p->location()));
     }
 
   Function_type *new_fntype = Type::make_function_type(NULL, new_params,
@@ -2120,7 +2157,7 @@ Build_recover_thunks::function(Named_object* orig_no)
     }
   args->push_back(this->can_recover_arg(location));
 
-  Expression* call = Expression::make_call(fn, args, false, location);
+  Call_expression* call = Expression::make_call(fn, args, false, location);
 
   Statement* s;
   if (orig_fntype->results() == NULL || orig_fntype->results()->empty())
@@ -2128,7 +2165,14 @@ Build_recover_thunks::function(Named_object* orig_no)
   else
     {
       Expression_list* vals = new Expression_list();
-      vals->push_back(call);
+      size_t rc = orig_fntype->results()->size();
+      if (rc == 1)
+       vals->push_back(call);
+      else
+       {
+         for (size_t i = 0; i < rc; ++i)
+           vals->push_back(Expression::make_call_result(call, i));
+       }
       s = Statement::make_return_statement(new_func->type()->results(),
                                           vals, location);
     }
@@ -2157,10 +2201,14 @@ Build_recover_thunks::function(Named_object* orig_no)
 
       const std::string& new_receiver_name(orig_fntype->receiver()->name());
       Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name);
-      gcc_assert(new_rec_no != NULL
-                && new_rec_no->is_variable()
-                && new_rec_no->var_value()->is_receiver());
-      new_rec_no->var_value()->set_is_not_receiver();
+      if (new_rec_no == NULL)
+       gcc_assert(saw_errors());
+      else
+       {
+         gcc_assert(new_rec_no->is_variable()
+                    && new_rec_no->var_value()->is_receiver());
+         new_rec_no->var_value()->set_is_not_receiver();
+       }
     }
 
   // Because we flipped blocks but not types, the can_recover
@@ -2429,6 +2477,7 @@ Gogo::set_unique_prefix(const std::string& arg)
 {
   gcc_assert(this->unique_prefix_.empty());
   this->unique_prefix_ = arg;
+  this->unique_prefix_specified_ = true;
 }
 
 // Work out the package priority.  It is one more than the maximum
@@ -2460,13 +2509,90 @@ Gogo::do_exports()
   exp.export_globals(this->package_name(),
                     this->unique_prefix(),
                     this->package_priority(),
-                    (this->need_init_fn_ && this->package_name() != "main"
+                    (this->need_init_fn_ && !this->is_main_package()
                      ? this->get_init_fn_name()
                      : ""),
                     this->imported_init_fns_,
                     this->package_->bindings());
 }
 
+// Find the blocks in order to convert named types defined in blocks.
+
+class Convert_named_types : public Traverse
+{
+ public:
+  Convert_named_types(Gogo* gogo)
+    : Traverse(traverse_blocks),
+      gogo_(gogo)
+  { }
+
+ protected:
+  int
+  block(Block* block);
+
+ private:
+  Gogo* gogo_;
+};
+
+int
+Convert_named_types::block(Block* block)
+{
+  this->gogo_->convert_named_types_in_bindings(block->bindings());
+  return TRAVERSE_CONTINUE;
+}
+
+// Convert all named types to the backend representation.  Since named
+// types can refer to other types, this needs to be done in the right
+// sequence, which is handled by Named_type::convert.  Here we arrange
+// to call that for each named type.
+
+void
+Gogo::convert_named_types()
+{
+  this->convert_named_types_in_bindings(this->globals_);
+  for (Packages::iterator p = this->packages_.begin();
+       p != this->packages_.end();
+       ++p)
+    {
+      Package* package = p->second;
+      this->convert_named_types_in_bindings(package->bindings());
+    }
+
+  Convert_named_types cnt(this);
+  this->traverse(&cnt);
+
+  // Make all the builtin named types used for type descriptors, and
+  // then convert them.  They will only be written out if they are
+  // needed.
+  Type::make_type_descriptor_type();
+  Type::make_type_descriptor_ptr_type();
+  Function_type::make_function_type_descriptor_type();
+  Pointer_type::make_pointer_type_descriptor_type();
+  Struct_type::make_struct_type_descriptor_type();
+  Array_type::make_array_type_descriptor_type();
+  Array_type::make_slice_type_descriptor_type();
+  Map_type::make_map_type_descriptor_type();
+  Channel_type::make_chan_type_descriptor_type();
+  Interface_type::make_interface_type_descriptor_type();
+  Type::convert_builtin_named_types(this);
+
+  this->named_types_are_converted_ = true;
+}
+
+// Convert all names types in a set of bindings.
+
+void
+Gogo::convert_named_types_in_bindings(Bindings* bindings)
+{
+  for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+       p != bindings->end_definitions();
+       ++p)
+    {
+      if ((*p)->is_type())
+       (*p)->type_value()->convert(this);
+    }
+}
+
 // Class Function.
 
 Function::Function(Function_type* type, Function* enclosing, Block* block,
@@ -2509,7 +2635,8 @@ Function::create_named_result_variables(Gogo* gogo)
        }
       Result_variable* result = new Result_variable(p->type(), this, index);
       Named_object* no = block->bindings()->add_result_variable(name, result);
-      this->named_results_->push_back(no);
+      if (no->is_result_variable())
+       this->named_results_->push_back(no);
     }
 }
 
@@ -3139,20 +3266,25 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
 // 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());
 }
@@ -3324,6 +3456,9 @@ Variable::type() const
 void
 Variable::determine_type()
 {
+  if (this->preinit_ != NULL)
+    this->preinit_->determine_types();
+
   // A variable in a type switch with a nil case will have the wrong
   // type here.  It will have an initializer which is a type guard.
   // We want to initialize it to the value without the type guard, and
@@ -4149,9 +4284,6 @@ Bindings::traverse(Traverse* traverse, bool is_global)
              if (t != NULL
                  && Type::traverse(t, traverse) == TRAVERSE_EXIT)
                return TRAVERSE_EXIT;
-           }
-         if ((traverse_mask & Traverse::traverse_expressions) != 0)
-           {
              if (p->const_value()->traverse_expression(traverse)
                  == TRAVERSE_EXIT)
                return TRAVERSE_EXIT;
@@ -4178,7 +4310,8 @@ Bindings::traverse(Traverse* traverse, bool is_global)
                return TRAVERSE_EXIT;
            }
          if (p->is_variable()
-             && (traverse_mask & Traverse::traverse_expressions) != 0)
+             && ((traverse_mask & Traverse::traverse_types) != 0
+                 || (traverse_mask & Traverse::traverse_expressions) != 0))
            {
              if (p->var_value()->traverse_expression(traverse)
                  == TRAVERSE_EXIT)