OSDN Git Service

compiler: Don't try to take the address of a constant.
[pf3gnuchains/gcc-fork.git] / gcc / go / gofrontend / expressions.cc
index 06e85eb..56df6f6 100644 (file)
@@ -6,6 +6,8 @@
 
 #include "go-system.h"
 
+#include <algorithm>
+
 #include <gmp.h>
 
 #ifndef ENABLE_BUILD_WITH_CXX
@@ -2403,8 +2405,7 @@ class Const_expression : public Expression
   do_numeric_constant_value(Numeric_constant* nc) const;
 
   bool
-  do_string_constant_value(std::string* val) const
-  { return this->constant_->const_value()->expr()->string_constant_value(val); }
+  do_string_constant_value(std::string* val) const;
 
   Type*
   do_type();
@@ -2514,6 +2515,21 @@ Const_expression::do_numeric_constant_value(Numeric_constant* nc) const
   return r;
 }
 
+bool
+Const_expression::do_string_constant_value(std::string* val) const
+{
+  if (this->seen_)
+    return false;
+
+  Expression* e = this->constant_->const_value()->expr();
+
+  this->seen_ = true;
+  bool ok = e->string_constant_value(val);
+  this->seen_ = false;
+
+  return ok;
+}
+
 // Return the type of the const reference.
 
 Type*
@@ -3590,8 +3606,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))
@@ -3681,10 +3696,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;
@@ -3697,7 +3712,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);
 
@@ -3895,6 +3913,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())
@@ -4022,7 +4044,7 @@ 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)
        {
@@ -5633,6 +5655,7 @@ Binary_expression::do_get_tree(Translate_context* context)
   enum tree_code code;
   bool use_left_type = true;
   bool is_shift_op = false;
+  bool is_idiv_op = false;
   switch (this->op_)
     {
     case OPERATOR_EQEQ:
@@ -5675,11 +5698,15 @@ Binary_expression::do_get_tree(Translate_context* context)
        if (t->float_type() != NULL || t->complex_type() != NULL)
          code = RDIV_EXPR;
        else
-         code = TRUNC_DIV_EXPR;
+         {
+           code = TRUNC_DIV_EXPR;
+           is_idiv_op = true;
+         }
       }
       break;
     case OPERATOR_MOD:
       code = TRUNC_MOD_EXPR;
+      is_idiv_op = true;
       break;
     case OPERATOR_LSHIFT:
       code = LSHIFT_EXPR;
@@ -5700,6 +5727,7 @@ Binary_expression::do_get_tree(Translate_context* context)
       go_unreachable();
     }
 
+  location_t gccloc = this->location().gcc_location();
   tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
 
   if (this->left_->type()->is_string_type())
@@ -5727,28 +5755,27 @@ Binary_expression::do_get_tree(Translate_context* context)
     }
 
   tree eval_saved = NULL_TREE;
