Rewrite conversion of named types to backend representation.
[gcc.git] / gcc / go / gofrontend / expressions.cc
index ebe4f282f8f1e8ecb0823dc6fb178a423e1728b6..ee486ffb27a79d5b3107e7a1785b05ad25774330 100644 (file)
@@ -362,6 +362,8 @@ Expression::convert_type_to_interface(Translate_context* context,
       first_field_value = fold_convert_loc(location, const_ptr_type_node,
                                           method_table);
     }
+  if (first_field_value == error_mark_node)
+    return error_mark_node;
 
   // Start building a constructor for the value we will return.
 
@@ -2357,6 +2359,9 @@ class Const_expression : public Expression
   check_for_init_loop();
 
  protected:
+  int
+  do_traverse(Traverse*);
+
   Expression*
   do_lower(Gogo*, Named_object*, int);
 
@@ -2412,6 +2417,16 @@ class Const_expression : public Expression
   mutable bool seen_;
 };
 
+// Traversal.
+
+int
+Const_expression::do_traverse(Traverse* traverse)
+{
+  if (this->type_ != NULL)
+    return Type::traverse(this->type_, traverse);
+  return TRAVERSE_CONTINUE;
+}
+
 // Lower a constant expression.  This is where we convert the
 // predeclared constant iota into an integer value.
 
