diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 475 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 17 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 1 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.cc | 7 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 69 |
6 files changed, 381 insertions, 190 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 18127de..f596a69 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -a6ddd0e1208a7d229c10be630c1110b3914038f5 +189ff44b2c26f29f41f0eb159e0d8f3fa508ecae The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 90a39a2..939a5f7 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -594,67 +594,110 @@ Expression::backend_numeric_constant_expression(Translate_context* context, return ret; } -// Return an expression which evaluates to true if VAL, of arbitrary integer -// type, is negative or is more than the maximum value of the Go type "int". +// Insert bounds checks for an index expression. Check that that VAL +// >= 0 and that it fits in an int. Then check that VAL OP BOUND is +// true. If any condition is false, call one of the CODE runtime +// functions, which will panic. -Expression* -Expression::check_bounds(Expression* val, Location loc) +void +Expression::check_bounds(Expression* val, Operator op, Expression* bound, + Runtime::Function code, + Runtime::Function code_u, + Runtime::Function code_extend, + Runtime::Function code_extend_u, + Statement_inserter* inserter, + Location loc) { - Type* val_type = val->type(); - Type* bound_type = Type::lookup_integer_type("int"); + go_assert(val->is_variable() || val->is_constant()); + go_assert(bound->is_variable() || bound->is_constant()); - int val_type_size; - bool val_is_unsigned = false; - if (val_type->integer_type() != NULL) - { - val_type_size = val_type->integer_type()->bits(); - val_is_unsigned = val_type->integer_type()->is_unsigned(); - } - else - { - if (!val_type->is_numeric_type() - || !Type::are_convertible(bound_type, val_type, NULL)) - { - go_assert(saw_errors()); - return Expression::make_boolean(true, loc); - } + Type* int_type = Type::lookup_integer_type("int"); + int int_type_size = int_type->integer_type()->bits(); - if (val_type->complex_type() != NULL) - val_type_size = val_type->complex_type()->bits(); - else - val_type_size = val_type->float_type()->bits(); + Type* val_type = val->type(); + if (val_type->integer_type() == NULL) + { + go_assert(saw_errors()); + return; } + int val_type_size = val_type->integer_type()->bits(); + bool val_is_unsigned = val_type->integer_type()->is_unsigned(); - Expression* negative_index = Expression::make_boolean(false, loc); - Expression* index_overflows = Expression::make_boolean(false, loc); + // Check that VAL >= 0. + Expression* check = NULL; if (!val_is_unsigned) { Expression* zero = Expression::make_integer_ul(0, val_type, loc); - negative_index = Expression::make_binary(OPERATOR_LT, val, zero, loc); + check = Expression::make_binary(OPERATOR_GE, val->copy(), zero, loc); } - int bound_type_size = bound_type->integer_type()->bits(); - if (val_type_size > bound_type_size - || (val_type_size == bound_type_size + // If VAL's type is larger than int, check that VAL fits in an int. + if (val_type_size > int_type_size + || (val_type_size == int_type_size && val_is_unsigned)) { mpz_t one; mpz_init_set_ui(one, 1UL); - // maxval = 2^(bound_type_size - 1) - 1 + // maxval = 2^(int_type_size - 1) - 1 mpz_t maxval; mpz_init(maxval); - mpz_mul_2exp(maxval, one, bound_type_size - 1); + mpz_mul_2exp(maxval, one, int_type_size - 1); mpz_sub_ui(maxval, maxval, 1); Expression* max = Expression::make_integer_z(&maxval, val_type, loc); mpz_clear(one); mpz_clear(maxval); - index_overflows = Expression::make_binary(OPERATOR_GT, val, max, loc); + Expression* cmp = Expression::make_binary(OPERATOR_LE, val->copy(), + max, loc); + if (check == NULL) + check = cmp; + else + check = Expression::make_binary(OPERATOR_ANDAND, check, cmp, loc); + } + + // For the final check we can assume that VAL fits in an int. + Expression* ival; + if (val_type == int_type) + ival = val->copy(); + else + ival = Expression::make_cast(int_type, val->copy(), loc); + + // BOUND is assumed to fit in an int. Either it comes from len or + // cap, or it was checked by an earlier call. + Expression* ibound; + if (bound->type() == int_type) + ibound = bound->copy(); + else + ibound = Expression::make_cast(int_type, bound->copy(), loc); + + Expression* cmp = Expression::make_binary(op, ival, ibound, loc); + if (check == NULL) + check = cmp; + else + check = Expression::make_binary(OPERATOR_ANDAND, check, cmp, loc); + + Runtime::Function c; + if (val_type_size > int_type_size) + { + if (val_is_unsigned) + c = code_extend_u; + else + c = code_extend; + } + else + { + if (val_is_unsigned) + c = code_u; + else + c = code; } - return Expression::make_binary(OPERATOR_OROR, negative_index, index_overflows, - loc); + Expression* ignore = Expression::make_boolean(true, loc); + Expression* crash = Runtime::make_call(c, loc, 2, + val->copy(), bound->copy()); + Expression* cond = Expression::make_conditional(check, ignore, crash, loc); + inserter->insert(Statement::make_statement(cond, true)); } void @@ -12666,7 +12709,8 @@ Array_index_expression::do_check_types(Gogo*) unsigned long v; if (this->start_->type()->integer_type() == NULL && !this->start_->type()->is_error() - && (!this->start_->numeric_constant_value(&nc) + && (!this->start_->type()->is_abstract() + || !this->start_->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("index must be integer")); if (this->end_ != NULL @@ -12674,7 +12718,8 @@ Array_index_expression::do_check_types(Gogo*) && !this->end_->type()->is_error() && !this->end_->is_nil_expression() && !this->end_->is_error_expression() - && (!this->end_->numeric_constant_value(&nc) + && (!this->end_->type()->is_abstract() + || !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 @@ -12682,7 +12727,8 @@ Array_index_expression::do_check_types(Gogo*) && !this->cap_->type()->is_error() && !this->cap_->is_nil_expression() && !this->cap_->is_error_expression() - && (!this->cap_->numeric_constant_value(&nc) + && (!this->cap_->type()->is_abstract() + || !this->cap_->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("slice capacity must be integer")); @@ -12799,13 +12845,21 @@ Array_index_expression::do_must_eval_subexpressions_in_order( return true; } -// Flatten array indexing by using temporary variables for slices and indexes. +// Flatten array indexing: add temporary variables and bounds checks. Expression* -Array_index_expression::do_flatten(Gogo*, Named_object*, +Array_index_expression::do_flatten(Gogo* gogo, Named_object*, Statement_inserter* inserter) { + if (this->is_flattened_) + return this; + this->is_flattened_ = true; + Location loc = this->location(); + + if (this->is_error_expression()) + return Expression::make_error(loc); + Expression* array = this->array_; Expression* start = this->start_; Expression* end = this->end_; @@ -12823,34 +12877,157 @@ Array_index_expression::do_flatten(Gogo*, Named_object*, return Expression::make_error(loc); } + Array_type* array_type = this->array_->type()->array_type(); + if (array_type == NULL) + { + go_assert(saw_errors()); + return Expression::make_error(loc); + } + Temporary_statement* temp; - if (array->type()->is_slice_type() && !array->is_variable()) + if (array_type->is_slice_type() && !array->is_variable()) { temp = Statement::make_temporary(NULL, array, loc); inserter->insert(temp); this->array_ = Expression::make_temporary_reference(temp, loc); + array = this->array_; } - if (!start->is_variable()) + if (!start->is_variable() && !start->is_constant()) { temp = Statement::make_temporary(NULL, start, loc); inserter->insert(temp); this->start_ = Expression::make_temporary_reference(temp, loc); + start = this->start_; } if (end != NULL && !end->is_nil_expression() - && !end->is_variable()) + && !end->is_variable() + && !end->is_constant()) { temp = Statement::make_temporary(NULL, end, loc); inserter->insert(temp); this->end_ = Expression::make_temporary_reference(temp, loc); + end = this->end_; } - if (cap != NULL && !cap->is_variable()) + if (cap != NULL && !cap->is_variable() && !cap->is_constant()) { temp = Statement::make_temporary(NULL, cap, loc); inserter->insert(temp); this->cap_ = Expression::make_temporary_reference(temp, loc); + cap = this->cap_; + } + + if (!this->needs_bounds_check_) + return this; + + Expression* len; + if (!array_type->is_slice_type()) + { + len = array_type->get_length(gogo, this->array_); + go_assert(len->is_constant()); + } + else + { + len = array_type->get_length(gogo, this->array_->copy()); + temp = Statement::make_temporary(NULL, len, loc); + inserter->insert(temp); + len = Expression::make_temporary_reference(temp, loc); + } + + Expression* scap = NULL; + if (array_type->is_slice_type()) + { + scap = array_type->get_capacity(gogo, this->array_->copy()); + temp = Statement::make_temporary(NULL, scap, loc); + inserter->insert(temp); + scap = Expression::make_temporary_reference(temp, loc); } + // The order of bounds checks here matches the order used by the gc + // compiler, as tested by issue30116[u].go. + + if (cap != NULL) + { + if (array_type->is_slice_type()) + Expression::check_bounds(cap, OPERATOR_LE, scap, + Runtime::PANIC_SLICE3_ACAP, + Runtime::PANIC_SLICE3_ACAP_U, + Runtime::PANIC_EXTEND_SLICE3_ACAP, + Runtime::PANIC_EXTEND_SLICE3_ACAP_U, + inserter, loc); + else + Expression::check_bounds(cap, OPERATOR_LE, len, + Runtime::PANIC_SLICE3_ALEN, + Runtime::PANIC_SLICE3_ALEN_U, + Runtime::PANIC_EXTEND_SLICE3_ALEN, + Runtime::PANIC_EXTEND_SLICE3_ALEN_U, + inserter, loc); + + Expression* start_bound = cap; + if (end != NULL && !end->is_nil_expression()) + { + Expression::check_bounds(end, OPERATOR_LE, cap, + Runtime::PANIC_SLICE3_B, + Runtime::PANIC_SLICE3_B_U, + Runtime::PANIC_EXTEND_SLICE3_B, + Runtime::PANIC_EXTEND_SLICE3_B_U, + inserter, loc); + start_bound = end; + } + + Expression::check_bounds(start, OPERATOR_LE, start_bound, + Runtime::PANIC_SLICE3_C, + Runtime::PANIC_SLICE3_C_U, + Runtime::PANIC_EXTEND_SLICE3_C, + Runtime::PANIC_EXTEND_SLICE3_C_U, + inserter, loc); + } + else if (end != NULL && !end->is_nil_expression()) + { + if (array_type->is_slice_type()) + Expression::check_bounds(end, OPERATOR_LE, scap, + Runtime::PANIC_SLICE_ACAP, + Runtime::PANIC_SLICE_ACAP_U, + Runtime::PANIC_EXTEND_SLICE_ACAP, + Runtime::PANIC_EXTEND_SLICE_ACAP_U, + inserter, loc); + else + Expression::check_bounds(end, OPERATOR_LE, len, + Runtime::PANIC_SLICE_ALEN, + Runtime::PANIC_SLICE_ALEN_U, + Runtime::PANIC_EXTEND_SLICE_ALEN, + Runtime::PANIC_EXTEND_SLICE_ALEN_U, + inserter, loc); + + Expression::check_bounds(start, OPERATOR_LE, end, + Runtime::PANIC_SLICE_B, + Runtime::PANIC_SLICE_B_U, + Runtime::PANIC_EXTEND_SLICE_B, + Runtime::PANIC_EXTEND_SLICE_B_U, + inserter, loc); + } + else if (end != NULL) + { + Expression* start_bound; + if (array_type->is_slice_type()) + start_bound = scap; + else + start_bound = len; + Expression::check_bounds(start, OPERATOR_LE, start_bound, + Runtime::PANIC_SLICE_B, + Runtime::PANIC_SLICE_B_U, + Runtime::PANIC_EXTEND_SLICE_B, + Runtime::PANIC_EXTEND_SLICE_B_U, + inserter, loc); + } + else + Expression::check_bounds(start, OPERATOR_LT, len, + Runtime::PANIC_INDEX, + Runtime::PANIC_INDEX_U, + Runtime::PANIC_EXTEND_INDEX, + Runtime::PANIC_EXTEND_INDEX_U, + inserter, loc); + return this; } @@ -12899,10 +13076,8 @@ Array_index_expression::do_get_backend(Translate_context* context) Type* int_type = Type::lookup_integer_type("int"); Btype* int_btype = int_type->get_backend(gogo); - // We need to convert the length and capacity to the Go "int" type here - // because the length of a fixed-length array could be of type "uintptr" - // and gimple disallows binary operations between "uintptr" and other - // integer types. FIXME. + // Convert the length and capacity to "int". FIXME: Do we need to + // do this? Bexpression* length = NULL; if (this->end_ == NULL || this->end_->is_nil_expression()) { @@ -12939,53 +13114,18 @@ Array_index_expression::do_get_backend(Translate_context* context) Bexpression* start = this->start_->get_backend(context); start = gogo->backend()->convert_expression(int_btype, start, loc); - Bexpression* crash = NULL; - Bexpression* bad_index = NULL; - if (this->needs_bounds_check_) - { - int code = (array_type->length() != NULL - ? (this->end_ == NULL - ? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS) - : (this->end_ == NULL - ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS)); - crash = gogo->runtime_error(code, loc)->get_backend(context); - bad_index = Expression::check_bounds(this->start_, loc)->get_backend(context); - Bexpression* start_too_large = - gogo->backend()->binary_expression((this->end_ == NULL - ? OPERATOR_GE - : OPERATOR_GT), - start, - (this->end_ == NULL - ? length - : capacity), - loc); - bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, - start_too_large, - bad_index, loc); - } - - Bfunction* bfn = context->function()->func_value()->get_decl(); if (this->end_ == NULL) { - // Simple array indexing. This has to return an l-value, so - // wrap the index check into START. - if (this->needs_bounds_check_) - start = - gogo->backend()->conditional_expression(bfn, int_btype, bad_index, - crash, start, loc); - + // Simple array indexing. Bexpression* ret; - if (array_type->length() != NULL) + if (!array_type->is_slice_type()) { Bexpression* array = this->array_->get_backend(context); ret = gogo->backend()->array_index_expression(array, start, loc); } else { - // Slice. Expression* valptr = array_type->get_value_pointer(gogo, this->array_, this->is_lvalue_); @@ -12999,31 +13139,7 @@ Array_index_expression::do_get_backend(Translate_context* context) return ret; } - // Array slice. - - if (this->cap_ != NULL) - { - cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc); - - if (this->needs_bounds_check_) - { - Bexpression* bounds_bcheck = - Expression::check_bounds(this->cap_, loc)->get_backend(context); - bad_index = - gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck, - bad_index, loc); - - Bexpression* cap_too_small = - gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc); - Bexpression* cap_too_large = - gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc); - Bexpression* bad_cap = - gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small, - cap_too_large, loc); - bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap, - bad_index, loc); - } - } + // Slice expression. Bexpression* end; if (this->end_->is_nil_expression()) @@ -13032,24 +13148,6 @@ Array_index_expression::do_get_backend(Translate_context* context) { end = this->end_->get_backend(context); end = gogo->backend()->convert_expression(int_btype, end, loc); - if (this->needs_bounds_check_) - { - Bexpression* bounds_bcheck = - Expression::check_bounds(this->end_, loc)->get_backend(context); - bad_index = - gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck, - bad_index, loc); - - Bexpression* end_too_small = - gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc); - Bexpression* end_too_large = - gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc); - Bexpression* bad_end = - gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small, - end_too_large, loc); - bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end, - bad_index, loc); - } } Bexpression* result_length = @@ -13081,12 +13179,7 @@ Array_index_expression::do_get_backend(Translate_context* context) init.push_back(result_length); init.push_back(result_capacity); - Bexpression* ret = - gogo->backend()->constructor_expression(struct_btype, init, loc); - if (this->needs_bounds_check_) - ret = gogo->backend()->conditional_expression(bfn, struct_btype, bad_index, - crash, ret, loc); - return ret; + return gogo->backend()->constructor_expression(struct_btype, init, loc); } // Export an array index expression. @@ -13164,7 +13257,15 @@ Expression* String_index_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { + if (this->is_flattened_) + return this; + this->is_flattened_ = true; + Location loc = this->location(); + + if (this->is_error_expression()) + return Expression::make_error(loc); + Expression* string = this->string_; Expression* start = this->start_; Expression* end = this->end_; @@ -13180,27 +13281,69 @@ String_index_expression::do_flatten(Gogo*, Named_object*, } Temporary_statement* temp; - if (!this->string_->is_variable()) + if (!string->is_variable()) { - temp = Statement::make_temporary(NULL, this->string_, loc); + temp = Statement::make_temporary(NULL, string, loc); inserter->insert(temp); this->string_ = Expression::make_temporary_reference(temp, loc); + string = this->string_; } - if (!this->start_->is_variable()) + if (!start->is_variable()) { - temp = Statement::make_temporary(NULL, this->start_, loc); + temp = Statement::make_temporary(NULL, start, loc); inserter->insert(temp); this->start_ = Expression::make_temporary_reference(temp, loc); + start = this->start_; } - if (this->end_ != NULL - && !this->end_->is_nil_expression() - && !this->end_->is_variable()) + if (end != NULL + && !end->is_nil_expression() + && !end->is_variable()) { - temp = Statement::make_temporary(NULL, this->end_, loc); + temp = Statement::make_temporary(NULL, end, loc); inserter->insert(temp); this->end_ = Expression::make_temporary_reference(temp, loc); + end = this->end_; } + Expression* len = Expression::make_string_info(string->copy(), + STRING_INFO_LENGTH, loc); + temp = Statement::make_temporary(NULL, len, loc); + inserter->insert(temp); + len = Expression::make_temporary_reference(temp, loc); + + // The order of bounds checks here matches the order used by the gc + // compiler, as tested by issue30116[u].go. + + if (end != NULL && !end->is_nil_expression()) + { + Expression::check_bounds(end, OPERATOR_LE, len, + Runtime::PANIC_SLICE_ALEN, + Runtime::PANIC_SLICE_ALEN_U, + Runtime::PANIC_EXTEND_SLICE_ALEN, + Runtime::PANIC_EXTEND_SLICE_ALEN_U, + inserter, loc); + Expression::check_bounds(start, OPERATOR_LE, end, + Runtime::PANIC_SLICE_B, + Runtime::PANIC_SLICE_B_U, + Runtime::PANIC_EXTEND_SLICE_B, + Runtime::PANIC_EXTEND_SLICE_B_U, + inserter, loc); + } + else if (end != NULL) + Expression::check_bounds(start, OPERATOR_LE, len, + Runtime::PANIC_SLICE_B, + Runtime::PANIC_SLICE_B_U, + Runtime::PANIC_EXTEND_SLICE_B, + Runtime::PANIC_EXTEND_SLICE_B_U, + inserter, loc); + else + Expression::check_bounds(start, OPERATOR_LT, len, + Runtime::PANIC_INDEX, + Runtime::PANIC_INDEX_U, + Runtime::PANIC_EXTEND_INDEX, + Runtime::PANIC_EXTEND_INDEX_U, + inserter, loc); + return this; } @@ -13245,7 +13388,8 @@ String_index_expression::do_check_types(Gogo*) unsigned long v; if (this->start_->type()->integer_type() == NULL && !this->start_->type()->is_error() - && (!this->start_->numeric_constant_value(&nc) + && (!this->start_->type()->is_abstract() + || !this->start_->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("index must be integer")); if (this->end_ != NULL @@ -13253,7 +13397,8 @@ String_index_expression::do_check_types(Gogo*) && !this->end_->type()->is_error() && !this->end_->is_nil_expression() && !this->end_->is_error_expression() - && (!this->end_->numeric_constant_value(&nc) + && (!this->end_->type()->is_abstract() + || !this->end_->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("slice end must be integer")); @@ -13303,14 +13448,7 @@ Bexpression* String_index_expression::do_get_backend(Translate_context* context) { Location loc = this->location(); - Expression* bad_index = Expression::check_bounds(this->start_, loc); - - int code = (this->end_ == NULL - ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS); - Gogo* gogo = context->gogo(); - Bexpression* crash = gogo->runtime_error(code, loc)->get_backend(context); Type* int_type = Type::lookup_integer_type("int"); @@ -13342,21 +13480,9 @@ String_index_expression::do_get_backend(Translate_context* context) if (this->end_ == NULL) { - Expression* start_too_large = - Expression::make_binary(OPERATOR_GE, start, length, loc); - bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large, - bad_index, loc); - ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc); Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo); - Bexpression* index = - gogo->backend()->indirect_expression(ubtype, ptr, true, loc); - - Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo); - Bexpression* index_error = bad_index->get_backend(context); - return gogo->backend()->conditional_expression(bfn, byte_btype, - index_error, crash, - index, loc); + return gogo->backend()->indirect_expression(ubtype, ptr, true, loc); } Expression* end = NULL; @@ -13365,20 +13491,8 @@ String_index_expression::do_get_backend(Translate_context* context) else { go_assert(this->end_->is_variable()); - Expression* bounds_check = Expression::check_bounds(this->end_, loc); - bad_index = - Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc); end = Expression::make_cast(int_type, this->end_, loc); - - Expression* end_too_large = - Expression::make_binary(OPERATOR_GT, end, length, loc); - bad_index = Expression::make_binary(OPERATOR_OROR, end_too_large, - bad_index, loc); } - Expression* start_too_large = - Expression::make_binary(OPERATOR_GT, start->copy(), end->copy(), loc); - bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large, - bad_index, loc); end = end->copy(); Bexpression* bend = end->get_backend(context); @@ -13405,12 +13519,7 @@ String_index_expression::do_get_backend(Translate_context* context) std::vector<Bexpression*> init; init.push_back(ptr); init.push_back(new_length); - Bexpression* bstrslice = - gogo->backend()->constructor_expression(str_btype, init, loc); - - Bexpression* index_error = bad_index->get_backend(context); - return gogo->backend()->conditional_expression(bfn, str_btype, index_error, - crash, bstrslice, loc); + return gogo->backend()->constructor_expression(str_btype, init, loc); } // Export a string index expression. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 3b65e7a..4c743da 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1059,10 +1059,11 @@ class Expression static Expression* import_expression(Import_expression*, Location); - // Return an expression which checks that VAL, of arbitrary integer type, - // is non-negative and is not more than the maximum integer value. - static Expression* - check_bounds(Expression* val, Location); + // Insert bounds checks for an index expression. + static void + check_bounds(Expression* val, Operator, Expression* bound, Runtime::Function, + Runtime::Function, Runtime::Function, Runtime::Function, + Statement_inserter*, Location); // Return an expression for constructing a direct interface type from a // pointer. @@ -2998,7 +2999,7 @@ class Array_index_expression : public Expression Expression* end, Expression* cap, Location location) : Expression(EXPRESSION_ARRAY_INDEX, location), array_(array), start_(start), end_(end), cap_(cap), type_(NULL), - is_lvalue_(false), needs_bounds_check_(true) + is_lvalue_(false), needs_bounds_check_(true), is_flattened_(false) { } // Return the array. @@ -3121,6 +3122,8 @@ class Array_index_expression : public Expression bool is_lvalue_; // Whether bounds check is needed. bool needs_bounds_check_; + // Whether this has already been flattened. + bool is_flattened_; }; // A string index. This is used for both indexing and slicing. @@ -3131,7 +3134,7 @@ class String_index_expression : public Expression String_index_expression(Expression* string, Expression* start, Expression* end, Location location) : Expression(EXPRESSION_STRING_INDEX, location), - string_(string), start_(start), end_(end) + string_(string), start_(start), end_(end), is_flattened_(false) { } // Return the string being indexed. @@ -3203,6 +3206,8 @@ class String_index_expression : public Expression // The end index of a slice. This may be NULL for a single index, // or it may be a nil expression for the length of the string. Expression* end_; + // Whether this has already been flattened. + bool is_flattened_; }; // An index into a map. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 8a24070..7aec0cf 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -6300,6 +6300,7 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) } if (this->asm_name_ == "runtime.gopanic" + || this->asm_name_.compare(0, 15, "runtime.goPanic") == 0 || this->asm_name_ == "__go_runtime_error" || this->asm_name_ == "runtime.panicdottype" || this->asm_name_ == "runtime.block") diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index e35658b..3cc5ded 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -30,6 +30,8 @@ enum Runtime_function_type RFT_BOOLPTR, // Go type int, C type intgo. RFT_INT, + // Go type uint, C type uintgo. + RFT_UINT, // Go type uint8, C type uint8_t. RFT_UINT8, // Go type uint16, C type uint16_t. @@ -113,6 +115,10 @@ runtime_function_type(Runtime_function_type bft) t = Type::lookup_integer_type("int"); break; + case RFT_UINT: + t = Type::lookup_integer_type("uint"); + break; + case RFT_UINT8: t = Type::lookup_integer_type("uint8"); break; @@ -262,6 +268,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, case RFT_BOOL: case RFT_BOOLPTR: case RFT_INT: + case RFT_UINT: case RFT_UINT8: case RFT_UINT16: case RFT_INT32: diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 7eac880..d7f5ee2 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -499,6 +499,75 @@ DEF_GO_RUNTIME(ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1", P3(POINTER, UINT8, INT32), R1(UINT8)) +// Panics reporting an index or slice out of bounds error. +DEF_GO_RUNTIME(PANIC_INDEX, "runtime.goPanicIndex", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_INDEX_U, "runtime.goPanicIndexU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE_ALEN, "runtime.goPanicSliceAlen", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE_ALEN_U, "runtime.goPanicSliceAlenU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE_ACAP, "runtime.goPanicSliceAcap", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE_ACAP_U, "runtime.goPanicSliceAcapU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE_B, "runtime.goPanicSliceB", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE_B_U, "runtime.goPanicSliceBU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_ALEN, "runtime.goPanicSlice3Alen", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_ALEN_U, "runtime.goPanicSlice3AlenU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_ACAP, "runtime.goPanicSlice3Acap", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_ACAP_U, "runtime.goPanicSlice3AcapU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_B, "runtime.goPanicSlice3B", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_B_U, "runtime.goPanicSlice3BU", + P2(UINT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_C, "runtime.goPanicSlice3C", + P2(INT, INT), R0()) +DEF_GO_RUNTIME(PANIC_SLICE3_C_U, "runtime.goPanicSlice3CU", + P2(UINT, INT), R0()) + +// Panics reporting an index or slice out of bounds error with a +// 64-bit index type. These are only used by 32-bit targets. +DEF_GO_RUNTIME(PANIC_EXTEND_INDEX, "runtime.goPanicExtendIndex", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_INDEX_U, "runtime.goPanicExtendIndexU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ALEN, "runtime.goPanicExtendSliceAlen", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ALEN_U, "runtime.goPanicExtendSliceAlenU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ACAP, "runtime.goPanicExtendSliceAcap", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_ACAP_U, "runtime.goPanicExtendSliceAcapU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_B, "runtime.goPanicExtendSliceB", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE_B_U, "runtime.goPanicExtendSliceBU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ALEN, "runtime.goPanicExtendSlice3Alen", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ALEN_U, "runtime.goPanicExtendSlice3AlenU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ACAP, "runtime.goPanicExtendSlice3Acap", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_ACAP_U, "runtime.goPanicExtendSlice3AcapU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_B, "runtime.goPanicExtendSlice3B", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_B_U, "runtime.goPanicExtendSlice3BU", + P2(UINT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C, "runtime.goPanicExtendSlice3C", + P2(INT64, INT), R0()) +DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C_U, "runtime.goPanicExtendSlice3CU", + P2(UINT64, INT), R0()) + // Remove helper macros. #undef ABFT6 #undef ABFT2 |