OSDN Git Service

compiler: No error if shift operand inherits interface type.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / expressions.cc
index e6d1a0d..3fa1cd6 100644 (file)
@@ -6,6 +6,8 @@
 
 #include "go-system.h"
 
+#include <algorithm>
+
 #include <gmp.h>
 
 #ifndef ENABLE_BUILD_WITH_CXX
@@ -166,7 +168,8 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
   if (lhs_type_tree == error_mark_node)
     return error_mark_node;
 
-  if (lhs_type != rhs_type && lhs_type->interface_type() != NULL)
+  if (lhs_type->forwarded() != rhs_type->forwarded()
+      && lhs_type->interface_type() != NULL)
     {
       if (rhs_type->interface_type() == NULL)
        return Expression::convert_type_to_interface(context, lhs_type,
@@ -177,7 +180,8 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
                                                          rhs_type, rhs_tree,
                                                          false, location);
     }
-  else if (lhs_type != rhs_type && rhs_type->interface_type() != NULL)
+  else if (lhs_type->forwarded() != rhs_type->forwarded()
+          && rhs_type->interface_type() != NULL)
     return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
                                                 rhs_tree, location);
   else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
@@ -297,19 +301,25 @@ Expression::convert_type_to_interface(Translate_context* context,
       // object type: a list of function pointers for each interface
       // method.
       Named_type* rhs_named_type = rhs_type->named_type();
+      Struct_type* rhs_struct_type = rhs_type->struct_type();
       bool is_pointer = false;
-      if (rhs_named_type == NULL)
+      if (rhs_named_type == NULL && rhs_struct_type == NULL)
        {
          rhs_named_type = rhs_type->deref()->named_type();
+         rhs_struct_type = rhs_type->deref()->struct_type();
          is_pointer = true;
        }
       tree method_table;
-      if (rhs_named_type == NULL)
-       method_table = null_pointer_node;
-      else
+      if (rhs_named_type != NULL)
        method_table =
          rhs_named_type->interface_method_table(gogo, lhs_interface_type,
                                                 is_pointer);
+      else if (rhs_struct_type != NULL)
+       method_table =
+         rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
+                                                 is_pointer);
+      else
+       method_table = null_pointer_node;
       first_field_value = fold_convert_loc(location.gcc_location(),
                                            const_ptr_type_node, method_table);
     }
@@ -1310,30 +1320,18 @@ Func_expression::do_get_tree(Translate_context* context)
             && TREE_CODE(TREE_OPERAND(fnaddr, 0)) == FUNCTION_DECL);
   TREE_ADDRESSABLE(TREE_OPERAND(fnaddr, 0)) = 1;
 
-  // For a normal non-nested function call, that is all we have to do.
-  if (!this->function_->is_function()
-      || this->function_->func_value()->enclosing() == NULL)
-    {
-      go_assert(this->closure_ == NULL);
-      return fnaddr;
-    }
+  // If there is no closure, that is all have to do.
+  if (this->closure_ == NULL)
+    return fnaddr;
 
-  // For a nested function call, we have to always allocate a
-  // trampoline.  If we don't always allocate, then closures will not
-  // be reliably distinct.
-  Expression* closure = this->closure_;
-  tree closure_tree;
-  if (closure == NULL)
-    closure_tree = null_pointer_node;
-  else
-    {
-      // Get the value of the closure.  This will be a pointer to
-      // space allocated on the heap.
-      closure_tree = closure->get_tree(context);
-      if (closure_tree == error_mark_node)
-       return error_mark_node;
-      go_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree)));
-    }
+  go_assert(this->function_->func_value()->enclosing() != NULL);
+
+  // Get the value of the closure.  This will be a pointer to space
+  // allocated on the heap.
+  tree closure_tree = this->closure_->get_tree(context);
+  if (closure_tree == error_mark_node)
+    return error_mark_node;
+  go_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree)));
 
   // Now we need to build some code on the heap.  This code will load
   // the static chain pointer with the closure and then jump to the
@@ -3604,8 +3602,7 @@ Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
       return Expression::make_error(this->location());
     }
 
