aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc475
-rw-r--r--gcc/go/gofrontend/expressions.h17
-rw-r--r--gcc/go/gofrontend/gogo.cc1
-rw-r--r--gcc/go/gofrontend/runtime.cc7
-rw-r--r--gcc/go/gofrontend/runtime.def69
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