Rewrite conversion of named types to backend representation.
[gcc.git] / gcc / go / gofrontend / gogo-tree.cc
index 67f9949f695b735c0179ad79c0e6cbc974e9611e..722a23a52d70dc8637d609364bbce2142eda9e2f 100644 (file)
@@ -22,7 +22,6 @@ extern "C"
 #include "convert.h"
 #include "output.h"
 #include "diagnostic.h"
-#include "rtl.h"
 
 #ifndef ENABLE_BUILD_WITH_CXX
 }
@@ -162,7 +161,7 @@ Gogo::get_init_fn_name()
   if (this->init_fn_name_.empty())
     {
       gcc_assert(this->package_ != NULL);
-      if (this->package_name() == "main")
+      if (this->is_main_package())
        {
          // Use a name which the runtime knows.
          this->init_fn_name_ = "__go_init_main";
@@ -187,7 +186,7 @@ Gogo::get_init_fn_name()
 void
 Gogo::init_imports(tree* init_stmt_list)
 {
-  gcc_assert(this->package_name() == "main");
+  gcc_assert(this->is_main_package());
 
   if (this->imported_init_fns_.empty())
     return;
@@ -341,7 +340,8 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
                                 void_type_node,
                                 build_pointer_type(root_list_type),
                                 build_fold_addr_expr(decl));
-  append_to_statement_list(call, init_stmt_list);
+  if (call != error_mark_node)
+    append_to_statement_list(call, init_stmt_list);
 }
 
 // Build the decl for the initialization function.
@@ -384,7 +384,7 @@ Gogo::write_initialization_function(tree fndecl, tree init_stmt_list)
 {
   // Make sure that we thought we needed an initialization function,
   // as otherwise we will not have reported it in the export data.
-  gcc_assert(this->package_name() == "main" || this->need_init_fn_);
+  gcc_assert(this->is_main_package() || this->need_init_fn_);
 
   if (fndecl == NULL_TREE)
     fndecl = this->initialization_function_decl();
@@ -640,6 +640,9 @@ sort_var_inits(Var_inits* var_inits)
 void
 Gogo::write_globals()
 {
+  this->convert_named_types();
+  this->build_interface_method_tables();
+
   Bindings* bindings = this->current_bindings();
   size_t count = bindings->size_definitions();
 
@@ -648,7 +651,7 @@ Gogo::write_globals()
   tree init_fndecl = NULL_TREE;
   tree init_stmt_list = NULL_TREE;
 
-  if (this->package_name() == "main")
+  if (this->is_main_package())
     this->init_imports(&init_stmt_list);
 
   // A list of variable initializations.
@@ -756,7 +759,7 @@ Gogo::write_globals()
              pop_cfun();
            }
 
-         if (var_init_tree != NULL_TREE)
+         if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node)
            {
              if (no->var_value()->init() == NULL
                  && !no->var_value()->has_pre_init())
@@ -804,22 +807,11 @@ Gogo::write_globals()
   // This will be called if this package is imported.
   if (init_stmt_list != NULL_TREE
       || this->need_init_fn_
-      || this->package_name() == "main")
+      || this->is_main_package())
     this->write_initialization_function(init_fndecl, init_stmt_list);
 
   // Pass everything back to the middle-end.
 
-  if (this->imported_unsafe_)
-    {
-      // Importing the "unsafe" package automatically disables TBAA.
-      flag_strict_aliasing = false;
-
-      // This is a real hack.  init_varasm_once has already grabbed an
-      // alias set, which we don't want when we aren't going strict
-      // aliasing.  We reinitialize to make it do it again.  FIXME.
-      init_varasm_once();
-    }
-
   wrapup_global_declarations(vec, count);
 
   cgraph_finalize_compilation_unit();
@@ -1208,10 +1200,13 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
 
   Translate_context context(gogo, function, NULL, NULL_TREE);
   tree block_tree = this->preinit_->get_tree(&context);
+  if (block_tree == error_mark_node)
+    return error_mark_node;
   gcc_assert(TREE_CODE(block_tree) == BIND_EXPR);
   tree statements = BIND_EXPR_BODY(block_tree);
-  while (TREE_CODE(statements) == TRY_FINALLY_EXPR
-        || TREE_CODE(statements) == TRY_CATCH_EXPR)
+  while (statements != NULL_TREE
+        && (TREE_CODE(statements) == TRY_FINALLY_EXPR
+            || TREE_CODE(statements) == TRY_CATCH_EXPR))
     statements = TREE_OPERAND(statements, 0);
 
   // It's possible to have pre-init statements without an initializer
@@ -1219,6 +1214,8 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
   if (this->init_ != NULL)
     {
       tree rhs_tree = this->init_->get_tree(&context);
+      if (rhs_tree == error_mark_node)
+       return error_mark_node;
       if (var_decl == NULL_TREE)
        append_to_statement_list(rhs_tree, &statements);
       else
@@ -1227,6 +1224,8 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
                                                        this->init_->type(),
                                                        rhs_tree,
                                                        this->location());
+         if (val == error_mark_node)
+           return error_mark_node;
          tree set = fold_build2_loc(this->location(), MODIFY_EXPR,
                                     void_type_node, var_decl, val);
          append_to_statement_list(set, &statements);
@@ -1256,14 +1255,15 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
 
          this->fndecl_ = decl;
 
-         gcc_assert(no->package() == NULL);
-         if (this->enclosing_ != NULL || Gogo::is_thunk(no))
+         if (no->package() != NULL)
+           ;
+         else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
            ;
          else if (Gogo::unpack_hidden_name(no->name()) == "init"
                   && !this->type_->is_method())
            ;
          else if (Gogo::unpack_hidden_name(no->name()) == "main"
-                  && gogo->package_name() == "main")
+                  && gogo->is_main_package())
            TREE_PUBLIC(decl) = 1;
          // Methods have to be public even if they are hidden because
          // they can be pulled into type descriptors when using