-  if (op == OPERATOR_PLUS || op == OPERATOR_MINUS
-      || op == OPERATOR_NOT || op == OPERATOR_XOR)
+  if (op == OPERATOR_PLUS || op == OPERATOR_MINUS || op == OPERATOR_XOR)
     {
       Numeric_constant nc;
       if (expr->numeric_constant_value(&nc))
@@ -3695,10 +3692,10 @@ Unary_expression::eval_constant(Operator op, const Numeric_constant* unc,
       else
        go_unreachable();
 
-    case OPERATOR_NOT:
     case OPERATOR_XOR:
       break;
 
+    case OPERATOR_NOT:
     case OPERATOR_AND:
     case OPERATOR_MULT:
       return false;
@@ -3711,7 +3708,10 @@ Unary_expression::eval_constant(Operator op, const Numeric_constant* unc,
     return false;
 
   mpz_t uval;
-  unc->get_int(&uval);
+  if (unc->is_rune())
+    unc->get_rune(&uval);
+  else
+    unc->get_int(&uval);
   mpz_t val;
   mpz_init(val);
 
@@ -3909,6 +3909,10 @@ Unary_expression::do_check_types(Gogo*)
       break;
 
     case OPERATOR_NOT:
+      if (!type->is_boolean_type())
+       this->report_error(_("expected boolean type"));
+      break;
+
     case OPERATOR_XOR:
       if (type->integer_type() == NULL
          && !type->is_boolean_type())
@@ -4036,19 +4040,50 @@ Unary_expression::do_get_tree(Translate_context* context)
 
       if (this->create_temp_
          && !TREE_ADDRESSABLE(TREE_TYPE(expr))
-         && !DECL_P(expr)
+         && (TREE_CODE(expr) == CONST_DECL || !DECL_P(expr))
          && TREE_CODE(expr) != INDIRECT_REF
          && TREE_CODE(expr) != COMPONENT_REF)
        {
-         tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
-         DECL_IGNORED_P(tmp) = 1;
-         DECL_INITIAL(tmp) = expr;
-         TREE_ADDRESSABLE(tmp) = 1;
-         return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
-                           build_pointer_type(TREE_TYPE(expr)),
-                           build1_loc(loc.gcc_location(), DECL_EXPR,
-                                       void_type_node, tmp),
-                           build_fold_addr_expr_loc(loc.gcc_location(), tmp));
+         if (current_function_decl != NULL)
+           {
+             tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
+             DECL_IGNORED_P(tmp) = 1;
+             DECL_INITIAL(tmp) = expr;
+             TREE_ADDRESSABLE(tmp) = 1;
+             return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
+                               build_pointer_type(TREE_TYPE(expr)),
+                               build1_loc(loc.gcc_location(), DECL_EXPR,
+                                          void_type_node, tmp),
+                               build_fold_addr_expr_loc(loc.gcc_location(),
+                                                        tmp));
+           }
+         else
+           {
+             tree tmp = build_decl(loc.gcc_location(), VAR_DECL,
+                                   create_tmp_var_name("A"), TREE_TYPE(expr));
+             DECL_EXTERNAL(tmp) = 0;
+             TREE_PUBLIC(tmp) = 0;
+             TREE_STATIC(tmp) = 1;
+             DECL_ARTIFICIAL(tmp) = 1;
+             TREE_ADDRESSABLE(tmp) = 1;
+             tree make_tmp;
+             if (!TREE_CONSTANT(expr))
+               make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR,
+                                          void_type_node, tmp, expr);
+             else
+               {
+                 TREE_READONLY(tmp) = 1;
+                 TREE_CONSTANT(tmp) = 1;
+                 DECL_INITIAL(tmp) = expr;
+                 make_tmp = NULL_TREE;
+               }
+             rest_of_decl_compilation(tmp, 1, 0);
+             tree addr = build_fold_addr_expr_loc(loc.gcc_location(), tmp);
+             if (make_tmp == NULL_TREE)
+               return addr;
+             return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
+                               TREE_TYPE(addr), make_tmp, addr);
+           }
        }
 
       return build_fold_addr_expr_loc(loc.gcc_location(), expr);
@@ -4448,9 +4483,8 @@ Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc,
     case OPERATOR_LE:
     case OPERATOR_GT:
     case OPERATOR_GE:
-      // These return boolean values and as such must be handled
-      // elsewhere.
-      go_unreachable();
+      // These return boolean values, not numeric.
+      return false;
     default:
       break;
     }
@@ -5056,7 +5090,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
                                                     &right_nc, location,
                                                     &result))
              return this;
-           return Expression::make_cast(Type::lookup_bool_type(),
+           return Expression::make_cast(Type::make_boolean_type(),
                                         Expression::make_boolean(result,
                                                                  location),
                                         location);
@@ -5087,10 +5121,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
            {
              int cmp = left_string.compare(right_string);
              bool r = Binary_expression::cmp_to_bool(op, cmp);
-             return Expression::make_cast(Type::lookup_bool_type(),
-                                          Expression::make_boolean(r,
-                                                                   location),
-                                          location);
+             return Expression::make_boolean(r, location);
            }
        }
     }
