OSDN Git Service

compiler: Fix handling of indirection of circular types.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / expressions.cc
index 5563dde..a2097e0 100644 (file)
@@ -522,8 +522,8 @@ Expression::convert_interface_to_interface(Translate_context* context,
       // first field is just the type descriptor of the object.
       go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
                        "__type_descriptor") == 0);
-      go_assert(TREE_TYPE(field) == TREE_TYPE(rhs_type_descriptor));
-      elt->value = rhs_type_descriptor;
+      elt->value = fold_convert_loc(location.gcc_location(),
+                                   TREE_TYPE(field), rhs_type_descriptor);
     }
   else
     {
@@ -3942,10 +3942,6 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
     go_assert(et->map_type() != NULL);
   else if (t->channel_type() != NULL)
     go_assert(et->channel_type() != NULL);
-  else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL)
-    go_assert((et->points_to() != NULL
-               && et->points_to()->channel_type() != NULL)
-              || et->is_nil_type());
   else if (t->points_to() != NULL)
     go_assert(et->points_to() != NULL || et->is_nil_type());
   else if (et->is_unsafe_pointer_type())
@@ -4304,14 +4300,23 @@ Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val,
          unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count];
          memset(phwi, 0, count * sizeof(HOST_WIDE_INT));
 
+         size_t obits = utype->integer_type()->bits();
+
+         if (!utype->integer_type()->is_unsigned()
+             && mpz_sgn(uval) < 0)
+           {
+             mpz_t adj;
+             mpz_init_set_ui(adj, 1);
+             mpz_mul_2exp(adj, adj, obits);
+             mpz_add(uval, uval, adj);
+             mpz_clear(adj);
+           }
+
          size_t ecount;
          mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval);
          go_assert(ecount <= count);
 
          // Trim down to the number of words required by the type.
-         size_t obits = utype->integer_type()->bits();
-         if (!utype->integer_type()->is_unsigned())
-           ++obits;
          size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1)
                           / HOST_BITS_PER_WIDE_INT);
          go_assert(ocount <= count);
@@ -4326,6 +4331,16 @@ Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val,
 
          mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi);
 
+         if (!utype->integer_type()->is_unsigned()
+             && mpz_tstbit(val, obits - 1))
+           {
+             mpz_t adj;
+             mpz_init_set_ui(adj, 1);
+             mpz_mul_2exp(adj, adj, obits);
+             mpz_sub(val, val, adj);
+             mpz_clear(adj);
+           }
+
          delete[] phwi;
        }
       return Integer_expression::check_constant(val, utype, location);
@@ -4690,29 +4705,33 @@ Unary_expression::do_get_tree(Translate_context* context)
        // need to check for nil.  We don't bother to check for small
        // structs because we expect the system to crash on a nil
        // pointer dereference.
-       HOST_WIDE_INT s = int_size_in_bytes(TREE_TYPE(TREE_TYPE(expr)));
-       if (s == -1 || s >= 4096)
+       tree target_type_tree = TREE_TYPE(TREE_TYPE(expr));
+       if (!VOID_TYPE_P(target_type_tree))
          {
-           if (!DECL_P(expr))
-             expr = save_expr(expr);
-           tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR,
-                                           boolean_type_node,
-                                          expr,
-                                          fold_convert(TREE_TYPE(expr),
-                                                       null_pointer_node));
-           tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
-                                            loc);
-           expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
-                                   TREE_TYPE(expr), build3(COND_EXPR,
-                                                           void_type_node,
-                                                           compare, crash,
-                                                           NULL_TREE),
-                                  expr);
+           HOST_WIDE_INT s = int_size_in_bytes(target_type_tree);
+           if (s == -1 || s >= 4096)
+             {
+               if (!DECL_P(expr))
+                 expr = save_expr(expr);
+               tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR,
+                                              boolean_type_node,
+                                              expr,
+                                              fold_convert(TREE_TYPE(expr),
+                                                           null_pointer_node));
+               tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
+                                                loc);
+               expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
+                                      TREE_TYPE(expr), build3(COND_EXPR,
+                                                              void_type_node,
+                                                              compare, crash,
+                                                              NULL_TREE),
+                                      expr);
+             }
          }
 
        // If the type of EXPR is a recursive pointer type, then we
        // need to insert a cast before indirecting.
