OSDN Git Service

Check for invalid uses of ... in builtin function calls.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / expressions.cc
index 8592ef5..e3a3ab5 100644 (file)
@@ -205,17 +205,9 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
   if (lhs_type == rhs_type)
     return rhs_tree;
 
-  if (lhs_type->is_error_type() || rhs_type->is_error_type())
+  if (lhs_type->is_error() || rhs_type->is_error())
     return error_mark_node;
 
-  if (lhs_type->is_undefined() || rhs_type->is_undefined())
-    {
-      // Make sure we report the error.
-      lhs_type->base();
-      rhs_type->base();
-      return error_mark_node;
-    }
-
   if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node)
     return error_mark_node;
 
@@ -362,6 +354,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.
 
@@ -716,7 +710,11 @@ Expression::float_constant_tree(mpfr_t val, tree type)
 tree
 Expression::complex_constant_tree(mpfr_t real, mpfr_t imag, tree type)
 {
-  if (TREE_CODE(type) == COMPLEX_TYPE)
+  if (type == error_mark_node)
+    return error_mark_node;
+  else if (TREE_CODE(type) == INTEGER_TYPE || TREE_CODE(type) == REAL_TYPE)
+    return Expression::float_constant_tree(real, type);
+  else if (TREE_CODE(type) == COMPLEX_TYPE)
     {
       REAL_VALUE_TYPE r1;
       real_from_mpfr(&r1, real, TREE_TYPE(type), GMP_RNDN);
@@ -894,6 +892,19 @@ Expression::make_type(Type* type, source_location location)
   return new Type_expression(type, location);
 }
 
+// Class Parser_expression.
+
+Type*
+Parser_expression::do_type()
+{
+  // We should never really ask for the type of a Parser_expression.
+  // However, it can happen, at least when we have an invalid const
+  // whose initializer refers to the const itself.  In that case we
+  // may ask for the type when lowering the const itself.
+  gcc_assert(saw_errors());
+  return Type::make_error_type();
+}
+
 // Class Var_expression.
 
 // Lower a variable expression.  Here we just make sure that the
@@ -917,14 +928,6 @@ Var_expression::do_lower(Gogo* gogo, Named_object* function, int)
   return this;
 }
 
-// Return the name of the variable.
-
-const std::string&
-Var_expression::name() const
-{
-  return this->variable_->name();
-}
-
 // Return the type of a reference to a variable.
 
 Type*
@@ -938,6 +941,15 @@ Var_expression::do_type()
     gcc_unreachable();
 }
 
+// Determine the type of a reference to a variable.
+
+void
+Var_expression::do_determine_type(const Type_context*)
+{
+  if (this->variable_->is_variable())
+    this->variable_->var_value()->determine_type();
+}
+
 // Something takes the address of this variable.  This means that we
 // may want to move the variable onto the heap.
 
@@ -1097,14 +1109,6 @@ Expression::make_sink(source_location location)
 // a function seems like it could work, though there might be little
 // point to it.
 
-// Return the name of the function.
-
-const std::string&
-Func_expression::name() const
-{
-  return this->function_->name();
-}
-
 // Traversal.
 
 int
@@ -1919,7 +1923,7 @@ Float_expression::do_determine_type(const Type_context* context)
               || context->type->complex_type() != NULL))
     this->type_ = context->type;
   else if (!context->may_be_abstract)
-    this->type_ = Type::lookup_float_type("float");
+    this->type_ = Type::lookup_float_type("float64");
 }
 
 // Return true if the floating point value VAL fits in the range of
@@ -2172,7 +2176,7 @@ Complex_expression::do_determine_type(const Type_context* context)
           && context->type->complex_type() != NULL)
     this->type_ = context->type;
   else if (!context->may_be_abstract)
-    this->type_ = Type::lookup_complex_type("complex");
+    this->type_ = Type::lookup_complex_type("complex128");
 }
 
 // Return true if the complex value REAL/IMAG fits in the range of the
@@ -2331,11 +2335,14 @@ class Const_expression : public Expression
   named_object()
   { return this->constant_; }
 
-  const std::string&
-  name() const
-  { return this->constant_->name(); }
+  // Check that the initializer does not refer to the constant itself.
+  void
+  check_for_init_loop();
 
  protected:
+  int
+  do_traverse(Traverse*);
+
   Expression*
   do_lower(Gogo*, Named_object*, int);
 
@@ -2391,6 +2398,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.
 
@@ -2597,23 +2614,49 @@ Const_expression::do_determine_type(const Type_context* context)
     }
 }
 
-// Check types of a const reference.
+// Check for a loop in which the initializer of a constant refers to
+// the constant itself.
 
 void
