diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-07-30 17:19:42 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-08-02 15:27:08 -0700 |
commit | 7459bfa8a37a4fbd6ed5153bff76f49d372b4ace (patch) | |
tree | e0c96ae718c359f5a026b93a2c3cf31eb4587fca /gcc/go | |
parent | 06d0437d4a5faca2b695918cbe1d54a61935c98b (diff) | |
download | gcc-7459bfa8a37a4fbd6ed5153bff76f49d372b4ace.zip gcc-7459bfa8a37a4fbd6ed5153bff76f49d372b4ace.tar.gz gcc-7459bfa8a37a4fbd6ed5153bff76f49d372b4ace.tar.bz2 |
compiler, runtime: allow slice to array pointer conversion
Panic if the slice is too short.
For golang/go#395
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/338630
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 53 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 7 |
4 files changed, 64 insertions, 3 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 19fbd64..95b9340 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -ad667e7c70cea9fa5730660d72ad891b5753eb62 +0a4d612e6b211780b294717503fc739bbd1f509c 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 46e71e5..15c9eab 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3866,11 +3866,12 @@ Type_conversion_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Convert to a constant at lowering time. +// Convert to a constant at lowering time. Also lower conversions +// from slice to pointer-to-array, as they can panic. Expression* Type_conversion_expression::do_lower(Gogo*, Named_object*, - Statement_inserter*, int) + Statement_inserter* inserter, int) { Type* type = this->type_; Expression* val = this->expr_; @@ -3958,6 +3959,54 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*, } } + if (type->points_to() != NULL + && type->points_to()->array_type() != NULL + && !type->points_to()->is_slice_type() + && val->type()->is_slice_type()) + { + Temporary_statement* val_temp = NULL; + if (!val->is_multi_eval_safe()) + { + val_temp = Statement::make_temporary(val->type(), NULL, location); + inserter->insert(val_temp); + val = Expression::make_set_and_use_temporary(val_temp, val, + location); + } + + Type* int_type = Type::lookup_integer_type("int"); + Temporary_statement* vallen_temp = + Statement::make_temporary(int_type, NULL, location); + inserter->insert(vallen_temp); + + Expression* arrlen = type->points_to()->array_type()->length(); + Expression* vallen = + Expression::make_slice_info(val, Expression::SLICE_INFO_LENGTH, + location); + vallen = Expression::make_set_and_use_temporary(vallen_temp, vallen, + location); + Expression* cond = Expression::make_binary(OPERATOR_GT, arrlen, vallen, + location); + + vallen = Expression::make_temporary_reference(vallen_temp, location); + Expression* panic = Runtime::make_call(Runtime::PANIC_SLICE_CONVERT, + location, 2, arrlen, vallen); + + Expression* nil = Expression::make_nil(location); + Expression* check = Expression::make_conditional(cond, panic, nil, + location); + + if (val_temp == NULL) + val = val->copy(); + else + val = Expression::make_temporary_reference(val_temp, location); + Expression* ptr = + Expression::make_slice_info(val, Expression::SLICE_INFO_VALUE_POINTER, + location); + ptr = Expression::make_unsafe_cast(type, ptr, location); + + return Expression::make_compound(check, ptr, location); + } + return this; } diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 231d92d..fad8ceb 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -582,6 +582,11 @@ DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C, "runtime.goPanicExtendSlice3C", DEF_GO_RUNTIME(PANIC_EXTEND_SLICE3_C_U, "runtime.goPanicExtendSlice3CU", P2(UINT64, INT), R0()) +// Panic for conversion of slice to pointer-to-array if the slice is +// too short. +DEF_GO_RUNTIME(PANIC_SLICE_CONVERT, "runtime.goPanicSliceConvert", + P2(INT, INT), R0()) + // Remove helper macros. #undef ABFT6 #undef ABFT2 diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index ab7166b..7c7b2eb 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -842,6 +842,13 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) return true; } + // A slice may be converted to a pointer-to-array. + if (rhs->is_slice_type() + && lhs->points_to() != NULL + && lhs->points_to()->array_type() != NULL + && !lhs->points_to()->is_slice_type()) + return true; + // An unsafe.Pointer type may be converted to any pointer type or to // a type whose underlying type is uintptr, and vice-versa. if (lhs->is_unsafe_pointer_type() |