-       if (TREE_TYPE(TREE_TYPE(expr)) == ptr_type_node)
+       if (VOID_TYPE_P(target_type_tree))
          {
            Type* pt = this->expr_->type()->points_to();
            tree ind = type_to_tree(pt->get_backend(context->gogo()));
@@ -5564,6 +5583,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
            && op != OPERATOR_RSHIFT)
          {
            // May be a type error--let it be diagnosed later.
+           return this;
          }
        else if (is_comparison)
          {
@@ -5667,6 +5687,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
            && op != OPERATOR_RSHIFT)
          {
            // May be a type error--let it be diagnosed later.
+           return this;
          }
        else if (is_comparison)
          {
@@ -5750,6 +5771,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
            && left_type->base() != right_type->base())
          {
            // May be a type error--let it be diagnosed later.
+           return this;
          }
        else if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
          {
@@ -5824,15 +5846,46 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
   }
 
   // String constant expressions.
-  if (op == OPERATOR_PLUS
-      && left->type()->is_string_type()
-      && right->type()->is_string_type())
+  if (left->type()->is_string_type() && right->type()->is_string_type())
     {
       std::string left_string;
       std::string right_string;
       if (left->string_constant_value(&left_string)
          && right->string_constant_value(&right_string))
-       return Expression::make_string(left_string + right_string, location);
+       {
+         if (op == OPERATOR_PLUS)
+           return Expression::make_string(left_string + right_string,
+                                          location);
+         else if (is_comparison)
+           {
+             int cmp = left_string.compare(right_string);
+             bool r;
+             switch (op)
+               {
+               case OPERATOR_EQEQ:
+                 r = cmp == 0;
+                 break;
+               case OPERATOR_NOTEQ:
+                 r = cmp != 0;
+                 break;
+               case OPERATOR_LT:
+                 r = cmp < 0;
+                 break;
+               case OPERATOR_LE:
+                 r = cmp <= 0;
+                 break;
+               case OPERATOR_GT:
+                 r = cmp > 0;
+                 break;
+               case OPERATOR_GE:
+                 r = cmp >= 0;
+                 break;
+               default:
+                 go_unreachable();
+               }
+             return Expression::make_boolean(r, location);
+           }
+       }
     }
 
   // Special case for shift of a floating point constant.
@@ -7657,7 +7710,10 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
            this->set_is_error();
            return this;
          }
-       this->lower_varargs(gogo, function, inserter, slice_type, 2);
+       Type* element_type = slice_type->array_type()->element_type();
+       this->lower_varargs(gogo, function, inserter,
+                           Type::make_array_type(element_type, NULL),
+                           2);
       }
       break;
 
@@ -7741,6 +7797,10 @@ Builtin_call_expression::lower_make()
       return Expression::make_error(this->location());
     }
 
+  bool have_big_args = false;
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+  int uintptr_bits = uintptr_type->integer_type()->bits();
+
   ++parg;
   Expression* len_arg;
   if (parg == args->end())
@@ -7764,6 +7824,9 @@ Builtin_call_expression::lower_make()
          this->report_error(_("bad size for make"));
          return Expression::make_error(this->location());
        }
+      if (len_arg->type()->integer_type() != NULL
+         && len_arg->type()->integer_type()->bits() > uintptr_bits)
+       have_big_args = true;
       ++parg;
     }
 
@@ -7776,6 +7839,9 @@ Builtin_call_expression::lower_make()
          this->report_error(_("bad capacity when making slice"));
          return Expression::make_error(this->location());
        }
+      if (cap_arg->type()->integer_type() != NULL
+         && cap_arg->type()->integer_type()->bits() > uintptr_bits)
+       have_big_args = true;
       ++parg;
     }
 
@@ -7798,16 +7864,26 @@ Builtin_call_expression::lower_make()
   if (is_slice)
     {
       if (cap_arg == NULL)
-       call = Runtime::make_call(Runtime::MAKESLICE1, loc, 2, type_arg,
-                                 len_arg);
+       call = Runtime::make_call((have_big_args
+                                  ? Runtime::MAKESLICE1BIG
+                                  : Runtime::MAKESLICE1),
+                                 loc, 2, type_arg, len_arg);
       else
-       call = Runtime::make_call(Runtime::MAKESLICE2, loc, 3, type_arg,
-                                 len_arg, cap_arg);
+       call = Runtime::make_call((have_big_args
+                                  ? Runtime::MAKESLICE2BIG
+                                  : Runtime::MAKESLICE2),
+                                 loc, 3, type_arg, len_arg, cap_arg);
     }
   else if (is_map)