-  if (is_shift_op)
+  if (is_shift_op
+      || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
     {
       // Make sure the values are evaluated.
-      if (!DECL_P(left) && TREE_SIDE_EFFECTS(left))
+      if (!DECL_P(left))
        {
          left = save_expr(left);
          eval_saved = left;
        }
-      if (!DECL_P(right) && TREE_SIDE_EFFECTS(right))
+      if (!DECL_P(right))
        {
          right = save_expr(right);
          if (eval_saved == NULL_TREE)
            eval_saved = right;
          else
-           eval_saved = fold_build2_loc(this->location().gcc_location(),
-                                         COMPOUND_EXPR,
+           eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR,
                                         void_type_node, eval_saved, right);
        }
     }
 
-  tree ret = fold_build2_loc(this->location().gcc_location(),
-                            code,
+  tree ret = fold_build2_loc(gccloc, code,
                             compute_type != NULL_TREE ? compute_type : type,
                             left, right);
 
@@ -5766,39 +5793,116 @@ Binary_expression::do_get_tree(Translate_context* context)
       tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
                                 build_int_cst_type(TREE_TYPE(right), bits));
 
-      tree overflow_result = fold_convert_loc(this->location().gcc_location(),
-                                             TREE_TYPE(left),
+      tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left),
                                              integer_zero_node);
       if (this->op_ == OPERATOR_RSHIFT
          && !this->left_->type()->integer_type()->is_unsigned())
        {
          tree neg =
-            fold_build2_loc(this->location().gcc_location(), LT_EXPR,
-                            boolean_type_node, left,
-                            fold_convert_loc(this->location().gcc_location(),
-                                             TREE_TYPE(left),
+            fold_build2_loc(gccloc, LT_EXPR, boolean_type_node,
+                           left,
+                            fold_convert_loc(gccloc, TREE_TYPE(left),
                                              integer_zero_node));
          tree neg_one =
-            fold_build2_loc(this->location().gcc_location(),
-                            MINUS_EXPR, TREE_TYPE(left),
-                            fold_convert_loc(this->location().gcc_location(),
-                                             TREE_TYPE(left),
+            fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left),
+                            fold_convert_loc(gccloc, TREE_TYPE(left),
                                              integer_zero_node),
-                            fold_convert_loc(this->location().gcc_location(),
-                                             TREE_TYPE(left),
+                            fold_convert_loc(gccloc, TREE_TYPE(left),
                                              integer_one_node));
          overflow_result =
-            fold_build3_loc(this->location().gcc_location(), COND_EXPR,
-                            TREE_TYPE(left), neg, neg_one,
-                            overflow_result);
+            fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
+                           neg, neg_one, overflow_result);
        }
 
-      ret = fold_build3_loc(this->location().gcc_location(), COND_EXPR,
-                            TREE_TYPE(left), compare, ret, overflow_result);
+      ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
+                           compare, ret, overflow_result);
 
       if (eval_saved != NULL_TREE)
-       ret = fold_build2_loc(this->location().gcc_location(), COMPOUND_EXPR,
-                             TREE_TYPE(ret), eval_saved, ret);
+       ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
+                             eval_saved, ret);
+    }
+
+  // Add checks for division by zero and division overflow as needed.
+  if (is_idiv_op)
+    {
+      if (go_check_divide_zero)
+       {
+         // right == 0
+         tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
+                                      right,
+                                      fold_convert_loc(gccloc,
+                                                       TREE_TYPE(right),
+                                                       integer_zero_node));
+
+         // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0
+         int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
+         tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
+                                      Gogo::runtime_error(errcode,
+                                                          this->location()),
+                                      fold_convert_loc(gccloc, TREE_TYPE(ret),
+                                                       integer_zero_node));
+
+         // right == 0 ? (__go_runtime_error(...), 0) : ret
+         ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+                               check, panic, ret);
+       }
+
+      if (go_check_divide_overflow)
+       {
+         // right == -1
+         // FIXME: It would be nice to say that this test is expected
+         // to return false.
+         tree m1 = integer_minus_one_node;
+         tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
+                                      right,
+                                      fold_convert_loc(gccloc,
+                                                       TREE_TYPE(right),
+                                                       m1));
+
+         tree overflow;
+         if (TYPE_UNSIGNED(TREE_TYPE(ret)))
+           {
+             // An unsigned -1 is the largest possible number, so
+             // dividing is always 1 or 0.
+             tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
+                                        left, right);
+             if (this->op_ == OPERATOR_DIV)
+               overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+                                          cmp,
+                                          fold_convert_loc(gccloc,
+                                                           TREE_TYPE(ret),
+                                                           integer_one_node),
+                                          fold_convert_loc(gccloc,
+                                                           TREE_TYPE(ret),
+                                                           integer_zero_node));
+             else
+               overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+                                          cmp,
+                                          fold_convert_loc(gccloc,
+                                                           TREE_TYPE(ret),
+                                                           integer_zero_node),
+                                          left);
+           }
+         else
+           {
+             // Computing left / -1 is the same as computing - left,
+             // which does not overflow since Go sets -fwrapv.
+             if (this->op_ == OPERATOR_DIV)
+               overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left),
+                                          left);
+             else
+               overflow = integer_zero_node;
+           }
+         overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow);
+
+         // right == -1 ? - left : ret
+         ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+                               check, overflow, ret);
+       }
+
+      if (eval_saved != NULL_TREE)
+       ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
+                             eval_saved, ret);
     }
 
   return ret;