@@ -4434,7 +4449,7 @@ Binary_expression::eval_integer(Operator op, Type* left_type, mpz_t left_val,
     case OPERATOR_LSHIFT:
       {
        unsigned long shift = mpz_get_ui(right_val);
-       if (mpz_cmp_ui(right_val, shift) != 0)
+       if (mpz_cmp_ui(right_val, shift) != 0 || shift > 0x100000)
          {
            error_at(location, "shift count overflow");
            mpz_set_ui(val, 0);
@@ -5859,13 +5874,21 @@ Binary_expression::do_get_tree(Translate_context* context)
   tree eval_saved = NULL_TREE;
   if (is_shift_op)
     {
-      if (!DECL_P(left))
-       left = save_expr(left);
-      if (!DECL_P(right))
-       right = save_expr(right);
       // Make sure the values are evaluated.
-      eval_saved = fold_build2_loc(this->location(), COMPOUND_EXPR,
-                                  void_type_node, left, right);
+      if (!DECL_P(left) && TREE_SIDE_EFFECTS(left))
+       {
+         left = save_expr(left);
+         eval_saved = left;
+       }
+      if (!DECL_P(right) && TREE_SIDE_EFFECTS(right))
+       {
+         right = save_expr(right);
+         if (eval_saved == NULL_TREE)
+           eval_saved = right;
+         else
+           eval_saved = fold_build2_loc(this->location(), COMPOUND_EXPR,
+                                        void_type_node, eval_saved, right);
+       }
     }
 
   tree ret = fold_build2_loc(this->location(),
@@ -5914,8 +5937,9 @@ Binary_expression::do_get_tree(Translate_context* context)
       ret = fold_build3_loc(this->location(), COND_EXPR, TREE_TYPE(left),
                            compare, ret, overflow_result);
 
-      ret = fold_build2_loc(this->location(), COMPOUND_EXPR,
-                           TREE_TYPE(ret), eval_saved, ret);
+      if (eval_saved != NULL_TREE)
+       ret = fold_build2_loc(this->location(), COMPOUND_EXPR,
+                             TREE_TYPE(ret), eval_saved, ret);
     }
 
   return ret;
@@ -6261,9 +6285,9 @@ Expression::comparison_tree(Translate_context* context, Operator op,
   else if (left_type->interface_type() != NULL
           && right_type->interface_type() != NULL)
     {
-      if (left_type->interface_type()->is_empty())
+      if (left_type->interface_type()->is_empty()
+         && right_type->interface_type()->is_empty())
        {
-         gcc_assert(right_type->interface_type()->is_empty());
          static tree empty_interface_compare_decl;
          left_tree = Gogo::call_builtin(&empty_interface_compare_decl,
                                         location,
@@ -6279,9 +6303,9 @@ Expression::comparison_tree(Translate_context* context, Operator op,
          // This can panic if the type is uncomparable.
          TREE_NOTHROW(empty_interface_compare_decl) = 0;
        }
-      else
+      else if (!left_type->interface_type()->is_empty()
+              && !right_type->interface_type()->is_empty())
        {
-         gcc_assert(!right_type->interface_type()->is_empty());
          static tree interface_compare_decl;
          left_tree = Gogo::call_builtin(&interface_compare_decl,
                                         location,
@@ -6297,6 +6321,32 @@ Expression::comparison_tree(Translate_context* context, Operator op,
          // This can panic if the type is uncomparable.
          TREE_NOTHROW(interface_compare_decl) = 0;
        }
+      else
+       {
+         if (left_type->interface_type()->is_empty())
+           {
+             gcc_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
+             std::swap(left_type, right_type);
+             std::swap(left_tree, right_tree);
+           }
+         gcc_assert(!left_type->interface_type()->is_empty());
+         gcc_assert(right_type->interface_type()->is_empty());
+         static tree interface_empty_compare_decl;
+         left_tree = Gogo::call_builtin(&interface_empty_compare_decl,
+                                        location,
+                                        "__go_interface_empty_compare",
+                                        2,
+                                        integer_type_node,
+                                        TREE_TYPE(left_tree),
+                                        left_tree,
+                                        TREE_TYPE(right_tree),
+                                        right_tree);
+         if (left_tree == error_mark_node)
+           return error_mark_node;
+         // This can panic if the type is uncomparable.
+         TREE_NOTHROW(interface_empty_compare_decl) = 0;
+       }
+
       right_tree = build_int_cst_type(integer_type_node, 0);
     }
 
@@ -6963,6 +7013,8 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
        return false;
       if (arg_type->is_abstract())
        return false;
+      if (arg_type->named_type() != NULL)
+       arg_type->named_type()->convert(this->gogo_);
       tree arg_type_tree = arg_type->get_tree(this->gogo_);
       if (arg_type_tree == error_mark_node)
        return false;
@@ -7007,6 +7059,8 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
       Type* st = struct_expr->type();
       if (st->struct_type() == NULL)
        return false;
+      if (st->named_type() != NULL)
+       st->named_type()->convert(this->gogo_);
       tree struct_tree = st->get_tree(this->gogo_);
       gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
       tree field = TYPE_FIELDS(struct_tree);
@@ -7930,7 +7984,11 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
        mpz_init(val);
        Type* dummy;
        bool b = this->integer_constant_value(true, val, &dummy);
-       gcc_assert(b);
+       if (!b)
+         {
+           gcc_assert(saw_errors());
+           return error_mark_node;
+         }
        tree type = Type::lookup_integer_type("int")->get_tree(gogo);
        tree ret = Expression::integer_constant_tree(val, type);
        mpz_clear(val);
@@ -8227,8 +8285,9 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, int)
          for (size_t i = 0; i < rc; ++i)
            args->push_back(Expression::make_call_result(call, i));
          // We can't return a new call expression here, because this
-         // one may be referenced by Call_result expressions.  FIXME.
-         delete this->args_;
+         // one may be referenced by Call_result expressions.  We
+         // also can't delete the old arguments, because we may still
+         // traverse them somewhere up the call stack.  FIXME.
          this->args_ = args;
        }
     }
@@ -8738,10 +8797,21 @@ Call_expression::do_get_tree(Translate_context* context)
       return error_mark_node;
     }
 
-  // This is to support builtin math functions when using 80387 math.
   tree fndecl = fn;
   if (TREE_CODE(fndecl) == ADDR_EXPR)
     fndecl = TREE_OPERAND(fndecl, 0);
+
+  // Add a type cast in case the type of the function is a recursive
+  // type which refers to itself.
+  if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl))
+    {
+      tree fnt = fntype->get_tree(gogo);
+      if (fnt == error_mark_node)
+       return error_mark_node;
+      fn = fold_convert_loc(location, fnt, fn);
+    }
+
+  // This is to support builtin math functions when using 80387 math.
   tree excess_type = NULL_TREE;
   if (DECL_P(fndecl)
       && DECL_IS_BUILTIN(fndecl)
@@ -8787,7 +8857,7 @@ Call_expression::do_get_tree(Translate_context* context)
   // to the correct type.
   if (TREE_TYPE(ret) == ptr_type_node)
     {
-      tree t = this->type()->get_tree(gogo);
+      tree t = this->type()->base()->get_tree(gogo);
       ret = fold_convert_loc(location, t, ret);
     }
 
@@ -8999,6 +9069,11 @@ Index_expression::do_lower(Gogo*, Named_object*, int)
   Type* type = left->type();
   if (type->is_error_type())
     return Expression::make_error(location);
+  else if (left->is_type_expression())
+    {
+      error_at(location, "attempt to index type expression");
+      return Expression::make_error(location);
+    }
   else if (type->array_type() != NULL)
     return Expression::make_array_index(left, start, end, location);
   else if (type->points_to() != NULL
@@ -9527,10 +9602,9 @@ void
 String_index_expression::do_determine_type(const Type_context*)
 {
   this->string_->determine_type_no_context();
-  Type_context subcontext(NULL, true);
-  this->start_->determine_type(&subcontext);
+  this->start_->determine_type_no_context();
   if (this->end_ != NULL)
-    this->end_->determine_type(&subcontext);
+    this->end_->determine_type_no_context();
 }
 
 // Check types of a string index.
@@ -9830,12 +9904,39 @@ Map_index_expression::get_value_pointer(Translate_context* context,
 
   // We need to pass in a pointer to the key, so stuff it into a
   // variable.
-  tree tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
-  DECL_IGNORED_P(tmp) = 0;
-  DECL_INITIAL(tmp) = index_tree;
-  tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-  tree tmpref = fold_convert(const_ptr_type_node, build_fold_addr_expr(tmp));
-  TREE_ADDRESSABLE(tmp) = 1;
+  tree tmp;
+  tree make_tmp;
+  if (current_function_decl != NULL)
+    {
+      tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
+      DECL_IGNORED_P(tmp) = 0;
+      DECL_INITIAL(tmp) = index_tree;
+      make_tmp = build1(DECL_EXPR, void_type_node, tmp);
+      TREE_ADDRESSABLE(tmp) = 1;
+    }
+  else
+    {
+      tmp = build_decl(this->location(), VAR_DECL, create_tmp_var_name("M"),
+                      TREE_TYPE(index_tree));
+      DECL_EXTERNAL(tmp) = 0;
+      TREE_PUBLIC(tmp) = 0;
+      TREE_STATIC(tmp) = 1;
+      DECL_ARTIFICIAL(tmp) = 1;
+      if (!TREE_CONSTANT(index_tree))
+       make_tmp = fold_build2_loc(this->location(), INIT_EXPR, void_type_node,
+                                  tmp, index_tree);
+      else
+       {
+         TREE_READONLY(tmp) = 1;
+         TREE_CONSTANT(tmp) = 1;
+         DECL_INITIAL(tmp) = index_tree;
+         make_tmp = NULL_TREE;
+       }
+      rest_of_decl_compilation(tmp, 1, 0);
+    }
+  tree tmpref = fold_convert_loc(this->location(), const_ptr_type_node,
+                                build_fold_addr_expr_loc(this->location(),
+                                                         tmp));
 
   static tree map_index_fndecl;
   tree call = Gogo::call_builtin(&map_index_fndecl,
@@ -9862,9 +9963,10 @@ Map_index_expression::get_value_pointer(Translate_context* context,
     return error_mark_node;
   tree ptr_val_type_tree = build_pointer_type(val_type_tree);
 
-  return build2(COMPOUND_EXPR, ptr_val_type_tree,
-               make_tmp,
-               fold_convert(ptr_val_type_tree, call));
+  tree ret = fold_convert_loc(this->location(), ptr_val_type_tree, call);
+  if (make_tmp != NULL_TREE)
+    ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret);
+  return ret;
 }
 
 // Make a map index expression.
@@ -12178,7 +12280,11 @@ tree
 Receive_expression::do_get_tree(Translate_context* context)
 {
   Channel_type* channel_type = this->channel_->type()->channel_type();
-  gcc_assert(channel_type != NULL);
+  if (channel_type == NULL)
+    {
+      gcc_assert(this->channel_->type()->is_error_type());
+      return error_mark_node;
+    }
   Type* element_type = channel_type->element_type();
   tree element_type_tree = element_type->get_tree(context->gogo());