-    call = Runtime::make_call(Runtime::MAKEMAP, loc, 2, type_arg, len_arg);
+    call = Runtime::make_call((have_big_args
+                              ? Runtime::MAKEMAPBIG
+                              : Runtime::MAKEMAP),
+                             loc, 2, type_arg, len_arg);
   else if (is_chan)
-    call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+    call = Runtime::make_call((have_big_args
+                              ? Runtime::MAKECHANBIG
+                              : Runtime::MAKECHAN),
+                             loc, 2, type_arg, len_arg);
   else
     go_unreachable();
 
@@ -8445,6 +8521,7 @@ Builtin_call_expression::do_check_types(Gogo*)
     case BUILTIN_INVALID:
     case BUILTIN_NEW:
     case BUILTIN_MAKE:
+    case BUILTIN_DELETE:
       return;
 
     case BUILTIN_LEN:
@@ -8613,27 +8690,34 @@ Builtin_call_expression::do_check_types(Gogo*)
            this->report_error(_("too many arguments"));
            break;
          }
+       if (args->front()->type()->is_error()
+           || args->back()->type()->is_error())
+         break;
+
+       Array_type* at = args->front()->type()->array_type();
+       Type* e = at->element_type();
 
        // The language permits appending a string to a []byte, as a
        // special case.
        if (args->back()->type()->is_string_type())
          {
-           const Array_type* at = args->front()->type()->array_type();
-           const Type* e = at->element_type()->forwarded();
            if (e->integer_type() != NULL && e->integer_type()->is_byte())
              break;
          }
 
+       // The language says that the second argument must be
+       // assignable to a slice of the element type of the first
+       // argument.  We already know the first argument is a slice
+       // type.
+       Type* arg2_type = Type::make_array_type(e, NULL);
        std::string reason;