@@ -6090,7 +6194,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);
@@ -8545,7 +8651,14 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
        new_args->push_back(*pa);
       else if (this->is_varargs_)
        {
-         this->report_error(_("too many arguments"));
+         if ((*pa)->type()->is_slice_type())
+           this->report_error(_("too many arguments"));
+         else
+           {
+             error_at(this->location(),
+                      _("invalid use of %<...%> with non-slice"));
+             this->set_is_error();
+           }
          return;
        }
       else
@@ -8790,6 +8903,9 @@ Call_expression::check_argument_type(int i, const Type* parameter_type,
 void
 Call_expression::do_check_types(Gogo*)
 {
+  if (this->classification() == EXPRESSION_ERROR)
+    return;
+
   Function_type* fntype = this->get_function_type();
   if (fntype == NULL)
     {
@@ -8825,7 +8941,17 @@ Call_expression::do_check_types(Gogo*)
     }
 
   // Note that varargs was handled by the lower_varargs() method, so
-  // we don't have to worry about it here.
+  // we don't have to worry about it here unless something is wrong.
+  if (this->is_varargs_ && !this->varargs_are_lowered_)
+    {
+      if (!fntype->is_varargs())
+       {
+         error_at(this->location(),
+                  _("invalid use of %<...%> calling non-variadic function"));
+         this->set_is_error();
+         return;
+       }
+    }
 
   const Typed_identifier_list* parameters = fntype->parameters();
   if (this->args_ == NULL)
@@ -9107,7 +9233,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);
@@ -10967,9 +11093,15 @@ class Struct_construction_expression : public Expression
   Struct_construction_expression(Type* type, Expression_list* vals,
                                 Location location)
     : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
-      type_(type), vals_(vals)
+      type_(type), vals_(vals), traverse_order_(NULL)
   { }
 
+  // Set the traversal order, used to ensure that we implement the
+  // order of evaluation rules.  Takes ownership of the argument.
+  void
+  set_traverse_order(std::vector<int>* traverse_order)
+  { this->traverse_order_ = traverse_order; }
+
   // Return whether this is a constant initializer.
   bool
   is_constant_struct() const;
@@ -10991,8 +11123,12 @@ class Struct_construction_expression : public Expression
   Expression*
   do_copy()
   {
-    return new Struct_construction_expression(this->type_, this->vals_->copy(),
-                                             this->location());
+    Struct_construction_expression* ret =
+      new Struct_construction_expression(this->type_, this->vals_->copy(),
+                                        this->location());
+    if (this->traverse_order_ != NULL)
+      ret->set_traverse_order(this->traverse_order_);
+    return ret;
   }
 
   tree
@@ -11010,6 +11146,9 @@ class Struct_construction_expression : public Expression
   // The list of values, in order of the fields in the struct.  A NULL
   // entry means that the field should be zero-initialized.
   Expression_list* vals_;
+  // If not NULL, the order in which to traverse vals_.  This is used
+  // so that we implement the order of evaluation rules correctly.
+  std::vector<int>* traverse_order_;
 };
 
 // Traversal.
