#include "go-system.h"
+#include <algorithm>
+
#include <gmp.h>
#ifndef ENABLE_BUILD_WITH_CXX
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();
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*
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())
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:
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;
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())
}
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);
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;
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
void
Call_expression::do_check_types(Gogo*)
{
+ if (this->classification() == EXPRESSION_ERROR)
+ return;
+
Function_type* fntype = this->get_function_type();
if (fntype == NULL)
{
}
// 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)
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);
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;
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
// 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.
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;
{
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 = *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)
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*);
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())
{
type->named_type()->message_name().c_str());
vals[index] = val;
+ traverse_order->push_back(index);
}
Expression_list* list = new Expression_list;
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.
{
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())
++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)
- {
- 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);
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.
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.