-       if (!Type::are_assignable(args->front()->type(), args->back()->type(),
-                                 &reason))
+       if (!Type::are_assignable(arg2_type, args->back()->type(), &reason))
          {
            if (reason.empty())
-             this->report_error(_("arguments 1 and 2 have different types"));
+             this->report_error(_("argument 2 has invalid type"));
            else
              {
-               error_at(this->location(),
-                        "arguments 1 and 2 have different types (%s)",
+               error_at(this->location(), "argument 2 has invalid type (%s)",
                         reason.c_str());
                this->set_is_error();
              }
@@ -8921,7 +9005,10 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
                    fnname = "__go_print_slice";
                  }
                else
-                 go_unreachable();
+                 {
+                   go_assert(saw_errors());
+                   return error_mark_node;
+                 }
 
                tree call = Gogo::call_builtin(pfndecl,
                                               location,
@@ -9604,8 +9691,11 @@ Call_expression::result_count() const
 Temporary_statement*
 Call_expression::result(size_t i) const
 {
-  go_assert(this->results_ != NULL
-           && this->results_->size() > i);
+  if (this->results_ == NULL || this->results_->size() <= i)
+    {
+      go_assert(saw_errors());
+      return NULL;
+    }
   return (*this->results_)[i];
 }
 
@@ -10000,7 +10090,8 @@ Call_expression::do_get_tree(Translate_context* context)
 
   // This is to support builtin math functions when using 80387 math.
   tree excess_type = NULL_TREE;
-  if (TREE_CODE(fndecl) == FUNCTION_DECL
+  if (optimize
+      && TREE_CODE(fndecl) == FUNCTION_DECL
       && DECL_IS_BUILTIN(fndecl)
       && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
       && nargs > 0
@@ -10091,6 +10182,11 @@ Call_expression::set_results(Translate_context* context, tree call_tree)
       go_assert(field != NULL_TREE);
 
       Temporary_statement* temp = this->result(i);
+      if (temp == NULL)
+       {
+         go_assert(saw_errors());
+         return error_mark_node;
+       }
       Temporary_reference_expression* ref =
        Expression::make_temporary_reference(temp, loc);
       ref->set_is_lvalue();
@@ -10270,8 +10366,17 @@ tree
 Call_result_expression::do_get_tree(Translate_context* context)
 {
   Call_expression* ce = this->call_->call_expression();
-  go_assert(ce != NULL);
+  if (ce == NULL)
+    {
+      go_assert(this->call_->is_error_expression());
+      return error_mark_node;
+    }
   Temporary_statement* ts = ce->result(this->index_);
+  if (ts == NULL)
+    {
+      go_assert(saw_errors());
+      return error_mark_node;
+    }
   Expression* ref = Expression::make_temporary_reference(ts, this->location());
   return ref->get_tree(context);
 }
@@ -10642,11 +10747,28 @@ Array_index_expression::do_get_tree(Translate_context* context)
 
   if (array_type->length() == NULL && !DECL_P(array_tree))
     array_tree = save_expr(array_tree);
-  tree length_tree = array_type->length_tree(gogo, array_tree);
-  if (length_tree == error_mark_node)
-    return error_mark_node;
-  length_tree = save_expr(length_tree);
-  tree length_type = TREE_TYPE(length_tree);
+
+  tree length_tree = NULL_TREE;
+  if (this->end_ == NULL || this->end_->is_nil_expression())
+    {
+      length_tree = array_type->length_tree(gogo, array_tree);
+      if (length_tree == error_mark_node)
+       return error_mark_node;
+      length_tree = save_expr(length_tree);
+    }
+
+  tree capacity_tree = NULL_TREE;
+  if (this->end_ != NULL)
+    {
+      capacity_tree = array_type->capacity_tree(gogo, array_tree);
+      if (capacity_tree == error_mark_node)
+       return error_mark_node;
+      capacity_tree = save_expr(capacity_tree);
+    }
+
+  tree length_type = (length_tree != NULL_TREE
+                     ? TREE_TYPE(length_tree)
+                     : TREE_TYPE(capacity_tree));
 
   tree bad_index = boolean_false_node;
 
@@ -10669,7 +10791,9 @@ Array_index_expression::do_get_tree(Translate_context* context)
                                               ? GE_EXPR
                                               : GT_EXPR),
                                              boolean_type_node, start_tree,
-                                             length_tree));
+                                             (this->end_ == NULL
+                                              ? length_tree
+                                              : capacity_tree)));
 
   int code = (array_type->length() != NULL
              ? (this->end_ == NULL
@@ -10716,12 +10840,6 @@ Array_index_expression::do_get_tree(Translate_context* context)
 
   // Array slice.
 
-  tree capacity_tree = array_type->capacity_tree(gogo, array_tree);
-  if (capacity_tree == error_mark_node)
-    return error_mark_node;
-  capacity_tree = fold_convert_loc(loc.gcc_location(), length_type,
-                                   capacity_tree);
-
   tree end_tree;
   if (this->end_->is_nil_expression())
     end_tree = length_tree;
@@ -10740,7 +10858,6 @@ Array_index_expression::do_get_tree(Translate_context* context)
 
       end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree);
 
-      capacity_tree = save_expr(capacity_tree);
       tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
                                      boolean_type_node,
                                     fold_build2_loc(loc.gcc_location(),
@@ -11704,10 +11821,21 @@ Selector_expression::lower_method_expression(Gogo* gogo)
   const Typed_identifier_list* method_parameters = method_type->parameters();
   if (method_parameters != NULL)
     {
+      int i = 0;
       for (Typed_identifier_list::const_iterator p = method_parameters->begin();
           p != method_parameters->end();
-          ++p)
-       parameters->push_back(*p);
+          ++p, ++i)
+       {
+         if (!p->name().empty())
+           parameters->push_back(*p);
+         else
+           {
+             char buf[20];
+             snprintf(buf, sizeof buf, "$param%d", i);
+             parameters->push_back(Typed_identifier(buf, p->type(),
+                                                    p->location()));
+           }
+       }
     }
 
   const Typed_identifier_list* method_results = method_type->results();
@@ -11767,14 +11895,14 @@ Selector_expression::lower_method_expression(Gogo* gogo)
     }
 
   Expression_list* args;
-  if (method_parameters == NULL)
+  if (parameters->size() <= 1)
     args = NULL;
   else
     {
       args = new Expression_list();
-      for (Typed_identifier_list::const_iterator p = method_parameters->begin();
-          p != method_parameters->end();
-          ++p)
+      Typed_identifier_list::const_iterator p = parameters->begin();
+      ++p;
+      for (; p != parameters->end(); ++p)
        {
          vno = gogo->lookup(p->name(), NULL);
          go_assert(vno != NULL);
@@ -13754,7 +13882,7 @@ tree
 Heap_composite_expression::do_get_tree(Translate_context* context)
 {
   tree expr_tree = this->expr_->get_tree(context);
-  if (expr_tree == error_mark_node)
+  if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node)
     return error_mark_node;
   tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree));
   go_assert(TREE_CODE(expr_size) == INTEGER_CST);