#include "go-system.h"
+#include <algorithm>
+
#include <gmp.h>
#ifndef ENABLE_BUILD_WITH_CXX
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,
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())
// 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);
}
&& 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
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))
else
go_unreachable();
- case OPERATOR_NOT:
case OPERATOR_XOR:
break;
+ case OPERATOR_NOT:
case OPERATOR_AND:
case OPERATOR_MULT:
return false;
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);
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())
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);
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;
}
&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);
{
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);
}
}
}
pf != fields->end();
++pf, ++field_index)
{
+ if (Gogo::is_sink_name(pf->field_name()))
+ continue;
+
if (field_index > 0)
{
if (left_temp == NULL)
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);
}
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:
case OPERATOR_MOD:
case OPERATOR_AND:
case OPERATOR_BITCLEAR:
+ case OPERATOR_OROR:
+ case OPERATOR_ANDAND:
{
Type* type;
if (!Binary_expression::operation_type(this->op_,
&& (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"));
}
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.
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());
// 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)
{
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);
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;
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.
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);
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
&& !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;
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())
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);
{
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.
void
do_export(Export*) const;
+ // The indexes.
+ const std::vector<unsigned long>*
+ indexes()
+ { return this->indexes_; }
+
// The list of values.
Expression_list*
vals()
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_;
};
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.
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();
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);
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(")");
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)
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() << "}" ;
}
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()),
tree
do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*);
};
// Return a tree for constructing a fixed array.
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.
do_copy()
{
return new Open_array_construction_expression(this->type(),
+ this->indexes(),
(this->vals() == NULL
? NULL
: this->vals()->copy()),
}
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)
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.
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*);
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*
{
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())
++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))
{
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);
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.
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"));
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,