@@ -5159,6 +5190,9 @@ Binary_expression::lower_struct_comparison(Gogo* gogo,
        pf != fields->end();
        ++pf, ++field_index)
     {
+      if (Gogo::is_sink_name(pf->field_name()))
+       continue;
+
       if (field_index > 0)
        {
          if (left_temp == NULL)
@@ -5277,24 +5311,13 @@ Binary_expression::operand_address(Statement_inserter* inserter,
 bool
 Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const
 {
-  Operator op = this->op_;
-
-  if (op == OPERATOR_EQEQ
-      || op == OPERATOR_NOTEQ
-      || op == OPERATOR_LT
-      || op == OPERATOR_LE
-      || op == OPERATOR_GT
-      || op == OPERATOR_GE)
-    return false;
-
   Numeric_constant left_nc;
   if (!this->left_->numeric_constant_value(&left_nc))
     return false;
   Numeric_constant right_nc;
   if (!this->right_->numeric_constant_value(&right_nc))
     return false;
-
-  return Binary_expression::eval_constant(op, &left_nc, &right_nc,
+  return Binary_expression::eval_constant(this->op_, &left_nc, &right_nc,
                                          this->location(), nc);
 }
 
@@ -5319,15 +5342,15 @@ Binary_expression::do_type()
 
   switch (this->op_)
     {
-    case OPERATOR_OROR:
-    case OPERATOR_ANDAND:
     case OPERATOR_EQEQ:
     case OPERATOR_NOTEQ:
     case OPERATOR_LT:
     case OPERATOR_LE:
     case OPERATOR_GT:
     case OPERATOR_GE:
-      return Type::lookup_bool_type();
+      if (this->type_ == NULL)
+       this->type_ = Type::make_boolean_type();
+      return this->type_;
 
     case OPERATOR_PLUS:
     case OPERATOR_MINUS:
@@ -5338,6 +5361,8 @@ Binary_expression::do_type()
     case OPERATOR_MOD:
     case OPERATOR_AND:
     case OPERATOR_BITCLEAR:
+    case OPERATOR_OROR:
+    case OPERATOR_ANDAND:
       {
        Type* type;
        if (!Binary_expression::operation_type(this->op_,
@@ -5434,7 +5459,8 @@ Binary_expression::do_determine_type(const Type_context* context)
          && (this->left_->type()->integer_type() == NULL
              || (subcontext.type->integer_type() == NULL
                  && subcontext.type->float_type() == NULL
-                 && subcontext.type->complex_type() == NULL)))
+                 && subcontext.type->complex_type() == NULL
+                 && subcontext.type->interface_type() == NULL)))
        this->report_error(("invalid context-determined non-integer type "
                            "for shift operand"));
 
@@ -5445,6 +5471,16 @@ Binary_expression::do_determine_type(const Type_context* context)
     }
 
   this->right_->determine_type(&subcontext);
+
+  if (is_comparison)
+    {
+      if (this->type_ != NULL && !this->type_->is_abstract())
+       ;
+      else if (context->type != NULL && context->type->is_boolean_type())
+       this->type_ = context->type;
+      else if (!context->may_be_abstract)
+       this->type_ = Type::lookup_bool_type();
+    }
 }
 
 // Report an error if the binary operator OP does not support TYPE.
@@ -5656,7 +5692,7 @@ Binary_expression::do_get_tree(Translate_context* context)
     case OPERATOR_LE:
     case OPERATOR_GT:
     case OPERATOR_GE:
-      return Expression::comparison_tree(context, this->op_,
+      return Expression::comparison_tree(context, this->type_, this->op_,
                                         this->left_->type(), left,
                                         this->right_->type(), right,
                                         this->location());
@@ -6117,8 +6153,8 @@ Expression::make_binary(Operator op, Expression* left, Expression* right,
 // Implement a comparison.
 
 tree
-Expression::comparison_tree(Translate_context* context, Operator op,
-                           Type* left_type, tree left_tree,
+Expression::comparison_tree(Translate_context* context, Type* result_type,
+                           Operator op, Type* left_type, tree left_tree,
                            Type* right_type, tree right_tree,
                            Location location)
 {
@@ -6186,7 +6222,9 @@ Expression::comparison_tree(Translate_context* context, Operator op,
          make_tmp = NULL_TREE;
          arg = right_tree;
        }
-      else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree)) || DECL_P(right_tree))
+      else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree))
+              || (TREE_CODE(right_tree) != CONST_DECL
+                  && DECL_P(right_tree)))
        {
          make_tmp = NULL_TREE;
          arg = build_fold_addr_expr_loc(location.gcc_location(), right_tree);
@@ -6357,7 +6395,13 @@ Expression::comparison_tree(Translate_context* context, Operator op,
   if (left_tree == error_mark_node || right_tree == error_mark_node)
     return error_mark_node;
 
-  tree ret = fold_build2(code, boolean_type_node, left_tree, right_tree);
+  tree result_type_tree;
+  if (result_type == NULL)
+    result_type_tree = boolean_type_node;
+  else
+    result_type_tree = type_to_tree(result_type->get_backend(context->gogo()));
+
+  tree ret = fold_build2(code, result_type_tree, left_tree, right_tree);
   if (CAN_HAVE_LOCATION_P(ret))
     SET_EXPR_LOCATION(ret, location.gcc_location());
   return ret;
@@ -6648,38 +6692,6 @@ Builtin_call_expression::do_set_recover_arg(Expression* arg)
   this->set_args(new_args);
 }
 
-// A traversal class which looks for a call expression.
-
-class Find_call_expression : public Traverse
-{
- public:
-  Find_call_expression()
-    : Traverse(traverse_expressions),
-      found_(false)
-  { }
-
-  int
-  expression(Expression**);
-
-  bool
-  found()
-  { return this->found_; }
-
- private:
-  bool found_;
-};
-
-int
-Find_call_expression::expression(Expression** pexpr)
-{
-  if ((*pexpr)->call_expression() != NULL)
-    {
-      this->found_ = true;
-      return TRAVERSE_EXIT;
-    }
-  return TRAVERSE_CONTINUE;
-}
-
 // Lower a builtin call expression.  This turns new and make into
 // specific expressions.  We also convert to a constant if we can.
 
@@ -6700,20 +6712,6 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
 
   if (this->is_constant())
     {
-      // We can only lower len and cap if there are no function calls
-      // in the arguments.  Otherwise we have to make the call.
-      if (this->code_ == BUILTIN_LEN || this->code_ == BUILTIN_CAP)
-       {
-         Expression* arg = this->one_arg();
-         if (arg != NULL && !arg->is_constant())
-           {
-             Find_call_expression find_call;
-             Expression::traverse(&arg, &find_call);
-             if (find_call.found())
-               return this;
-           }
-       }
-
       Numeric_constant nc;
       if (this->numeric_constant_value(&nc))
        return nc.expression(loc);
@@ -7030,8 +7028,42 @@ Builtin_call_expression::one_arg() const
   return args->front();
 }
 
-// Return whether this is constant: len of a string, or len or cap of
-// a fixed array, or unsafe.Sizeof, unsafe.Offsetof, unsafe.Alignof.
+// A traversal class which looks for a call or receive expression.
+
+class Find_call_expression : public Traverse
+{
+ public:
+  Find_call_expression()
+    : Traverse(traverse_expressions),
+      found_(false)
+  { }
+
+  int
+  expression(Expression**);
+
+  bool
+  found()
+  { return this->found_; }
+
+ private:
+  bool found_;
+};
+
+int
+Find_call_expression::expression(Expression** pexpr)
+{
+  if ((*pexpr)->call_expression() != NULL
+      || (*pexpr)->receive_expression() != NULL)
+    {
+      this->found_ = true;
+      return TRAVERSE_EXIT;
+    }
+  return TRAVERSE_CONTINUE;
+}
+
+// Return whether this is constant: len of a string constant, or len
+// or cap of an array, or unsafe.Sizeof, unsafe.Offsetof,
+// unsafe.Alignof.
 
 bool
 Builtin_call_expression::do_is_constant() const
@@ -7054,6 +7086,17 @@ Builtin_call_expression::do_is_constant() const
            && !arg_type->points_to()->is_slice_type())
          arg_type = arg_type->points_to();
 