@@ -1684,7 +1684,8 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
                                 void_type_node,
                                 ptr_type_node,
                                 this->defer_stack(end_loc));
-  append_to_statement_list(call, &stmt_list);
+  if (call != error_mark_node)
+    append_to_statement_list(call, &stmt_list);
 
   tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list);
   tree set;
@@ -1723,7 +1724,8 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
                                    void_type_node,
                                    ptr_type_node,
                                    this->defer_stack(end_loc));
-  TREE_NOTHROW(undefer_fndecl) = 0;
+  if (undefer_fndecl != NULL_TREE)
+    TREE_NOTHROW(undefer_fndecl) = 0;
 
   tree defer = Gogo::call_builtin(&check_fndecl,
                                  end_loc,
@@ -2346,6 +2348,8 @@ Gogo::map_descriptor(Map_type* maptype)
   Map_descriptors::iterator p = ins.first;
   if (!ins.second)
     {
+      if (p->second == error_mark_node)
+       return error_mark_node;
       gcc_assert(p->second != NULL_TREE && DECL_P(p->second));
       return build_fold_addr_expr(p->second);
     }
@@ -2375,7 +2379,10 @@ Gogo::map_descriptor(Map_type* maptype)
                                        "__val",
                                        valtype->get_tree(this));
   if (map_entry_type == error_mark_node)
-    return error_mark_node;
+    {
+      p->second = error_mark_node;
+      return error_mark_node;
+    }
 
   tree map_entry_key_field = DECL_CHAIN(TYPE_FIELDS(map_entry_type));
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_key_field)),
@@ -2630,26 +2637,14 @@ Gogo::build_type_descriptor_decl(const Type* type, Expression* initializer,
 
   DECL_INITIAL(decl) = constructor;
 
-  if (type_descriptor_location == TYPE_DESCRIPTOR_COMMON)
+  if (type_descriptor_location == TYPE_DESCRIPTOR_DEFINED)
+    TREE_PUBLIC(decl) = 1;
+  else
     {
+      gcc_assert(type_descriptor_location == TYPE_DESCRIPTOR_COMMON);
       make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
       resolve_unique_section(decl, 1, 0);
     }
-  else
-    {
-#ifdef OBJECT_FORMAT_ELF
-      // Give the decl protected visibility.  This avoids out-of-range
-      // references with shared libraries with the x86_64 small model
-      // when the type descriptor gets a COPY reloc into the main
-      // executable.  There is no need to have unique pointers to type
-      // descriptors, as the runtime code compares reflection strings
-      // if necessary.
-      DECL_VISIBILITY(decl) = VISIBILITY_PROTECTED;
-      DECL_VISIBILITY_SPECIFIED(decl) = 1;
-#endif
-
-      TREE_PUBLIC(decl) = 1;
-    }
 
   rest_of_decl_compilation(decl, 1, 0);
 }
@@ -2761,17 +2756,7 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
   // definition of the table.  Otherwise it is a comdat table which
   // may be defined in multiple packages.
   if (has_hidden_methods)
