diff options
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 189 |
1 files changed, 137 insertions, 52 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 45220b640b2..9dbbfbf8f1d 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3351,14 +3351,10 @@ Type_conversion_expression::do_get_tree(Translate_context* context) return se->get_tree(context); } - static tree int_to_string_fndecl; - ret = Gogo::call_builtin(&int_to_string_fndecl, - this->location(), - "__go_int_to_string", - 1, - type_tree, - int_type_tree, - expr_tree); + Call_expression* i2s_expr = + Runtime::make_call(Runtime::INT_TO_STRING, this->location(), 1, + this->expr_); + ret = i2s_expr->get_tree(context); } else if (type->is_string_type() && expr_type->is_slice_type()) { @@ -3408,29 +3404,18 @@ Type_conversion_expression::do_get_tree(Translate_context* context) { Type* e = type->array_type()->element_type()->forwarded(); go_assert(e->integer_type() != NULL); + + Call_expression* s2a_expr; if (e->integer_type()->is_byte()) - { - tree string_to_byte_array_fndecl = NULL_TREE; - ret = Gogo::call_builtin(&string_to_byte_array_fndecl, - this->location(), - "__go_string_to_byte_array", - 1, - type_tree, - TREE_TYPE(expr_tree), - expr_tree); - } + s2a_expr = Runtime::make_call(Runtime::STRING_TO_BYTE_ARRAY, + this->location(), 1, this->expr_); else { go_assert(e->integer_type()->is_rune()); - tree string_to_int_array_fndecl = NULL_TREE; - ret = Gogo::call_builtin(&string_to_int_array_fndecl, - this->location(), - "__go_string_to_int_array", - 1, - type_tree, - TREE_TYPE(expr_tree), - expr_tree); + s2a_expr = Runtime::make_call(Runtime::STRING_TO_INT_ARRAY, + this->location(), 1, this->expr_); } + ret = s2a_expr->get_tree(context); } else if ((type->is_unsafe_pointer_type() && expr_type->points_to() != NULL) @@ -10250,7 +10235,9 @@ Index_expression::do_traverse(Traverse* traverse) if (Expression::traverse(&this->left_, traverse) == TRAVERSE_EXIT || Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT || (this->end_ != NULL - && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)) + && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT) + || (this->cap_ != NULL + && Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)) return TRAVERSE_EXIT; return TRAVERSE_CONTINUE; } @@ -10265,6 +10252,7 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) Expression* left = this->left_; Expression* start = this->start_; Expression* end = this->end_; + Expression* cap = this->cap_; Type* type = left->type(); if (type->is_error()) @@ -10275,20 +10263,27 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) return Expression::make_error(location); } else if (type->array_type() != NULL) - return Expression::make_array_index(left, start, end, location); + return Expression::make_array_index(left, start, end, cap, location); else if (type->points_to() != NULL && type->points_to()->array_type() != NULL && !type->points_to()->is_slice_type()) { Expression* deref = Expression::make_unary(OPERATOR_MULT, left, location); - return Expression::make_array_index(deref, start, end, location); + return Expression::make_array_index(deref, start, end, cap, location); } else if (type->is_string_type()) - return Expression::make_string_index(left, start, end, location); + { + if (cap != NULL) + { + error_at(location, "invalid 3-index slice of string"); + return Expression::make_error(location); + } + return Expression::make_string_index(left, start, end, location); + } else if (type->map_type() != NULL) { - if (end != NULL) + if (end != NULL || cap != NULL) { error_at(location, "invalid slice of map"); return Expression::make_error(location); @@ -10307,14 +10302,15 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) } } -// Write an indexed expression (expr[expr:expr] or expr[expr]) to a -// dump context +// Write an indexed expression +// (expr[expr:expr:expr], expr[expr:expr] or expr[expr]) to a dump context. void Index_expression::dump_index_expression(Ast_dump_context* ast_dump_context, const Expression* expr, const Expression* start, - const Expression* end) + const Expression* end, + const Expression* cap) { expr->dump_expression(ast_dump_context); ast_dump_context->ostream() << "["; @@ -10324,6 +10320,11 @@ Index_expression::dump_index_expression(Ast_dump_context* ast_dump_context, ast_dump_context->ostream() << ":"; end->dump_expression(ast_dump_context); } + if (cap != NULL) + { + ast_dump_context->ostream() << ":"; + cap->dump_expression(ast_dump_context); + } ast_dump_context->ostream() << "]"; } @@ -10334,16 +10335,16 @@ Index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { Index_expression::dump_index_expression(ast_dump_context, this->left_, - this->start_, this->end_); + this->start_, this->end_, this->cap_); } // Make an index expression. Expression* Expression::make_index(Expression* left, Expression* start, Expression* end, - Location location) + Expression* cap, Location location) { - return new Index_expression(left, start, end, location); + return new Index_expression(left, start, end, cap, location); } // An array index. This is used for both indexing and slicing. @@ -10352,9 +10353,9 @@ class Array_index_expression : public Expression { public: Array_index_expression(Expression* array, Expression* start, - Expression* end, Location location) + Expression* end, Expression* cap, Location location) : Expression(EXPRESSION_ARRAY_INDEX, location), - array_(array), start_(start), end_(end), type_(NULL) + array_(array), start_(start), end_(end), cap_(cap), type_(NULL) { } protected: @@ -10378,6 +10379,9 @@ class Array_index_expression : public Expression (this->end_ == NULL ? NULL : this->end_->copy()), + (this->cap_ == NULL + ? NULL + : this->cap_->copy()), this->location()); } @@ -10409,6 +10413,9 @@ class Array_index_expression : public Expression // The end index of a slice. This may be NULL for a simple array // index, or it may be a nil expression for the length of the array. Expression* end_; + // The capacity argument of a slice. This may be NULL for an array index or + // slice. + Expression* cap_; // The type of the expression. Type* type_; }; @@ -10427,6 +10434,11 @@ Array_index_expression::do_traverse(Traverse* traverse) if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT) return TRAVERSE_EXIT; } + if (this->cap_ != NULL) + { + if (Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } return TRAVERSE_CONTINUE; } @@ -10466,6 +10478,8 @@ Array_index_expression::do_determine_type(const Type_context*) this->start_->determine_type_no_context(); if (this->end_ != NULL) this->end_->determine_type_no_context(); + if (this->cap_ != NULL) + this->cap_->determine_type_no_context(); } // Check types of an array index. @@ -10488,6 +10502,14 @@ Array_index_expression::do_check_types(Gogo*) && (!this->end_->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("slice end must be integer")); + if (this->cap_ != NULL + && this->cap_->type()->integer_type() == NULL + && !this->cap_->type()->is_error() + && !this->cap_->is_nil_expression() + && !this->cap_->is_error_expression() + && (!this->cap_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) + this->report_error(_("slice capacity must be integer")); Array_type* array_type = this->array_->type()->array_type(); if (array_type == NULL) @@ -10525,8 +10547,10 @@ Array_index_expression::do_check_types(Gogo*) { Numeric_constant enc; mpz_t eval; + bool eval_valid = false; if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval)) { + eval_valid = true; if (mpz_sgn(eval) < 0 || mpz_sizeinbase(eval, 2) >= int_bits || (lval_valid && mpz_cmp(eval, lval) > 0)) @@ -10536,8 +10560,37 @@ Array_index_expression::do_check_types(Gogo*) } else if (ival_valid && mpz_cmp(ival, eval) > 0) this->report_error(_("inverted slice range")); - mpz_clear(eval); } + + Numeric_constant cnc; + mpz_t cval; + if (this->cap_ != NULL + && this->cap_->numeric_constant_value(&cnc) && cnc.to_int(&cval)) + { + if (mpz_sgn(cval) < 0 + || mpz_sizeinbase(cval, 2) >= int_bits + || (lval_valid && mpz_cmp(cval, lval) > 0)) + { + error_at(this->cap_->location(), "array index out of bounds"); + this->set_is_error(); + } + else if (ival_valid && mpz_cmp(ival, cval) > 0) + { + error_at(this->cap_->location(), + "invalid slice index: capacity less than start"); + this->set_is_error(); + } + else if (eval_valid && mpz_cmp(eval, cval) > 0) + { + error_at(this->cap_->location(), + "invalid slice index: capacity less than length"); + this->set_is_error(); + } + mpz_clear(cval); + } + + if (eval_valid) + mpz_clear(eval); } if (ival_valid) mpz_clear(ival); @@ -10617,9 +10670,17 @@ Array_index_expression::do_get_tree(Translate_context* context) capacity_tree = save_expr(capacity_tree); } + tree cap_arg = capacity_tree; + if (this->cap_ != NULL) + { + cap_arg = this->cap_->get_tree(context); + if (cap_arg == error_mark_node) + return error_mark_node; + } + tree length_type = (length_tree != NULL_TREE ? TREE_TYPE(length_tree) - : TREE_TYPE(capacity_tree)); + : TREE_TYPE(cap_arg)); tree bad_index = boolean_false_node; @@ -10691,6 +10752,29 @@ Array_index_expression::do_get_tree(Translate_context* context) // Array slice. + if (this->cap_ != NULL) + { + if (!DECL_P(cap_arg)) + cap_arg = save_expr(cap_arg); + if (!INTEGRAL_TYPE_P(TREE_TYPE(cap_arg))) + cap_arg = convert_to_integer(length_type, cap_arg); + + bad_index = Expression::check_bounds(cap_arg, length_type, bad_index, + loc); + cap_arg = fold_convert_loc(loc.gcc_location(), length_type, cap_arg); + + tree bad_cap = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, + boolean_type_node, + fold_build2_loc(loc.gcc_location(), + LT_EXPR, boolean_type_node, + cap_arg, start_tree), + fold_build2_loc(loc.gcc_location(), + GT_EXPR, boolean_type_node, + cap_arg, capacity_tree)); + bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, + boolean_type_node, bad_index, bad_cap); + } + tree end_tree; if (this->end_->is_nil_expression()) end_tree = length_tree; @@ -10716,11 +10800,12 @@ Array_index_expression::do_get_tree(Translate_context* context) end_tree, start_tree), fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node, - end_tree, capacity_tree)); + end_tree, cap_arg)); bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node, bad_index, bad_end); } + Type* element_type = array_type->element_type(); tree element_type_tree = type_to_tree(element_type->get_backend(gogo)); if (element_type_tree == error_mark_node) @@ -10744,8 +10829,7 @@ Array_index_expression::do_get_tree(Translate_context* context) length_type, end_tree, start_tree); tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR, - length_type, capacity_tree, - start_tree); + length_type, cap_arg, start_tree); tree struct_tree = type_to_tree(this->type()->get_backend(gogo)); go_assert(TREE_CODE(struct_tree) == RECORD_TYPE); @@ -10795,16 +10879,17 @@ Array_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { Index_expression::dump_index_expression(ast_dump_context, this->array_, - this->start_, this->end_); + this->start_, this->end_, this->cap_); } -// Make an array index expression. END may be NULL. +// Make an array index expression. END and CAP may be NULL. Expression* Expression::make_array_index(Expression* array, Expression* start, - Expression* end, Location location) + Expression* end, Expression* cap, + Location location) { - return new Array_index_expression(array, start, end, location); + return new Array_index_expression(array, start, end, cap, location); } // A string index. This is used for both indexing and slicing. @@ -11082,8 +11167,8 @@ void String_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { - Index_expression::dump_index_expression(ast_dump_context, this->string_, - this->start_, this->end_); + Index_expression::dump_index_expression(ast_dump_context, this->string_, + this->start_, this->end_, NULL); } // Make a string index expression. END may be NULL. @@ -11310,8 +11395,8 @@ void Map_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { - Index_expression::dump_index_expression(ast_dump_context, - this->map_, this->index_, NULL); + Index_expression::dump_index_expression(ast_dump_context, this->map_, + this->index_, NULL, NULL); } // Make a map index expression. |