+       // The len and cap functions are only constant if there are no
+       // function calls or channel operations in the arguments.
+       // Otherwise we have to make the call.
+       if (!arg->is_constant())
+         {
+           Find_call_expression find_call;
+           Expression::traverse(&arg, &find_call);
+           if (find_call.found())
+             return false;
+         }
+
        if (arg_type->array_type() != NULL
            && arg_type->array_type()->length() != NULL)
          return true;
@@ -7440,7 +7483,7 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
        if (args != NULL && args->size() == 2)
          {
            Type* t1 = args->front()->type();
-           Type* t2 = args->front()->type();
+           Type* t2 = args->back()->type();
            if (!t1->is_abstract())
              arg_type = t1;
            else if (!t2->is_abstract())
@@ -9223,7 +9266,7 @@ Call_expression::set_results(Translate_context* context, tree call_tree)
       ref->set_is_lvalue();
       tree temp_tree = ref->get_tree(context);
       if (temp_tree == error_mark_node)
-       continue;
+       return error_mark_node;
 
       tree val_tree = build3_loc(loc.gcc_location(), COMPONENT_REF,
                                  TREE_TYPE(field), call_tree, field, NULL_TREE);
@@ -11392,11 +11435,12 @@ class Array_construction_expression : public Expression
 {
  protected:
   Array_construction_expression(Expression_classification classification,
-                               Type* type, Expression_list* vals,
-                               Location location)
+                               Type* type,
+                               const std::vector<unsigned long>* indexes,
+                               Expression_list* vals, Location location)
     : Expression(classification, location),
-      type_(type), vals_(vals)
-  { }
+      type_(type), indexes_(indexes), vals_(vals)
+  { go_assert(indexes == NULL || indexes->size() == vals->size()); }
 
  public:
   // Return whether this is a constant initializer.
@@ -11425,6 +11469,11 @@ protected:
   void
   do_export(Export*) const;
 
+  // The indexes.
+  const std::vector<unsigned long>*
+  indexes()
+  { return this->indexes_; }
+
   // The list of values.
   Expression_list*
   vals()
@@ -11440,7 +11489,10 @@ protected:
  private:
   // The type of the array to construct.
   Type* type_;
-  // The list of values.
+  // The list of indexes into the array, one for each value.  This may
+  // be NULL, in which case the indexes start at zero and increment.
+  const std::vector<unsigned long>* indexes_;
+  // The list of values.  This may be NULL if there are no values.
   Expression_list* vals_;
 };
 