-Const_expression::do_check_types(Gogo*)
+Const_expression::check_for_init_loop()
 {
-  if (this->type_ != NULL && this->type_->is_error_type())
+  if (this->type_ != NULL && this->type_->is_error())
     return;
 
+  if (this->seen_)
+    {
+      this->report_error(_("constant refers to itself"));
+      this->type_ = Type::make_error_type();
+      return;
+    }
+
   Expression* init = this->constant_->const_value()->expr();
   Find_named_object find_named_object(this->constant_);
+
+  this->seen_ = true;
   Expression::traverse(&init, &find_named_object);
+  this->seen_ = false;
+
   if (find_named_object.found())
     {
-      this->report_error(_("constant refers to itself"));
-      this->type_ = Type::make_error_type();
+      if (this->type_ == NULL || !this->type_->is_error())
+       {
+         this->report_error(_("constant refers to itself"));
+         this->type_ = Type::make_error_type();
+       }
       return;
     }
+}
+
+// Check types of a const reference.
+
+void
+Const_expression::do_check_types(Gogo*)
+{
+  if (this->type_ != NULL && this->type_->is_error())
+    return;
+
+  this->check_for_init_loop();
 
   if (this->type_ == NULL || this->type_->is_abstract())
     return;
@@ -2667,7 +2710,8 @@ Const_expression::do_get_tree(Translate_context* context)
   // object is an abstract int or float, we try to get the abstract
   // value.  Otherwise we may lose something in the conversion.
   if (this->type_ != NULL
-      && this->constant_->const_value()->type()->is_abstract())
+      && (this->constant_->const_value()->type() == NULL
+         || this->constant_->const_value()->type()->is_abstract()))
     {
       Expression* expr = this->constant_->const_value()->expr();
       mpz_t ival;
@@ -2740,9 +2784,19 @@ Find_named_object::expression(Expression** pexpr)
   switch ((*pexpr)->classification())
     {
     case Expression::EXPRESSION_CONST_REFERENCE:
-      if (static_cast<Const_expression*>(*pexpr)->named_object() == this->no_)
-       break;
-      return TRAVERSE_CONTINUE;
+      {
+       Const_expression* ce = static_cast<Const_expression*>(*pexpr);
+       if (ce->named_object() == this->no_)
+         break;
+
+       // We need to check a constant initializer explicitly, as
+       // loops here will not be caught by the loop checking for
+       // variable initializers.
+       ce->check_for_init_loop();
+
+       return TRAVERSE_CONTINUE;
+      }
+
     case Expression::EXPRESSION_VAR_REFERENCE:
       if ((*pexpr)->var_expression()->named_object() == this->no_)
        break;
@@ -3249,14 +3303,8 @@ Type_conversion_expression::do_check_types(Gogo*)
   Type* expr_type = this->expr_->type();
   std::string reason;
 
-  if (type->is_error_type()
-      || type->is_undefined()
-      || expr_type->is_error_type()
-      || expr_type->is_undefined())
+  if (type->is_error() || expr_type->is_error())
     {
-      // Make sure we emit an error for an undefined type.
-      type->base();
-      expr_type->base();
       this->set_is_error();
       return;
     }
@@ -3965,7 +4013,7 @@ void
 Unary_expression::do_check_types(Gogo*)
 {
   Type* type = this->expr_->type();
-  if (type->is_error_type())
+  if (type->is_error())
     {
       this->set_is_error();
       return;
@@ -4376,7 +4424,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);
@@ -5105,7 +5153,7 @@ Binary_expression::do_lower(Gogo*, Named_object*, int)
          {
            // May be a type error--let it be diagnosed later.
          }
-       else if (is_comparison)
+       else if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
          {
            bool b = Binary_expression::compare_complex(op,
                                                        (left_type != NULL
@@ -5358,6 +5406,9 @@ Binary_expression::do_discarding_value()
 Type*
 Binary_expression::do_type()
 {
+  if (this->classification() == EXPRESSION_ERROR)
+    return Type::make_error_type();
+
   switch (this->op_)
     {
     case OPERATOR_OROR:
@@ -5382,7 +5433,16 @@ Binary_expression::do_type()
       {
        Type* left_type = this->left_->type();
        Type* right_type = this->right_->type();
-       if (!left_type->is_abstract() && left_type->named_type() != NULL)
+       if (left_type->is_error())
+         return left_type;
+       else if (right_type->is_error())
+         return right_type;
+       else if (!Type::are_compatible_for_binop(left_type, right_type))
+         {
+           this->report_error(_("incompatible types in binary expression"));
+           return Type::make_error_type();
+         }
+       else if (!left_type->is_abstract() && left_type->named_type() != NULL)
          return left_type;
        else if (!right_type->is_abstract() && right_type->named_type() != NULL)
          return right_type;
@@ -5478,6 +5538,9 @@ Binary_expression::do_determine_type(const Type_context* context)
        subcontext.type = tright;
       else
        subcontext.type = tleft;
+
+      if (subcontext.type != NULL && !context->may_be_abstract)
+       subcontext.type = subcontext.type->make_non_abstract_type();
     }
 
   this->left_->determine_type(&subcontext);
@@ -5606,9 +5669,12 @@ Binary_expression::check_operator_type(Operator op, Type* type,
 void
 Binary_expression::do_check_types(Gogo*)
 {
+  if (this->classification() == EXPRESSION_ERROR)
+    return;
+
   Type* left_type = this->left_->type();
   Type* right_type = this->right_->type();
-  if (left_type->is_error_type() || right_type->is_error_type())
+  if (left_type->is_error() || right_type->is_error())
     {
       this->set_is_error();
       return;
@@ -5667,7 +5733,13 @@ Binary_expression::do_check_types(Gogo*)
          if (this->right_->integer_constant_value(true, val, &type))
            {
              if (mpz_sgn(val) < 0)
-               this->report_error(_("negative shift count"));
+               {
+                 this->report_error(_("negative shift count"));
+                 mpz_set_ui(val, 0);
+                 source_location rloc = this->right_->location();
+                 this->right_ = Expression::make_integer(&val, right_type,
+                                                         rloc);
+               }
            }
          mpz_clear(val);
        }
@@ -5783,13 +5855,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(),
@@ -5838,8 +5918,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;
@@ -6185,9 +6266,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,
@@ -6203,9 +6284,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,
@@ -6221,6 +6302,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);
     }
 
@@ -6336,7 +6443,8 @@ Bound_method_expression::do_check_types(Gogo*)
 tree
 Bound_method_expression::do_get_tree(Translate_context*)
 {
-  gcc_unreachable();
+  error_at(this->location(), "reference to method other than calling it");
+  return error_mark_node;
 }
 
 // Make a method expression.
@@ -6414,8 +6522,7 @@ class Builtin_call_expression : public Call_expression
       BUILTIN_APPEND,
       BUILTIN_CAP,
       BUILTIN_CLOSE,
-      BUILTIN_CLOSED,
-      BUILTIN_CMPLX,
+      BUILTIN_COMPLEX,
       BUILTIN_COPY,
       BUILTIN_IMAG,
       BUILTIN_LEN,
@@ -6443,13 +6550,16 @@ class Builtin_call_expression : public Call_expression
   real_imag_type(Type*);
 
   static Type*
-  cmplx_type(Type*);
+  complex_type(Type*);
 
   // A pointer back to the general IR structure.  This avoids a global
   // variable, or passing it around everywhere.
   Gogo* gogo_;
   // The builtin function being called.
   Builtin_function_code code_;
+  // Used to stop endless loops when the length of an array uses len
+  // or cap of the array itself.
+  mutable bool seen_;
 };
 
 Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
@@ -6458,7 +6568,7 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
                                                 bool is_varargs,
                                                 source_location location)
   : Call_expression(fn, args, is_varargs, location),
-    gogo_(gogo), code_(BUILTIN_INVALID)
+    gogo_(gogo), code_(BUILTIN_INVALID), seen_(false)
 {
   Func_expression* fnexp = this->fn()->func_expression();
   gcc_assert(fnexp != NULL);
@@ -6469,10 +6579,8 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
     this->code_ = BUILTIN_CAP;
   else if (name == "close")
     this->code_ = BUILTIN_CLOSE;
-  else if (name == "closed")
-    this->code_ = BUILTIN_CLOSED;
-  else if (name == "cmplx")
-    this->code_ = BUILTIN_CMPLX;
+  else if (name == "complex")
+    this->code_ = BUILTIN_COMPLEX;
   else if (name == "copy")
     this->code_ = BUILTIN_COPY;
   else if (name == "imag")
@@ -6564,6 +6672,12 @@ Find_call_expression::expression(Expression** pexpr)
 Expression*
 Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
 {
+  if (this->is_varargs() && this->code_ != BUILTIN_APPEND)
+    {
+      this->report_error(_("invalid use of %<...%> with builtin function"));
+      return Expression::make_error(this->location());
+    }
+
   if (this->code_ == BUILTIN_NEW)
     {
       const Expression_list* args = this->args();
@@ -6713,9 +6827,7 @@ Builtin_call_expression::real_imag_type(Type* arg_type)
     return NULL;
   while (nt->real_type()->named_type() != NULL)
     nt = nt->real_type()->named_type();
-  if (nt->name() == "complex")
-    return Type::lookup_float_type("float");
-  else if (nt->name() == "complex64")
+  if (nt->name() == "complex64")
     return Type::lookup_float_type("float32");
   else if (nt->name() == "complex128")
     return Type::lookup_float_type("float64");
@@ -6723,11 +6835,11 @@ Builtin_call_expression::real_imag_type(Type* arg_type)
     return NULL;
 }
 
-// Return the type of the cmplx function, given the type of one of the
+// Return the type of the complex function, given the type of one of the
 // argments.  Like real_imag_type, we have to map by name.
 
 Type*
-Builtin_call_expression::cmplx_type(Type* arg_type)
+Builtin_call_expression::complex_type(Type* arg_type)
 {
   if (arg_type == NULL || arg_type->is_abstract())
     return NULL;
@@ -6736,9 +6848,7 @@ Builtin_call_expression::cmplx_type(Type* arg_type)
     return NULL;
   while (nt->real_type()->named_type() != NULL)
     nt = nt->real_type()->named_type();
-  if (nt->name() == "float")
-    return Type::lookup_complex_type("complex");
-  else if (nt->name() == "float32")
+  if (nt->name() == "float32")
     return Type::lookup_complex_type("complex64");
   else if (nt->name() == "float64")
     return Type::lookup_complex_type("complex128");
@@ -6768,6 +6878,9 @@ Builtin_call_expression::do_is_constant() const
     case BUILTIN_LEN:
     case BUILTIN_CAP:
       {
+       if (this->seen_)
+         return false;
+
        Expression* arg = this->one_arg();
        if (arg == NULL)
          return false;
@@ -6780,10 +6893,15 @@ Builtin_call_expression::do_is_constant() const
 
        if (arg_type->array_type() != NULL
            && arg_type->array_type()->length() != NULL)
-         return arg_type->array_type()->length()->is_constant();
+         return true;
 
        if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
-         return arg->is_constant();
+         {
+           this->seen_ = true;
+           bool ret = arg->is_constant();
+           this->seen_ = false;
+           return ret;
+         }
       }
       break;
 
@@ -6799,7 +6917,7 @@ Builtin_call_expression::do_is_constant() const
        return arg->field_reference_expression() != NULL;
       }
 
-    case BUILTIN_CMPLX:
+    case BUILTIN_COMPLEX:
       {
        const Expression_list* args = this->args();
        if (args != NULL && args->size() == 2)
@@ -6855,8 +6973,13 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
       if (arg_type->array_type() != NULL
          && arg_type->array_type()->length() != NULL)
        {
+         if (this->seen_)
+           return false;
          Expression* e = arg_type->array_type()->length();
-         if (e->integer_constant_value(iota_is_constant, val, ptype))
+         this->seen_ = true;
+         bool r = e->integer_constant_value(iota_is_constant, val, ptype);
+         this->seen_ = false;
+         if (r)
            {
              *ptype = Type::lookup_integer_type("int");
              return true;
@@ -6870,11 +6993,15 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
       if (arg == NULL)
        return false;
       Type* arg_type = arg->type();
-      if (arg_type->is_error_type() || arg_type->is_undefined())
+      if (arg_type->is_error())
        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;
       unsigned long val_long;
       if (this->code_ == BUILTIN_SIZEOF)
        {
@@ -6916,6 +7043,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);
@@ -6979,7 +7108,7 @@ bool
 Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
                                                   Type** ptype) const
 {
-  if (this->code_ == BUILTIN_CMPLX)
+  if (this->code_ == BUILTIN_COMPLEX)
     {
       const Expression_list* args = this->args();
       if (args == NULL || args->size() != 2)
@@ -7004,7 +7133,7 @@ Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
        {
          mpfr_set(real, r, GMP_RNDN);
          mpfr_set(imag, i, GMP_RNDN);
-         *ptype = Builtin_call_expression::cmplx_type(rtype);
+         *ptype = Builtin_call_expression::complex_type(rtype);
          ret = true;
        }
 
@@ -7051,9 +7180,6 @@ Builtin_call_expression::do_type()
     case BUILTIN_PRINTLN:
       return Type::make_void_type();
 
-    case BUILTIN_CLOSED:
-      return Type::lookup_bool_type();
-
     case BUILTIN_RECOVER:
       return Type::make_interface_type(NULL, BUILTINS_LOCATION);
 
@@ -7080,7 +7206,7 @@ Builtin_call_expression::do_type()
        return t;
       }
 
-    case BUILTIN_CMPLX:
+    case BUILTIN_COMPLEX:
       {
        const Expression_list* args = this->args();
        if (args == NULL || args->size() != 2)
@@ -7092,7 +7218,7 @@ Builtin_call_expression::do_type()
            if (t->is_abstract())
              t = t->make_non_abstract_type();
          }
-       t = Builtin_call_expression::cmplx_type(t);
+       t = Builtin_call_expression::complex_type(t);
        if (t == NULL)
          t = Type::make_error_type();
        return t;
@@ -7105,6 +7231,9 @@ Builtin_call_expression::do_type()
 void
 Builtin_call_expression::do_determine_type(const Type_context* context)
 {
+  if (!this->determining_types())
+    return;
+
   this->fn()->determine_type_no_context();
 
   const Expression_list* args = this->args();
@@ -7121,13 +7250,13 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
 
     case BUILTIN_REAL:
     case BUILTIN_IMAG:
-      arg_type = Builtin_call_expression::cmplx_type(context->type);
+      arg_type = Builtin_call_expression::complex_type(context->type);
       is_print = false;
       break;
 
-    case BUILTIN_CMPLX:
+    case BUILTIN_COMPLEX:
       {
-       // For the cmplx function the type of one operand can
+       // For the complex function the type of one operand can
        // determine the type of the other, as in a binary expression.
        arg_type = Builtin_call_expression::real_imag_type(context->type);
        if (args != NULL && args->size() == 2)
@@ -7217,8 +7346,7 @@ Builtin_call_expression::check_one_arg()
       return false;
     }
   if (args->front()->is_error_expression()
-      || args->front()->type()->is_error_type()
-      || args->front()->type()->is_undefined())
+      || args->front()->type()->is_error())
     {
       this->set_is_error();
       return false;
@@ -7252,7 +7380,7 @@ Builtin_call_expression::do_check_types(Gogo*)
              arg_type = arg_type->points_to();
            if (this->code_ == BUILTIN_CAP)
              {
-               if (!arg_type->is_error_type()
+               if (!arg_type->is_error()
                    && arg_type->array_type() == NULL
                    && arg_type->channel_type() == NULL)
                  this->report_error(_("argument must be array or slice "
@@ -7260,7 +7388,7 @@ Builtin_call_expression::do_check_types(Gogo*)
              }
            else
              {
-               if (!arg_type->is_error_type()
+               if (!arg_type->is_error()
                    && !arg_type->is_string_type()
                    && arg_type->array_type() == NULL
                    && arg_type->map_type() == NULL
@@ -7292,7 +7420,7 @@ Builtin_call_expression::do_check_types(Gogo*)
                 ++p)
              {
                Type* type = (*p)->type();
-               if (type->is_error_type()
+               if (type->is_error()
                    || type->is_string_type()
                    || type->integer_type() != NULL
                    || type->float_type() != NULL
@@ -7314,7 +7442,6 @@ Builtin_call_expression::do_check_types(Gogo*)
       break;
 
     case BUILTIN_CLOSE:
-    case BUILTIN_CLOSED:
       if (this->check_one_arg())
        {
          if (this->one_arg()->type()->channel_type() == NULL)
@@ -7357,7 +7484,7 @@ Builtin_call_expression::do_check_types(Gogo*)
          }
        Type* arg1_type = args->front()->type();
        Type* arg2_type = args->back()->type();
-       if (arg1_type->is_error_type() || arg2_type->is_error_type())
+       if (arg1_type->is_error() || arg2_type->is_error())
          break;
 
        Type* e1;
@@ -7424,7 +7551,7 @@ Builtin_call_expression::do_check_types(Gogo*)
        }
       break;
 
-    case BUILTIN_CMPLX:
+    case BUILTIN_COMPLEX:
       {
        const Expression_list* args = this->args();
        if (args == NULL || args->size() < 2)
@@ -7432,15 +7559,15 @@ Builtin_call_expression::do_check_types(Gogo*)
        else if (args->size() > 2)
          this->report_error(_("too many arguments"));
        else if (args->front()->is_error_expression()
-                || args->front()->type()->is_error_type()
+                || args->front()->type()->is_error()
                 || args->back()->is_error_expression()
-                || args->back()->type()->is_error_type())
+                || args->back()->type()->is_error())
          this->set_is_error();
        else if (!Type::are_identical(args->front()->type(),
                                      args->back()->type(), true, NULL))
-         this->report_error(_("cmplx arguments must have identical types"));
+         this->report_error(_("complex arguments must have identical types"));
        else if (args->front()->type()->float_type() == NULL)
-         this->report_error(_("cmplx arguments must have "
+         this->report_error(_("complex arguments must have "
                               "floating-point type"));
       }
       break;
@@ -7471,7 +7598,18 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
        gcc_assert(args != NULL && args->size() == 1);
        Expression* arg = *args->begin();
        Type* arg_type = arg->type();
+
+       if (this->seen_)
+         {
+           gcc_assert(saw_errors());
+           return error_mark_node;
+         }
+       this->seen_ = true;
+
        tree arg_tree = arg->get_tree(context);
+
+       this->seen_ = false;
+
        if (arg_tree == error_mark_node)
          return error_mark_node;
 
@@ -7490,7 +7628,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
            if (arg_type->is_string_type())
              val_tree = String_type::length_tree(gogo, arg_tree);
            else if (arg_type->array_type() != NULL)
-             val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+             {
+               if (this->seen_)
+                 {
+                   gcc_assert(saw_errors());
+                   return error_mark_node;
+                 }
+               this->seen_ = true;
+               val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+               this->seen_ = false;
+             }
            else if (arg_type->map_type() != NULL)
              {
                static tree map_len_fndecl;
@@ -7519,7 +7666,17 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
        else
          {
            if (arg_type->array_type() != NULL)
-             val_tree = arg_type->array_type()->capacity_tree(gogo, arg_tree);
+             {
+               if (this->seen_)
+                 {
+                   gcc_assert(saw_errors());
+                   return error_mark_node;
+                 }
+               this->seen_ = true;
+               val_tree = arg_type->array_type()->capacity_tree(gogo,
+                                                                arg_tree);
+               this->seen_ = false;
+             }
            else if (arg_type->channel_type() != NULL)
              {
                static tree chan_cap_fndecl;
@@ -7769,7 +7926,6 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
       }
 
     case BUILTIN_CLOSE:
-    case BUILTIN_CLOSED:
       {
        const Expression_list* args = this->args();
        gcc_assert(args != NULL && args->size() == 1);
@@ -7777,28 +7933,14 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
        tree arg_tree = arg->get_tree(context);
        if (arg_tree == error_mark_node)
          return error_mark_node;
-       if (this->code_ == BUILTIN_CLOSE)
-         {
-           static tree close_fndecl;
-           return Gogo::call_builtin(&close_fndecl,
-                                     location,
-                                     "__go_builtin_close",
-                                     1,
-                                     void_type_node,
-                                     TREE_TYPE(arg_tree),
-                                     arg_tree);
-         }
-       else
-         {
-           static tree closed_fndecl;
-           return Gogo::call_builtin(&closed_fndecl,
-                                     location,
-                                     "__go_builtin_closed",
-                                     1,
-                                     boolean_type_node,
-                                     TREE_TYPE(arg_tree),
-                                     arg_tree);
-         }
+       static tree close_fndecl;
+       return Gogo::call_builtin(&close_fndecl,
+                                 location,
+                                 "__go_builtin_close",
+                                 1,
+                                 void_type_node,
+                                 TREE_TYPE(arg_tree),
+                                 arg_tree);
       }
 
     case BUILTIN_SIZEOF:
@@ -7809,7 +7951,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);
@@ -7905,18 +8051,24 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
        Expression* arg1 = args->front();
        Expression* arg2 = args->back();
 
-       Array_type* at = arg1->type()->array_type();
-       Type* element_type = at->element_type();
-
        tree arg1_tree = arg1->get_tree(context);
        tree arg2_tree = arg2->get_tree(context);
        if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
          return error_mark_node;
 
-       Array_type* at2 = arg2->type()->array_type();
+       Array_type* at = arg1->type()->array_type();
+       Type* element_type = at->element_type();
+
+       arg2_tree = Expression::convert_for_assignment(context, at,
+                                                      arg2->type(),
+                                                      arg2_tree,
+                                                      location);
+       if (arg2_tree == error_mark_node)
+         return error_mark_node;
+
        arg2_tree = save_expr(arg2_tree);
-       tree arg2_val = at2->value_pointer_tree(gogo, arg2_tree);
-       tree arg2_len = at2->length_tree(gogo, arg2_tree);
+       tree arg2_val = at->value_pointer_tree(gogo, arg2_tree);
+       tree arg2_len = at->length_tree(gogo, arg2_tree);
        if (arg2_val == error_mark_node || arg2_len == error_mark_node)
          return error_mark_node;
        arg2_val = fold_convert_loc(location, ptr_type_node, arg2_val);
@@ -7967,7 +8119,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
                                 arg_tree);
       }
 
-    case BUILTIN_CMPLX:
+    case BUILTIN_COMPLEX:
       {
        const Expression_list* args = this->args();
        gcc_assert(args != NULL && args->size() == 2);
@@ -8100,8 +8252,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;
        }
     }
@@ -8179,11 +8332,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
          this->report_error(_("too many arguments"));
          return this;
        }
-      else if (pa + 1 == old_args->end()
-              && this->is_compatible_varargs_argument(function, *pa,
-                                                      varargs_type,
-                                                      &issued_error))
-       new_args->push_back(*pa);
       else
        {
          Type* element_type = varargs_type->array_type()->element_type();
@@ -8221,84 +8369,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
   return ret;
 }
 
-// Return true if ARG is a varargs argment which should be passed to
-// the varargs parameter of type PARAM_TYPE without wrapping.  ARG
-// will be the last argument passed in the call, and PARAM_TYPE will
-// be the type of the last parameter of the varargs function being
-// called.
-
-bool
-Call_expression::is_compatible_varargs_argument(Named_object* function,
-                                               Expression* arg,
-                                               Type* param_type,
-                                               bool* issued_error)
-{
-  *issued_error = false;
-
-  Type* var_type = NULL;
-
-  // The simple case is passing the varargs parameter of the caller.
-  Var_expression* ve = arg->var_expression();
-  if (ve != NULL && ve->named_object()->is_variable())
-    {
-      Variable* var = ve->named_object()->var_value();
-      if (var->is_varargs_parameter())
-       var_type = var->type();
-    }
-
-  // The complex case is passing the varargs parameter of some
-  // enclosing function.  This will look like passing down *c.f where
-  // c is the closure variable and f is a field in the closure.
-  if (function != NULL
-      && function->func_value()->needs_closure()
-      && arg->classification() == EXPRESSION_UNARY)
-    {
-      Unary_expression* ue = static_cast<Unary_expression*>(arg);
-      if (ue->op() == OPERATOR_MULT)
-       {
-         Field_reference_expression* fre =
-           ue->operand()->deref()->field_reference_expression();
-         if (fre != NULL)
-           {
-             Var_expression* ve = fre->expr()->deref()->var_expression();
-             if (ve != NULL)
-               {
-                 Named_object* no = ve->named_object();
-                 Function* f = function->func_value();
-                 if (no == f->closure_var())
-                   {
-                     // At this point we know that this indeed a
-                     // reference to some enclosing variable.  Now we
-                     // need to figure out whether that variable is a
-                     // varargs parameter.
-                     Named_object* enclosing =
-                       f->enclosing_var(fre->field_index());
-                     Variable* var = enclosing->var_value();
-                     if (var->is_varargs_parameter())
-                       var_type = var->type();
-                   }
-               }
-           }
-       }
-    }
-
-  if (var_type == NULL)
-    return false;
-
-  // We only match if the parameter is the same, with an identical
-  // type.
-  Array_type* var_at = var_type->array_type();
-  gcc_assert(var_at != NULL);
-  Array_type* param_at = param_type->array_type();
-  if (param_at != NULL
-      && Type::are_identical(var_at->element_type(),
-                            param_at->element_type(), true, NULL))
-    return true;
-  error_at(arg->location(), "... mismatch: passing ...T as ...");
-  *issued_error = true;
-  return false;
-}
-
 // Get the function type.  Returns NULL if we don't know the type.  If
 // this returns NULL, and if_ERROR is true, issues an error.
 
@@ -8383,6 +8453,9 @@ Call_expression::do_type()
 void
 Call_expression::do_determine_type(const Type_context*)
 {
+  if (!this->determining_types())
+    return;
+
   this->fn_->determine_type_no_context();
   Function_type* fntype = this->get_function_type();
   const Typed_identifier_list* parameters = NULL;
@@ -8409,6 +8482,21 @@ Call_expression::do_determine_type(const Type_context*)
     }
 }
 
+// Called when determining types for a Call_expression.  Return true
+// if we should go ahead, false if they have already been determined.
+
+bool
+Call_expression::determining_types()
+{
+  if (this->types_are_determined_)
+    return false;
+  else
+    {
+      this->types_are_determined_ = true;
+      return true;
+    }
+}
+
 // Check types for parameter I.
 
 bool
@@ -8443,7 +8531,7 @@ Call_expression::do_check_types(Gogo*)
   Function_type* fntype = this->get_function_type();
   if (fntype == NULL)
     {
-      if (!this->fn_->type()->is_error_type())
+      if (!this->fn_->type()->is_error())
        this->report_error(_("expected function"));
       return;
     }
@@ -8660,7 +8748,10 @@ Call_expression::do_get_tree(Translate_context* context)
                                                       arg_val,
                                                       location);
          if (args[i] == error_mark_node)
-           return error_mark_node;
+           {
+             delete[] args;
+             return error_mark_node;
+           }
        }
       gcc_assert(pp == params->end());
       gcc_assert(i == nargs);
@@ -8668,7 +8759,10 @@ Call_expression::do_get_tree(Translate_context* context)
 
   tree rettype = TREE_TYPE(TREE_TYPE(fntype->get_tree(gogo)));
   if (rettype == error_mark_node)
-    return error_mark_node;
+    {
+      delete[] args;
+      return error_mark_node;
+    }
 
   tree fn;
   if (has_closure)
@@ -8683,12 +8777,26 @@ Call_expression::do_get_tree(Translate_context* context)
     gcc_unreachable();
 
   if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
-    return error_mark_node;
+    {
+      delete[] args;
+      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)
@@ -8734,7 +8842,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);
     }
 
@@ -8833,10 +8941,16 @@ Call_result_expression::do_type()
   // Call_expression::do_must_eval_in_order when there is an error.
   Call_expression* ce = this->call_->call_expression();
   if (ce == NULL)
-    return Type::make_error_type();
+    {
+      this->set_is_error();
+      return Type::make_error_type();
+    }
   Function_type* fntype = ce->get_function_type();
   if (fntype == NULL)
-    return Type::make_error_type();
+    {
+      this->set_is_error();
+      return Type::make_error_type();
+    }
   const Typed_identifier_list* results = fntype->results();
   if (results == NULL)
     {
@@ -8875,8 +8989,7 @@ Call_result_expression::do_check_types(Gogo*)
 void
 Call_result_expression::do_determine_type(const Type_context*)
 {
-  if (this->index_ == 0)
-    this->call_->determine_type_no_context();
+  this->call_->determine_type_no_context();
 }
 
 // Return the tree.
@@ -8887,7 +9000,11 @@ Call_result_expression::do_get_tree(Translate_context* context)
   tree call_tree = this->call_->get_tree(context);
   if (call_tree == error_mark_node)
     return error_mark_node;
-  gcc_assert(TREE_CODE(TREE_TYPE(call_tree)) == RECORD_TYPE);
+  if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
+    {
+      gcc_assert(saw_errors());
+      return error_mark_node;
+    }
   tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
   for (unsigned int i = 0; i < this->index_; ++i)
     {
@@ -8934,8 +9051,13 @@ Index_expression::do_lower(Gogo*, Named_object*, int)
   Expression* end = this->end_;
 
   Type* type = left->type();
-  if (type->is_error_type())
+  if (type->is_error())
     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
@@ -9085,10 +9207,9 @@ void
 Array_index_expression::do_determine_type(const Type_context*)
 {
   this->array_->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 an array index.
@@ -9106,7 +9227,7 @@ Array_index_expression::do_check_types(Gogo*)
   Array_type* array_type = this->array_->type()->array_type();
   if (array_type == NULL)
     {
-      gcc_assert(this->array_->type()->is_error_type());
+      gcc_assert(this->array_->type()->is_error());
       return;
     }
 
@@ -9188,7 +9309,7 @@ Array_index_expression::do_get_tree(Translate_context* context)
   Array_type* array_type = this->array_->type()->array_type();
   if (array_type == NULL)
     {
-      gcc_assert(this->array_->type()->is_error_type());
+      gcc_assert(this->array_->type()->is_error());
       return error_mark_node;
     }
 
@@ -9456,7 +9577,7 @@ String_index_expression::do_type()
   if (this->end_ == NULL)
     return Type::lookup_integer_type("uint8");
   else
-    return Type::make_string_type();
+    return this->string_->type();
 }
 
 // Determine the type of a string index.
@@ -9465,10 +9586,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.
@@ -9768,12 +9888,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,
@@ -9800,9 +9947,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.
@@ -9821,7 +9969,10 @@ Expression::make_map_index(Expression* map, Expression* index,
 Type*
 Field_reference_expression::do_type()
 {
-  Struct_type* struct_type = this->expr_->type()->struct_type();
+  Type* type = this->expr_->type();
+  if (type->is_error())
+    return type;
+  Struct_type* struct_type = type->struct_type();
   gcc_assert(struct_type != NULL);
   return struct_type->field(this->field_index_)->type();
 }
@@ -9831,7 +9982,10 @@ Field_reference_expression::do_type()
 void
 Field_reference_expression::do_check_types(Gogo*)
 {
-  Struct_type* struct_type = this->expr_->type()->struct_type();
+  Type* type = this->expr_->type();
+  if (type->is_error())
+    return;
+  Struct_type* struct_type = type->struct_type();
   gcc_assert(struct_type != NULL);
   gcc_assert(struct_type->field(this->field_index_) != NULL);
 }
@@ -9859,6 +10013,8 @@ Field_reference_expression::do_get_tree(Translate_context* context)
       field = DECL_CHAIN(field);
       gcc_assert(field != NULL_TREE);
     }
+  if (TREE_TYPE(field) == error_mark_node)
+    return error_mark_node;
   return build3(COMPONENT_REF, TREE_TYPE(field), struct_tree, field,
                NULL_TREE);
 }
@@ -10178,7 +10334,14 @@ Selector_expression::lower_method_expression(Gogo* gogo)
   gcc_assert(vno != NULL);
   Expression* ve = Expression::make_var_reference(vno, location);
   Expression* bm = Type::bind_field_or_method(gogo, nt, ve, name, location);
-  gcc_assert(bm != NULL && !bm->is_error_expression());
+
+  // Even though we found the method above, if it has an error type we
+  // may see an error here.
+  if (bm->is_error_expression())
+    {
+      gogo->finish_function(location);
+      return bm;
+    }
 
   Expression_list* args;
   if (method_parameters == NULL)
@@ -10524,6 +10687,10 @@ Struct_construction_expression::do_determine_type(const Type_context*)
          (*pv)->determine_type(&subcontext);
        }
     }
+  // Extra values are an error we will report elsewhere; we still want
+  // to determine the type to avoid knockon errors.
+  for (; pv != this->vals_->end(); ++pv)
+    (*pv)->determine_type_no_context();
 }
 
 // Check types.
@@ -10964,7 +11131,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
   Array_type* array_type = this->type()->array_type();
   if (array_type == NULL)
     {
-      gcc_assert(this->type()->is_error_type());
+      gcc_assert(this->type()->is_error());
       return error_mark_node;
     }
 
@@ -11007,7 +11174,15 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
     return error_mark_node;
 
   bool is_constant_initializer = TREE_CONSTANT(values);
-  bool is_in_function = context->function() != NULL;
+
+  // We have to copy the initial values into heap memory if we are in
+  // a function or if the values are not constants.  We also have to
+  // copy them if they may contain pointers in a non-constant context,
+  // as otherwise the garbage collector won't see them.
+  bool copy_to_heap = (context->function() != NULL
+                      || !is_constant_initializer
+                      || (element_type->has_pointer()
+                          && !context->is_const()));
 
   if (is_constant_initializer)
     {
@@ -11017,12 +11192,12 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
       TREE_PUBLIC(tmp) = 0;
       TREE_STATIC(tmp) = 1;
       DECL_ARTIFICIAL(tmp) = 1;
-      if (is_in_function)
+      if (copy_to_heap)
        {
-         // If this is not a function, we will only initialize the
-         // value once, so we can use this directly rather than
-         // copying it.  In that case we can't make it read-only,
-         // because the program is permitted to change it.
+         // If we are not copying the value to the heap, we will only
+         // initialize the value once, so we can use this directly
+         // rather than copying it.  In that case we can't make it
+         // read-only, because the program is permitted to change it.
          TREE_READONLY(tmp) = 1;
          TREE_CONSTANT(tmp) = 1;
        }
@@ -11033,10 +11208,9 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
 
   tree space;
   tree set;
-  if (!is_in_function && is_constant_initializer)
+  if (!copy_to_heap)
     {
-      // Outside of a function, we know the initializer will only run
-      // once.
+      // the initializer will only run once.
       space = build_fold_addr_expr(values);
       set = NULL_TREE;
     }
@@ -11083,7 +11257,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
   tree constructor = build_constructor(type_tree, init);
   if (constructor == error_mark_node)
     return error_mark_node;
-  if (!is_in_function && is_constant_initializer)
+  if (!copy_to_heap)
     TREE_CONSTANT(constructor) = 1;
 
   if (set == NULL_TREE)
@@ -11426,7 +11600,7 @@ class Composite_literal_expression : public Parser_expression
 
  private:
   Expression*
-  lower_struct(Type*);
+  lower_struct(Gogo*, Type*);
 
   Expression*
   lower_array(Type*);
@@ -11476,7 +11650,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
        type = type->map_type()->val_type();
       else
        {
-         if (!type->is_error_type())
+         if (!type->is_error())
            error_at(this->location(),
                     ("may only omit types within composite literals "
                      "of slice, array, or map type"));
@@ -11484,10 +11658,10 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
        }
     }
 
-  if (type->is_error_type())
+  if (type->is_error())
     return Expression::make_error(this->location());
   else if (type->struct_type() != NULL)
-    return this->lower_struct(type);
+    return this->lower_struct(gogo, type);
   else if (type->array_type() != NULL)
     return this->lower_array(type);
   else if (type->map_type() != NULL)
@@ -11504,7 +11678,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, int)
 // Lower a struct composite literal.
 
 Expression*
-Composite_literal_expression::lower_struct(Type* type)
+Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
 {
   source_location location = this->location();
   Struct_type* st = type->struct_type();
@@ -11532,6 +11706,7 @@ Composite_literal_expression::lower_struct(Type* type)
 
       bool bad_key = false;
       std::string name;
+      const Named_object* no = NULL;
       switch (name_expr->classification())
        {
        case EXPRESSION_UNKNOWN_REFERENCE:
@@ -11539,7 +11714,7 @@ Composite_literal_expression::lower_struct(Type* type)
          break;
 
        case EXPRESSION_CONST_REFERENCE:
-         name = static_cast<Const_expression*>(name_expr)->name();
+         no = static_cast<Const_expression*>(name_expr)->named_object();
          break;
 
        case EXPRESSION_TYPE:
@@ -11549,16 +11724,16 @@ Composite_literal_expression::lower_struct(Type* type)
            if (nt == NULL)
              bad_key = true;
            else
-             name = nt->name();
+             no = nt->named_object();
          }
          break;
 
        case EXPRESSION_VAR_REFERENCE:
-         name = name_expr->var_expression()->name();
+         no = name_expr->var_expression()->named_object();
          break;
 
        case EXPRESSION_FUNC_REFERENCE:
-         name = name_expr->func_expression()->name();
+         no = name_expr->func_expression()->named_object();
          break;
 
        case EXPRESSION_UNARY:
@@ -11606,6 +11781,23 @@ Composite_literal_expression::lower_struct(Type* type)
          return Expression::make_error(location);
        }
 
+      if (no != NULL)
+       {
+         name = no->name();
+
+         // A predefined name won't be packed.  If it starts with a
+         // lower case letter we need to check for that case, because
+         // the field name will be packed.
+         if (!Gogo::is_hidden_name(name)
+             && name[0] >= 'a'
+             && name[0] <= 'z')
+           {
+             Named_object* gno = gogo->lookup_global(name.c_str());
+             if (gno == no)
+               name = gogo->pack_hidden_name(name, false);
+           }
+       }
+
       unsigned int index;
       const Struct_field* sf = st->find_local_field(name, &index);
       if (sf == NULL)
@@ -11666,6 +11858,7 @@ Composite_literal_expression::lower_array(Type* type)
        {
          mpz_t ival;
          mpz_init(ival);
+
          Type* dummy;
          if (!index_expr->integer_constant_value(true, ival, &dummy))
            {
@@ -11674,12 +11867,14 @@ Composite_literal_expression::lower_array(Type* type)
                       "index expression is not integer constant");
              return Expression::make_error(location);
            }
+
          if (mpz_sgn(ival) < 0)
            {
              mpz_clear(ival);
              error_at(index_expr->location(), "index expression is negative");
              return Expression::make_error(location);
            }
+
          index = mpz_get_ui(ival);
          if (mpz_cmp_ui(ival, index) != 0)
            {
@@ -11687,7 +11882,30 @@ Composite_literal_expression::lower_array(Type* type)
              error_at(index_expr->location(), "index value overflow");
              return Expression::make_error(location);
            }
+
+         Named_type* ntype = Type::lookup_integer_type("int");
+         Integer_type* inttype = ntype->integer_type();
+         mpz_t max;
+         mpz_init_set_ui(max, 1);
+         mpz_mul_2exp(max, max, inttype->bits() - 1);
+         bool ok = mpz_cmp(ival, max) < 0;
+         mpz_clear(max);
+         if (!ok)
+           {
+             mpz_clear(ival);
+             error_at(index_expr->location(), "index value overflow");
+             return Expression::make_error(location);
+           }
+
          mpz_clear(ival);
+
+         // FIXME: Our representation isn't very good; this avoids
+         // thrashing.
+         if (index > 0x1000000)
+           {
+             error_at(index_expr->location(), "index too large for compiler");
+             return Expression::make_error(location);
+           }
        }
 
       if (index == vals.size())
@@ -11905,7 +12123,7 @@ Type_guard_expression::do_check_types(Gogo*)
     }
   else if (expr_type->interface_type() == NULL)
     {
-      if (!expr_type->is_error_type() && !this->type_->is_error_type())
+      if (!expr_type->is_error() && !this->type_->is_error())
        this->report_error(_("type assertion only valid for interface types"));
       this->set_is_error();
     }
@@ -11915,7 +12133,7 @@ Type_guard_expression::do_check_types(Gogo*)
       if (!expr_type->interface_type()->implements_interface(this->type_,
                                                             &reason))
        {
-         if (!this->type_->is_error_type())
+         if (!this->type_->is_error())
            {
              if (reason.empty())
                this->report_error(_("impossible type assertion: "
@@ -12067,7 +12285,7 @@ void
 Receive_expression::do_check_types(Gogo*)
 {
   Type* type = this->channel_->type();
-  if (type->is_error_type())
+  if (type->is_error())
     {
       this->set_is_error();
       return;
@@ -12090,7 +12308,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());
+      return error_mark_node;
+    }
   Type* element_type = channel_type->element_type();
   tree element_type_tree = element_type->get_tree(context->gogo());
 
@@ -12110,100 +12332,6 @@ Expression::make_receive(Expression* channel, source_location location)
   return new Receive_expression(channel, location);
 }
 
-// Class Send_expression.
-
-// Traversal.
-
-int
-Send_expression::do_traverse(Traverse* traverse)
-{
-  if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
-    return TRAVERSE_EXIT;
-  return Expression::traverse(&this->val_, traverse);
-}
-
-// Get the type.
-
-Type*
-Send_expression::do_type()
-{
-  return Type::lookup_bool_type();
-}
-
-// Set types.
-
-void
-Send_expression::do_determine_type(const Type_context*)
-{
-  this->channel_->determine_type_no_context();
-
-  Type* type = this->channel_->type();
-  Type_context subcontext;
-  if (type->channel_type() != NULL)
-    subcontext.type = type->channel_type()->element_type();
-  this->val_->determine_type(&subcontext);
-}
-
-// Check types.
-
-void
-Send_expression::do_check_types(Gogo*)
-{
-  Type* type = this->channel_->type();
-  if (type->is_error_type())
-    {
-      this->set_is_error();
-      return;
-    }
-  Channel_type* channel_type = type->channel_type();
-  if (channel_type == NULL)
-    {
-      error_at(this->location(), "left operand of %<<-%> must be channel");
-      this->set_is_error();
-      return;
-    }
-  Type* element_type = channel_type->element_type();
-  if (element_type != NULL
-      && !Type::are_assignable(element_type, this->val_->type(), NULL))
-    {
-      this->report_error(_("incompatible types in send"));
-      return;
-    }
-  if (!channel_type->may_send())
-    {
-      this->report_error(_("invalid send on receive-only channel"));
-      return;
-    }
-}
-
-// Get a tree for a send expression.
-
-tree
-Send_expression::do_get_tree(Translate_context* context)
-{
-  tree channel = this->channel_->get_tree(context);
-  tree val = this->val_->get_tree(context);
-  if (channel == error_mark_node || val == error_mark_node)
-    return error_mark_node;
-  Channel_type* channel_type = this->channel_->type()->channel_type();
-  val = Expression::convert_for_assignment(context,
-                                          channel_type->element_type(),
-                                          this->val_->type(),
-                                          val,
-                                          this->location());
-  return Gogo::send_on_channel(channel, val, this->is_value_discarded_,
-                              this->for_select_, this->location());
-}
-
-// Make a send expression
-
-Send_expression*
-Expression::make_send(Expression* channel, Expression* val,
-                     source_location location)
-{
-  return new Send_expression(channel, val, location);
-}
-
 // An expression which evaluates to a pointer to the type descriptor
 // of a type.