This implements https://golang.org/cl/161477 in the gofrontend.
Updates golang/go#30116
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/191881
From-SVN: r274998
-a6ddd0e1208a7d229c10be630c1110b3914038f5
+189ff44b2c26f29f41f0eb159e0d8f3fa508ecae
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
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
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
&& !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
&& !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"));
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_;
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;
}
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())
{
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_);
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())
{
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 =
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.
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_;
}
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;
}
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
&& !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"));
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");
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;
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);
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.
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.
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.
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.
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.
// 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.
}
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")
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.
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;
case RFT_BOOL:
case RFT_BOOLPTR:
case RFT_INT:
+ case RFT_UINT:
case RFT_UINT8:
case RFT_UINT16:
case RFT_INT32:
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
return string(r[:j])
}
+//go:nosplit
+// itoa converts val to a decimal representation. The result is
+// written somewhere within buf and the location of the result is returned.
+// buf must be at least 20 bytes.
+func itoa(buf []byte, val uint64) []byte {
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return buf[i:]
+}
+
// An errorString represents a runtime error described by a single string.
type errorString string
return string(e)
}
+// An boundsError represents a an indexing or slicing operation gone wrong.
+type boundsError struct {
+ x int64
+ y int
+ // Values in an index or slice expression can be signed or unsigned.
+ // That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1.
+ // Instead, we keep track of whether x should be interpreted as signed or unsigned.
+ // y is known to be nonnegative and to fit in an int.
+ signed bool
+ code boundsErrorCode
+}
+
+type boundsErrorCode uint8
+
+const (
+ boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed
+
+ boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed
+ boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed
+ boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen)
+
+ boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed
+ boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed
+ boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen)
+ boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen)
+
+ // Note: in the above, len(s) and cap(s) are stored in y
+)
+
+// boundsErrorFmts provide error text for various out-of-bounds panics.
+// Note: if you change these strings, you should adjust the size of the buffer
+// in boundsError.Error below as well.
+var boundsErrorFmts = [...]string{
+ boundsIndex: "index out of range [%x] with length %y",
+ boundsSliceAlen: "slice bounds out of range [:%x] with length %y",
+ boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y",
+ boundsSliceB: "slice bounds out of range [%x:%y]",
+ boundsSlice3Alen: "slice bounds out of range [::%x] with length %y",
+ boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y",
+ boundsSlice3B: "slice bounds out of range [:%x:%y]",
+ boundsSlice3C: "slice bounds out of range [%x:%y:]",
+}
+
+// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y.
+var boundsNegErrorFmts = [...]string{
+ boundsIndex: "index out of range [%x]",
+ boundsSliceAlen: "slice bounds out of range [:%x]",
+ boundsSliceAcap: "slice bounds out of range [:%x]",
+ boundsSliceB: "slice bounds out of range [%x:]",
+ boundsSlice3Alen: "slice bounds out of range [::%x]",
+ boundsSlice3Acap: "slice bounds out of range [::%x]",
+ boundsSlice3B: "slice bounds out of range [:%x:]",
+ boundsSlice3C: "slice bounds out of range [%x::]",
+}
+
+func (e boundsError) RuntimeError() {}
+
+func appendIntStr(b []byte, v int64, signed bool) []byte {
+ if signed && v < 0 {
+ b = append(b, '-')
+ v = -v
+ }
+ var buf [20]byte
+ b = append(b, itoa(buf[:], uint64(v))...)
+ return b
+}
+
+func (e boundsError) Error() string {
+ fmt := boundsErrorFmts[e.code]
+ if e.signed && e.x < 0 {
+ fmt = boundsNegErrorFmts[e.code]
+ }
+ // max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y"
+ // x can be at most 20 characters. y can be at most 19.
+ b := make([]byte, 0, 100)
+ b = append(b, "runtime error: "...)
+ for i := 0; i < len(fmt); i++ {
+ c := fmt[i]
+ if c != '%' {
+ b = append(b, c)
+ continue
+ }
+ i++
+ switch fmt[i] {
+ case 'x':
+ b = appendIntStr(b, e.x, e.signed)
+ case 'y':
+ b = appendIntStr(b, int64(e.y), true)
+ }
+ }
+ return string(b)
+}
+
type stringer interface {
String() string
}
//go:linkname makefuncreturning runtime.makefuncreturning
//go:linkname gorecover runtime.gorecover
//go:linkname deferredrecover runtime.deferredrecover
+//go:linkname goPanicIndex runtime.goPanicIndex
+//go:linkname goPanicIndexU runtime.goPanicIndexU
+//go:linkname goPanicSliceAlen runtime.goPanicSliceAlen
+//go:linkname goPanicSliceAlenU runtime.goPanicSliceAlenU
+//go:linkname goPanicSliceAcap runtime.goPanicSliceAcap
+//go:linkname goPanicSliceAcapU runtime.goPanicSliceAcapU
+//go:linkname goPanicSliceB runtime.goPanicSliceB
+//go:linkname goPanicSliceBU runtime.goPanicSliceBU
+//go:linkname goPanicSlice3Alen runtime.goPanicSlice3Alen
+//go:linkname goPanicSlice3AlenU runtime.goPanicSlice3AlenU
+//go:linkname goPanicSlice3Acap runtime.goPanicSlice3Acap
+//go:linkname goPanicSlice3AcapU runtime.goPanicSlice3AcapU
+//go:linkname goPanicSlice3B runtime.goPanicSlice3B
+//go:linkname goPanicSlice3BU runtime.goPanicSlice3BU
+//go:linkname goPanicSlice3C runtime.goPanicSlice3C
+//go:linkname goPanicSlice3CU runtime.goPanicSlice3CU
//go:linkname panicmem runtime.panicmem
// Temporary for C code to call:
//go:linkname throw runtime.throw
-// Calling panic with one of the errors below will call errorString.Error
-// which will call mallocgc to concatenate strings. That will fail if
-// malloc is locked, causing a confusing error message. Throw a better
-// error message instead.
-func panicCheckMalloc(err error) {
+// Check to make sure we can really generate a panic. If the panic
+// was generated from the runtime, or from inside malloc, then convert
+// to a throw of msg.
+// pc should be the program counter of the compiler-generated code that
+// triggered this panic.
+func panicCheck1(pc uintptr, msg string) {
+ name, _, _, _ := funcfileline(pc-1, -1)
+ if hasPrefix(name, "runtime.") {
+ throw(msg)
+ }
+ // TODO: is this redundant? How could we be in malloc
+ // but not in the runtime? runtime/internal/*, maybe?
gp := getg()
if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
- throw(string(err.(errorString)))
+ throw(msg)
}
}
-var indexError = error(errorString("index out of range"))
+// Same as above, but calling from the runtime is allowed.
+//
+// Using this function is necessary for any panic that may be
+// generated by runtime.sigpanic, since those are always called by the
+// runtime.
+func panicCheck2(err string) {
+ // panic allocates, so to avoid recursive malloc, turn panics
+ // during malloc into throws.
+ gp := getg()
+ if gp != nil && gp.m != nil && gp.m.mallocing != 0 {
+ throw(err)
+ }
+}
-// The panicindex, panicslice, and panicdivide functions are called by
+// Many of the following panic entry-points turn into throws when they
+// happen in various runtime contexts. These should never happen in
+// the runtime, and if they do, they indicate a serious issue and
+// should not be caught by user code.
+//
+// The panic{Index,Slice,divide,shift} functions are called by
// code generated by the compiler for out of bounds index expressions,
-// out of bounds slice expressions, and division by zero. The
-// panicdivide (again), panicoverflow, panicfloat, and panicmem
+// out of bounds slice expressions, division by zero, and shift by negative.
+// The panicdivide (again), panicoverflow, panicfloat, and panicmem
// functions are called by the signal handler when a signal occurs
// indicating the respective problem.
//
-// Since panicindex and panicslice are never called directly, and
+// Since panic{Index,Slice,shift} are never called directly, and
// since the runtime package should never have an out of bounds slice
-// or array reference, if we see those functions called from the
+// or array reference or negative shift, if we see those functions called from the
// runtime package we turn the panic into a throw. That will dump the
// entire runtime stack for easier debugging.
+//
+// The entry points called by the signal handler will be called from
+// runtime.sigpanic, so we can't disallow calls from the runtime to
+// these (they always look like they're called from the runtime).
+// Hence, for these, we just check for clearly bad runtime conditions.
+
+// failures in the comparisons for s[x], 0 <= x < y (y == len(s))
+func goPanicIndex(x int, y int) {
+ panicCheck1(getcallerpc(), "index out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsIndex})
+}
+func goPanicIndexU(x uint, y int) {
+ panicCheck1(getcallerpc(), "index out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex})
+}
-func panicindex() {
- name, _, _, _ := funcfileline(getcallerpc()-1, -1)
- if hasPrefix(name, "runtime.") {
- throw(string(indexError.(errorString)))
- }
- panicCheckMalloc(indexError)
- panic(indexError)
+// failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s))
+func goPanicSliceAlen(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAlen})
+}
+func goPanicSliceAlenU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen})
+}
+func goPanicSliceAcap(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAcap})
+}
+func goPanicSliceAcapU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap})
}
-var sliceError = error(errorString("slice bounds out of range"))
+// failures in the comparisons for s[x:y], 0 <= x <= y
+func goPanicSliceB(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceB})
+}
+func goPanicSliceBU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB})
+}
-func panicslice() {
- name, _, _, _ := funcfileline(getcallerpc()-1, -1)
- if hasPrefix(name, "runtime.") {
- throw(string(sliceError.(errorString)))
- }
- panicCheckMalloc(sliceError)
- panic(sliceError)
+// failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s))
+func goPanicSlice3Alen(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Alen})
+}
+func goPanicSlice3AlenU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen})
+}
+func goPanicSlice3Acap(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Acap})
+}
+func goPanicSlice3AcapU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap})
+}
+
+// failures in the comparisons for s[:x:y], 0 <= x <= y
+func goPanicSlice3B(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3B})
+}
+func goPanicSlice3BU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B})
+}
+
+// failures in the comparisons for s[x:y:], 0 <= x <= y
+func goPanicSlice3C(x int, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3C})
+}
+func goPanicSlice3CU(x uint, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C})
+}
+
+var shiftError = error(errorString("negative shift amount"))
+
+func panicshift() {
+ panicCheck1(getcallerpc(), "negative shift amount")
+ panic(shiftError)
}
var divideError = error(errorString("integer divide by zero"))
func panicdivide() {
- panicCheckMalloc(divideError)
+ panicCheck2("integer divide by zero")
panic(divideError)
}
var overflowError = error(errorString("integer overflow"))
func panicoverflow() {
- panicCheckMalloc(overflowError)
+ panicCheck2("integer overflow")
panic(overflowError)
}
var floatError = error(errorString("floating point error"))
func panicfloat() {
- panicCheckMalloc(floatError)
+ panicCheck2("floating point error")
panic(floatError)
}
var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
func panicmem() {
- panicCheckMalloc(memoryError)
+ panicCheck2("invalid memory address or nil pointer dereference")
panic(memoryError)
}
--- /dev/null
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64p32 arm mips mipsle m68k nios2 sh shbe
+
+package runtime
+
+import _ "unsafe" // for go:linkname
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname goPanicExtendIndex runtime.goPanicExtendIndex
+//go:linkname goPanicExtendIndexU runtime.goPanicExtendIndexU
+//go:linkname goPanicExtendSliceAlen runtime.goPanicExtendSliceAlen
+//go:linkname goPanicExtendSliceAlenU runtime.goPanicExtendSliceAlenU
+//go:linkname goPanicExtendSliceAcap runtime.goPanicExtendSliceAcap
+//go:linkname goPanicExtendSliceAcapU runtime.goPanicExtendSliceAcapU
+//go:linkname goPanicExtendSliceB runtime.goPanicExtendSliceB
+//go:linkname goPanicExtendSliceBU runtime.goPanicExtendSliceBU
+//go:linkname goPanicExtendSlice3Alen runtime.goPanicExtendSlice3Alen
+//go:linkname goPanicExtendSlice3AlenU runtime.goPanicExtendSlice3AlenU
+//go:linkname goPanicExtendSlice3Acap runtime.goPanicExtendSlice3Acap
+//go:linkname goPanicExtendSlice3AcapU runtime.goPanicExtendSlice3AcapU
+//go:linkname goPanicExtendSlice3B runtime.goPanicExtendSlice3B
+//go:linkname goPanicExtendSlice3BU runtime.goPanicExtendSlice3BU
+//go:linkname goPanicExtendSlice3C runtime.goPanicExtendSlice3C
+//go:linkname goPanicExtendSlice3CU runtime.goPanicExtendSlice3CU
+
+// Additional index/slice error paths for 32-bit platforms.
+// Used when the high word of a 64-bit index is not zero.
+
+// failures in the comparisons for s[x], 0 <= x < y (y == len(s))
+func goPanicExtendIndex(x int64, y int) {
+ panicCheck1(getcallerpc(), "index out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsIndex})
+}
+func goPanicExtendIndexU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "index out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex})
+}
+
+// failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s))
+func goPanicExtendSliceAlen(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSliceAlen})
+}
+func goPanicExtendSliceAlenU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen})
+}
+func goPanicExtendSliceAcap(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSliceAcap})
+}
+func goPanicExtendSliceAcapU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap})
+}
+
+// failures in the comparisons for s[x:y], 0 <= x <= y
+func goPanicExtendSliceB(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSliceB})
+}
+func goPanicExtendSliceBU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB})
+}
+
+// failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s))
+func goPanicExtendSlice3Alen(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3Alen})
+}
+func goPanicExtendSlice3AlenU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen})
+}
+func goPanicExtendSlice3Acap(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3Acap})
+}
+func goPanicExtendSlice3AcapU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap})
+}
+
+// failures in the comparisons for s[:x:y], 0 <= x <= y
+func goPanicExtendSlice3B(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3B})
+}
+func goPanicExtendSlice3BU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B})
+}
+
+// failures in the comparisons for s[x:y:], 0 <= x <= y
+func goPanicExtendSlice3C(x int64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: x, signed: true, y: y, code: boundsSlice3C})
+}
+func goPanicExtendSlice3CU(x uint64, y int) {
+ panicCheck1(getcallerpc(), "slice bounds out of range")
+ panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C})
+}
# types and should not be exported back to C
# semt is a Go translation of the C type sem_t; it fails to convert on
# some systems and need not be exported back to C.
-# sigset conflicts with system type sigset on AIX, so we need to rename it
+# sigset conflicts with system type sigset on AIX, so we need to rename it.
+# boundsError has a field name that is a C keyword, and we don't need it.
grep -v "#define _" ${IN} | grep -v "#define [cm][01234] " | grep -v "#define empty " | grep -v "#define \\$" > runtime.inc.tmp2
for pattern in '_[GP][a-z]' _Max _Lock _Sig _Trace _MHeap _Num
do
grep "#define $pattern" ${IN} >> runtime.inc.tmp2
done
-TYPES="_Complex_lock _Reader_lock semt"
+TYPES="_Complex_lock _Reader_lock semt boundsError"
for TYPE in $TYPES
do
sed -e '/struct '${TYPE}' {/,/^}/s/^.*$//' runtime.inc.tmp2 > runtime.inc.tmp3;