@@ -11523,18 +11575,6 @@ Array_construction_expression::do_check_types(Gogo*)
          this->set_is_error();
        }
     }
-
-  Expression* length = at->length();
-  Numeric_constant nc;
-  unsigned long val;
-  if (length != NULL
-      && !length->is_error_expression()
-      && length->numeric_constant_value(&nc)
-      && nc.to_unsigned_long(&val) == Numeric_constant::NC_UL_VALID)
-    {
-      if (this->vals_->size() > val)
-       this->report_error(_("too many elements in composite literal"));
-    }
 }
 
 // Get a constructor tree for the array values.
@@ -11552,12 +11592,22 @@ Array_construction_expression::get_constructor_tree(Translate_context* context,
   if (this->vals_ != NULL)
     {
       size_t i = 0;
+      std::vector<unsigned long>::const_iterator pi;
+      if (this->indexes_ != NULL)
+       pi = this->indexes_->begin();
       for (Expression_list::const_iterator pv = this->vals_->begin();
           pv != this->vals_->end();
           ++pv, ++i)
        {
+         if (this->indexes_ != NULL)
+           go_assert(pi != this->indexes_->end());
          constructor_elt* elt = VEC_quick_push(constructor_elt, values, NULL);
-         elt->index = size_int(i);
+
+         if (this->indexes_ == NULL)
+           elt->index = size_int(i);
+         else
+           elt->index = size_int(*pi);
+
          if (*pv == NULL)
            {
              Gogo* gogo = context->gogo();
@@ -11578,7 +11628,11 @@ Array_construction_expression::get_constructor_tree(Translate_context* context,
            return error_mark_node;
          if (!TREE_CONSTANT(elt->value))
            is_constant = false;
+         if (this->indexes_ != NULL)
+           ++pi;
        }
+      if (this->indexes_ != NULL)
+       go_assert(pi == this->indexes_->end());
     }
 
   tree ret = build_constructor(type_tree, values);
@@ -11596,13 +11650,28 @@ Array_construction_expression::do_export(Export* exp) const
   exp->write_type(this->type_);
   if (this->vals_ != NULL)
     {
+      std::vector<unsigned long>::const_iterator pi;
+      if (this->indexes_ != NULL)
+       pi = this->indexes_->begin();
       for (Expression_list::const_iterator pv = this->vals_->begin();
           pv != this->vals_->end();
           ++pv)
        {
          exp->write_c_string(", ");
+
+         if (this->indexes_ != NULL)
+           {
+             char buf[100];
+             snprintf(buf, sizeof buf, "%lu", *pi);
+             exp->write_c_string(buf);
+             exp->write_c_string(":");
+           }
+
          if (*pv != NULL)
            (*pv)->export_expression(exp);
+
+         if (this->indexes_ != NULL)
+           ++pi;
        }
     }
   exp->write_c_string(")");
@@ -11614,8 +11683,7 @@ void
 Array_construction_expression::do_dump_expression(
     Ast_dump_context* ast_dump_context) const
 {
-  Expression* length = this->type_->array_type() != NULL ?
-                        this->type_->array_type()->length() : NULL;
+  Expression* length = this->type_->array_type()->length();
 
   ast_dump_context->ostream() << "[" ;
   if (length != NULL)
@@ -11625,7 +11693,22 @@ Array_construction_expression::do_dump_expression(
   ast_dump_context->ostream() << "]" ;
   ast_dump_context->dump_type(this->type_);
   ast_dump_context->ostream() << "{" ;
-  ast_dump_context->dump_expression_list(this->vals_);
+  if (this->indexes_ == NULL)
+    ast_dump_context->dump_expression_list(this->vals_);
+  else
+    {
+      Expression_list::const_iterator pv = this->vals_->begin();
+      for (std::vector<unsigned long>::const_iterator pi =
+            this->indexes_->begin();
+          pi != this->indexes_->end();
+          ++pi, ++pv)
+       {
+         if (pi != this->indexes_->begin())
+           ast_dump_context->ostream() << ", ";
+         ast_dump_context->ostream() << *pi << ':';
+         ast_dump_context->dump_expression(*pv);
+       }
+    }
   ast_dump_context->ostream() << "}" ;
 
 }
@@ -11636,20 +11719,19 @@ class Fixed_array_construction_expression :
   public Array_construction_expression
 {
  public:
-  Fixed_array_construction_expression(Type* type, Expression_list* vals,
-                                     Location location)
+  Fixed_array_construction_expression(Type* type,
+                                     const std::vector<unsigned long>* indexes,
+                                     Expression_list* vals, Location location)
     : Array_construction_expression(EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
-                                   type, vals, location)
-  {
-    go_assert(type->array_type() != NULL
-              && type->array_type()->length() != NULL);
-  }
+                                   type, indexes, vals, location)
+  { go_assert(type->array_type() != NULL && !type->is_slice_type()); }
 
  protected:
   Expression*
   do_copy()
   {
     return new Fixed_array_construction_expression(this->type(),
+                                                  this->indexes(),
                                                   (this->vals() == NULL
                                                    ? NULL
                                                    : this->vals()->copy()),
@@ -11658,9 +11740,6 @@ class Fixed_array_construction_expression :
 
   tree
   do_get_tree(Translate_context*);
-
-  void
-  do_dump_expression(Ast_dump_context*);
 };
 
 // Return a tree for constructing a fixed array.
@@ -11673,35 +11752,17 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context)
   return this->get_constructor_tree(context, type_to_tree(btype));
 }
 
-// Dump ast representation of an array construction expressin.
-
-void
-Fixed_array_construction_expression::do_dump_expression(
-    Ast_dump_context* ast_dump_context)
-{
-
-  ast_dump_context->ostream() << "[";
-  ast_dump_context->dump_expression (this->type()->array_type()->length());
-  ast_dump_context->ostream() << "]";
-  ast_dump_context->dump_type(this->type());
-  ast_dump_context->ostream() << "{";
-  ast_dump_context->dump_expression_list(this->vals());
-  ast_dump_context->ostream() << "}";
-
-}
 // Construct an open array.
 
 class Open_array_construction_expression : public Array_construction_expression
 {
  public:
-  Open_array_construction_expression(Type* type, Expression_list* vals,
-                                    Location location)
+  Open_array_construction_expression(Type* type,
+                                    const std::vector<unsigned long>* indexes,
+                                    Expression_list* vals, Location location)
     : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
-                                   type, vals, location)
-  {
-    go_assert(type->array_type() != NULL
-              && type->array_type()->length() == NULL);
-  }
+                                   type, indexes, vals, location)
+  { go_assert(type->is_slice_type()); }
 
  protected:
   // Note that taking the address of an open array literal is invalid.
@@ -11710,6 +11771,7 @@ class Open_array_construction_expression : public Array_construction_expression
   do_copy()
   {
     return new Open_array_construction_expression(this->type(),
+                                                 this->indexes(),
                                                  (this->vals() == NULL
                                                   ? NULL
                                                   : this->vals()->copy()),
@@ -11761,13 +11823,18 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
     }
   else
     {
-      tree max = size_int(this->vals()->size() - 1);
+      unsigned long max_index;
+      if (this->indexes() == NULL)
+       max_index = this->vals()->size() - 1;
+      else
+       max_index = this->indexes()->back();
+      tree max_tree = size_int(max_index);
       tree constructor_type = build_array_type(element_type_tree,
-                                              build_index_type(max));
+                                              build_index_type(max_tree));
       if (constructor_type == error_mark_node)
        return error_mark_node;
       values = this->get_constructor_tree(context, constructor_type);
-      length_tree = size_int(this->vals()->size());
+      length_tree = size_int(max_index + 1);
     }
 
   if (values == error_mark_node)
@@ -11875,7 +11942,7 @@ Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
                                         Location location)
 {
   go_assert(type->is_slice_type());
-  return new Open_array_construction_expression(type, vals, location);
+  return new Open_array_construction_expression(type, NULL, vals, location);
 }
 
 // Construct a map.
@@ -12229,7 +12296,7 @@ class Composite_literal_expression : public Parser_expression
   lower_array(Type*);
 
   Expression*
-  make_array(Type*, Expression_list*);
+  make_array(Type*, const std::vector<unsigned long>*, Expression_list*);
 
   Expression*
   lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);