@@ -11017,9 +11156,26 @@ class Struct_construction_expression : public Expression
 int
 Struct_construction_expression::do_traverse(Traverse* traverse)
 {
-  if (this->vals_ != NULL
-      && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
-    return TRAVERSE_EXIT;
+  if (this->vals_ != NULL)
+    {
+      if (this->traverse_order_ == NULL)
+       {
+         if (this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+           return TRAVERSE_EXIT;
+       }
+      else
+       {
+         for (std::vector<int>::const_iterator p =
+                this->traverse_order_->begin();
+              p != this->traverse_order_->end();
+              ++p)
+           {
+             if (Expression::traverse(&this->vals_->at(*p), traverse)
+                 == TRAVERSE_EXIT)
+               return TRAVERSE_EXIT;
+           }
+       }
+    }
   if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
     return TRAVERSE_EXIT;
   return TRAVERSE_CONTINUE;
@@ -11246,11 +11402,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.
@@ -11279,6 +11436,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()
@@ -11294,7 +11456,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_;
 };
 
@@ -11377,18 +11542,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.
@@ -11406,12 +11559,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();
@@ -11432,7 +11595,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);
@@ -11450,13 +11617,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(")");
@@ -11468,8 +11650,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)
@@ -11479,7 +11660,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() << "}" ;
 
 }
@@ -11490,20 +11686,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()),
@@ -11512,9 +11707,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.
@@ -11527,35 +11719,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.
@@ -11564,6 +11738,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()),
@@ -11615,13 +11790,19 @@ 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 = *std::max_element(this->indexes()->begin(),
+                                     this->indexes()->end());
+      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)
@@ -11729,7 +11910,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.
@@ -12083,7 +12264,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*);
@@ -12198,6 +12379,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
 
   size_t field_count = st->field_count();
   std::vector<Expression*> vals(field_count);
+  std::vector<int>* traverse_order = new(std::vector<int>);
   Expression_list::const_iterator p = this->vals_->begin();
   while (p != this->vals_->end())
     {
@@ -12350,6 +12532,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
                 type->named_type()->message_name().c_str());
 
       vals[index] = val;
+      traverse_order->push_back(index);
     }
 
   Expression_list* list = new Expression_list;
@@ -12357,7 +12540,10 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
   for (size_t i = 0; i < field_count; ++i)
     list->push_back(vals[i]);
 
-  return new Struct_construction_expression(type, list, location);
+  Struct_construction_expression* ret =
+    new Struct_construction_expression(type, list, location);
+  ret->set_traverse_order(traverse_order);
+  return ret;
 }
 
 // Lower an array composite literal.
@@ -12367,10 +12553,12 @@ 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());
+  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())
@@ -12383,8 +12571,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))
            {
@@ -12420,59 +12619,65 @@ 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)
-           {
-             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)
+         if (std::find(indexes->begin(), indexes->end(), index)
+             != indexes->end())
            {
-             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;
+
+         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;
+    }
 
-  return this->make_array(type, list);
+  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 = 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);
+           }
+       }
+      else
+       {
+         size = *std::max_element(indexes->begin(), indexes->end());
+         ++size;
+       }
+
       mpz_t vlen;
       mpz_init_set_ui(vlen, size);
       Expression* elen = Expression::make_integer(&vlen, NULL, location);
@@ -12480,10 +12685,44 @@ 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 = *std::max_element(indexes->begin(),
+                                                   indexes->end());
+             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.
@@ -13489,7 +13728,13 @@ Numeric_constant::set_float(Type* type, const mpfr_t val)
   this->clear();
   this->classification_ = NC_FLOAT;
   this->type_ = type;
-  mpfr_init_set(this->u_.float_val, val, GMP_RNDN);
+  // Numeric constants do not have negative zero values, so remove
+  // them here.  They also don't have infinity or NaN values, but we
+  // should never see them here.
+  if (mpfr_zero_p(val))
+    mpfr_init_set_ui(this->u_.float_val, 0, GMP_RNDN);
+  else
+    mpfr_init_set(this->u_.float_val, val, GMP_RNDN);
 }
 
 // Set to a complex value.