-    {
-#ifdef OBJECT_FORMAT_ELF
-      // Give the decl protected visibility.  This avoids out-of-range
-      // references with shared libraries with the x86_64 small model
-      // when the table gets a COPY reloc into the main executable.
-      DECL_VISIBILITY(decl) = VISIBILITY_PROTECTED;
-      DECL_VISIBILITY_SPECIFIED(decl) = 1;
-#endif
-
-      TREE_PUBLIC(decl) = 1;
-    }
+    TREE_PUBLIC(decl) = 1;
   else
     {
       make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
@@ -2817,7 +2802,11 @@ Gogo::call_builtin(tree* pdecl, source_location location, const char* name,
       types[i] = va_arg(ap, tree);
       args[i] = va_arg(ap, tree);
       if (types[i] == error_mark_node || args[i] == error_mark_node)
-       return error_mark_node;
+       {
+         delete[] types;
+         delete[] args;
+         return error_mark_node;
+       }
     }
   va_end(ap);
 
@@ -2867,6 +2856,8 @@ Gogo::runtime_error(int code, source_location location)
                                void_type_node,
                                integer_type_node,
                                build_int_cst(integer_type_node, code));
+  if (ret == error_mark_node)
+    return error_mark_node;
   // The runtime error function panics and does not return.
   TREE_NOTHROW(runtime_error_fndecl) = 0;
   TREE_THIS_VOLATILE(runtime_error_fndecl) = 1;
@@ -2883,6 +2874,9 @@ tree
 Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
                      source_location location)
 {
+  if (channel == error_mark_node || val == error_mark_node)
+    return error_mark_node;
+
   if (int_size_in_bytes(TREE_TYPE(val)) <= 8
       && !AGGREGATE_TYPE_P(TREE_TYPE(val))
       && !FLOAT_TYPE_P(TREE_TYPE(val)))
@@ -2904,6 +2898,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
                                        (for_select
                                         ? boolean_true_node
                                         : boolean_false_node));
+         if (ret == error_mark_node)
+           return error_mark_node;
          // This can panic if there are too many operations on a
          // closed channel.
          TREE_NOTHROW(send_small_fndecl) = 0;
@@ -2922,6 +2918,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
                                        channel,
                                        uint64_type_node,
                                        val);
+         if (ret == error_mark_node)
+           return error_mark_node;
          // This can panic if there are too many operations on a
          // closed channel.
          TREE_NOTHROW(send_nonblocking_small_fndecl) = 0;
@@ -2967,6 +2965,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
                                    (for_select
                                     ? boolean_true_node
                                     : boolean_false_node));
+         if (call == error_mark_node)
+           return error_mark_node;
          // This can panic if there are too many operations on a
          // closed channel.
          TREE_NOTHROW(send_big_fndecl) = 0;
@@ -2984,6 +2984,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
                                    channel,
                                    ptr_type_node,
                                    val);
+         if (call == error_mark_node)
+           return error_mark_node;
          // This can panic if there are too many operations on a
          // closed channel.
          TREE_NOTHROW(send_nonblocking_big_fndecl) = 0;
@@ -3009,6 +3011,9 @@ tree
 Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
                           source_location location)
 {
+  if (type_tree == error_mark_node || channel == error_mark_node)
+    return error_mark_node;
+
   if (int_size_in_bytes(type_tree) <= 8
       && !AGGREGATE_TYPE_P(type_tree)
       && !FLOAT_TYPE_P(type_tree))
@@ -3025,6 +3030,8 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
                                     (for_select
                                      ? boolean_true_node
                                      : boolean_false_node));
+      if (call == error_mark_node)
+       return error_mark_node;
       // This can panic if there are too many operations on a closed
       // channel.
       TREE_NOTHROW(receive_small_fndecl) = 0;
@@ -3057,6 +3064,8 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
                                     (for_select
                                      ? boolean_true_node
                                      : boolean_false_node));
+      if (call == error_mark_node)
+       return error_mark_node;
       // This can panic if there are too many operations on a closed
       // channel.
       TREE_NOTHROW(receive_big_fndecl) = 0;
@@ -3114,6 +3123,8 @@ Gogo::make_trampoline(tree fnaddr, tree closure, source_location location)
                              ptr_type_node,
                              fold_convert_loc(location, ptr_type_node,
                                               closure));
+  if (x == error_mark_node)
+    return error_mark_node;
 
   x = save_expr(x);