@@ -12511,6 +12578,17 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
   return ret;
 }
 
+// Used to sort an index/value array.
+
+class Index_value_compare
+{
+ public:
+  bool
+  operator()(const std::pair<unsigned long, Expression*>& a,
+            const std::pair<unsigned long, Expression*>& b)
+  { return a.first < b.first; }
+};
+
 // Lower an array composite literal.
 
 Expression*
@@ -12518,10 +12596,13 @@ Composite_literal_expression::lower_array(Type* type)
 {
   Location location = this->location();
   if (this->vals_ == NULL || !this->has_keys_)
-    return this->make_array(type, this->vals_);
+    return this->make_array(type, NULL, this->vals_);
 
-  std::vector<Expression*> vals;
-  vals.reserve(this->vals_->size());
+  std::vector<unsigned long>* indexes = new std::vector<unsigned long>;
+  indexes->reserve(this->vals_->size());
+  bool indexes_out_of_order = false;
+  Expression_list* vals = new Expression_list();
+  vals->reserve(this->vals_->size());
   unsigned long index = 0;
   Expression_list::const_iterator p = this->vals_->begin();
   while (p != this->vals_->end())
@@ -12534,8 +12615,19 @@ Composite_literal_expression::lower_array(Type* type)
 
       ++p;
 
-      if (index_expr != NULL)
+      if (index_expr == NULL)
+       {
+         if (!indexes->empty())
+           indexes->push_back(index);
+       }
+      else
        {
+         if (indexes->empty() && !vals->empty())
+           {
+             for (size_t i = 0; i < vals->size(); ++i)
+               indexes->push_back(i);
+           }
+
          Numeric_constant nc;
          if (!index_expr->numeric_constant_value(&nc))
            {
@@ -12571,59 +12663,93 @@ Composite_literal_expression::lower_array(Type* type)
              return Expression::make_error(location);
            }
 
-         // FIXME: Our representation isn't very good; this avoids
-         // thrashing.
-         if (index > 0x1000000)
+         if (std::find(indexes->begin(), indexes->end(), index)
+             != indexes->end())
            {
-             error_at(index_expr->location(), "index too large for compiler");
-             return Expression::make_error(location);
-           }
-       }
-
-      if (index == vals.size())
-       vals.push_back(val);
-      else
-       {
-         if (index > vals.size())
-           {
-             vals.reserve(index + 32);
-             vals.resize(index + 1, static_cast<Expression*>(NULL));
-           }
-         if (vals[index] != NULL)
-           {
-             error_at((index_expr != NULL
-                       ? index_expr->location()
-                       : val->location()),
-                      "duplicate value for index %lu",
+             error_at(index_expr->location(), "duplicate value for index %lu",
                       index);
              return Expression::make_error(location);
            }
-         vals[index] = val;
+
+         if (!indexes->empty() && index < indexes->back())
+           indexes_out_of_order = true;
+
+         indexes->push_back(index);
        }
 
+      vals->push_back(val);
+
       ++index;
     }
 
-  size_t size = vals.size();
-  Expression_list* list = new Expression_list;
-  list->reserve(size);
-  for (size_t i = 0; i < size; ++i)
-    list->push_back(vals[i]);
+  if (indexes->empty())
+    {
+      delete indexes;
+      indexes = NULL;
+    }
+
+  if (indexes_out_of_order)
+    {
+      typedef std::vector<std::pair<unsigned long, Expression*> > V;
+
+      V v;
+      v.reserve(indexes->size());
+      std::vector<unsigned long>::const_iterator pi = indexes->begin();
+      for (Expression_list::const_iterator pe = vals->begin();
+          pe != vals->end();
+          ++pe, ++pi)
+       v.push_back(std::make_pair(*pi, *pe));
 
-  return this->make_array(type, list);
+      std::sort(v.begin(), v.end(), Index_value_compare());
+
+      delete indexes;
+      delete vals;
+      indexes = new std::vector<unsigned long>();
+      indexes->reserve(v.size());
+      vals = new Expression_list();
+      vals->reserve(v.size());
+
+      for (V::const_iterator p = v.begin(); p != v.end(); ++p)
+       {
+         indexes->push_back(p->first);
+         vals->push_back(p->second);
+       }
+    }
+
+  return this->make_array(type, indexes, vals);
 }
 
 // Actually build the array composite literal. This handles
 // [...]{...}.
 
 Expression*
-Composite_literal_expression::make_array(Type* type, Expression_list* vals)
+Composite_literal_expression::make_array(
+    Type* type,
+    const std::vector<unsigned long>* indexes,
+    Expression_list* vals)
 {
   Location location = this->location();
   Array_type* at = type->array_type();
+
   if (at->length() != NULL && at->length()->is_nil_expression())
     {
-      size_t size = vals == NULL ? 0 : vals->size();
+      size_t size;
+      if (vals == NULL)
+       size = 0;
+      else if (indexes != NULL)
+       size = indexes->back() + 1;
+      else
+       {
+         size = vals->size();
+         Integer_type* it = Type::lookup_integer_type("int")->integer_type();
+         if (sizeof(size) <= static_cast<size_t>(it->bits() * 8)
+             && size >> (it->bits() - 1) != 0)
+           {
+             error_at(location, "too many elements in composite literal");
+             return Expression::make_error(location);
+           }
+       }
+
       mpz_t vlen;
       mpz_init_set_ui(vlen, size);
       Expression* elen = Expression::make_integer(&vlen, NULL, location);
@@ -12631,10 +12757,43 @@ Composite_literal_expression::make_array(Type* type, Expression_list* vals)
       at = Type::make_array_type(at->element_type(), elen);
       type = at;
     }
+  else if (at->length() != NULL
+          && !at->length()->is_error_expression()
+          && this->vals_ != NULL)
+    {
+      Numeric_constant nc;
+      unsigned long val;
+      if (at->length()->numeric_constant_value(&nc)
+         && nc.to_unsigned_long(&val) == Numeric_constant::NC_UL_VALID)
+       {
+         if (indexes == NULL)
+           {
+             if (this->vals_->size() > val)
+               {
+                 error_at(location, "too many elements in composite literal");
+                 return Expression::make_error(location);
+               }
+           }
+         else
+           {
+             unsigned long max = indexes->back();
+             if (max >= val)
+               {
+                 error_at(location,
+                          ("some element keys in composite literal "
+                           "are out of range"));
+                 return Expression::make_error(location);
+               }
+           }
+       }
+    }
+
   if (at->length() != NULL)
-    return new Fixed_array_construction_expression(type, vals, location);
+    return new Fixed_array_construction_expression(type, indexes, vals,
+                                                  location);
   else
-    return new Open_array_construction_expression(type, vals, location);
+    return new Open_array_construction_expression(type, indexes, vals,
+                                                 location);
 }
 
 // Lower a map composite literal.
@@ -12788,26 +12947,8 @@ Type_guard_expression::do_traverse(Traverse* traverse)
 void
 Type_guard_expression::do_check_types(Gogo*)
 {
-  // 6g permits using a type guard with unsafe.pointer; we are
-  // compatible.
   Type* expr_type = this->expr_->type();
-  if (expr_type->is_unsafe_pointer_type())
-    {
-      if (this->type_->points_to() == NULL
-         && (this->type_->integer_type() == NULL
-             || (this->type_->forwarded()
-                 != Type::lookup_integer_type("uintptr"))))
-       this->report_error(_("invalid unsafe.Pointer conversion"));
-    }
-  else if (this->type_->is_unsafe_pointer_type())
-    {
-      if (expr_type->points_to() == NULL
-         && (expr_type->integer_type() == NULL
-             || (expr_type->forwarded()
-                 != Type::lookup_integer_type("uintptr"))))
-       this->report_error(_("invalid unsafe.Pointer conversion"));
-    }
-  else if (expr_type->interface_type() == NULL)
+  if (expr_type->interface_type() == NULL)
     {
       if (!expr_type->is_error() && !this->type_->is_error())
        this->report_error(_("type assertion only valid for interface types"));
@@ -12840,23 +12981,10 @@ Type_guard_expression::do_check_types(Gogo*)
 tree
 Type_guard_expression::do_get_tree(Translate_context* context)
 {
-  Gogo* gogo = context->gogo();
   tree expr_tree = this->expr_->get_tree(context);
   if (expr_tree == error_mark_node)
     return error_mark_node;
-  Type* expr_type = this->expr_->type();
-  if ((this->type_->is_unsafe_pointer_type()
-       && (expr_type->points_to() != NULL
-          || expr_type->integer_type() != NULL))
-      || (expr_type->is_unsafe_pointer_type()
-         && this->type_->points_to() != NULL))
-    return convert_to_pointer(type_to_tree(this->type_->get_backend(gogo)),
-                             expr_tree);
-  else if (expr_type->is_unsafe_pointer_type()
-          && this->type_->integer_type() != NULL)
-    return convert_to_integer(type_to_tree(this->type_->get_backend(gogo)),
-                             expr_tree);
-  else if (this->type_->interface_type() != NULL)
+  if (this->type_->interface_type() != NULL)
     return Expression::convert_interface_to_interface(context, this->type_,
                                                      this->expr_->type(),
                                                      expr_tree, true,