diff options
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 137 |
1 files changed, 94 insertions, 43 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 20c49f13b0e..90cf6f32dab 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -205,9 +205,6 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, Type* rhs_type, tree rhs_tree, Location location) { - if (lhs_type == rhs_type) - return rhs_tree; - if (lhs_type->is_error() || rhs_type->is_error()) return error_mark_node; @@ -220,7 +217,7 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, if (lhs_type_tree == error_mark_node) return error_mark_node; - if (lhs_type->interface_type() != NULL) + if (lhs_type != rhs_type && lhs_type->interface_type() != NULL) { if (rhs_type->interface_type() == NULL) return Expression::convert_type_to_interface(context, lhs_type, @@ -231,7 +228,7 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, rhs_type, rhs_tree, false, location); } - else if (rhs_type->interface_type() != NULL) + else if (lhs_type != rhs_type && rhs_type->interface_type() != NULL) return Expression::convert_interface_to_type(context, lhs_type, rhs_type, rhs_tree, location); else if (lhs_type->is_slice_type() && rhs_type->is_nil_type()) @@ -284,13 +281,21 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, || SCALAR_FLOAT_TYPE_P(lhs_type_tree) || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree); - else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE - && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE) + else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE + && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE) + || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE + && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE)) { + // Avoid confusion from zero sized variables which may be + // represented as non-zero-sized. + if (int_size_in_bytes(lhs_type_tree) == 0 + || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) + return rhs_tree; + // This conversion must be permitted by Go, or we wouldn't have // gotten here. go_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); + == int_size_in_bytes(TREE_TYPE(rhs_tree))); return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, lhs_type_tree, rhs_tree); } @@ -3942,10 +3947,6 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context) go_assert(et->map_type() != NULL); else if (t->channel_type() != NULL) go_assert(et->channel_type() != NULL); - else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL) - go_assert((et->points_to() != NULL - && et->points_to()->channel_type() != NULL) - || et->is_nil_type()); else if (t->points_to() != NULL) go_assert(et->points_to() != NULL || et->is_nil_type()); else if (et->is_unsafe_pointer_type()) @@ -4304,14 +4305,23 @@ Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val, unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count]; memset(phwi, 0, count * sizeof(HOST_WIDE_INT)); + size_t obits = utype->integer_type()->bits(); + + if (!utype->integer_type()->is_unsigned() + && mpz_sgn(uval) < 0) + { + mpz_t adj; + mpz_init_set_ui(adj, 1); + mpz_mul_2exp(adj, adj, obits); + mpz_add(uval, uval, adj); + mpz_clear(adj); + } + size_t ecount; mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval); go_assert(ecount <= count); // Trim down to the number of words required by the type. - size_t obits = utype->integer_type()->bits(); - if (!utype->integer_type()->is_unsigned()) - ++obits; size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT); go_assert(ocount <= count); @@ -4326,6 +4336,16 @@ Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val, mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi); + if (!utype->integer_type()->is_unsigned() + && mpz_tstbit(val, obits - 1)) + { + mpz_t adj; + mpz_init_set_ui(adj, 1); + mpz_mul_2exp(adj, adj, obits); + mpz_sub(val, val, adj); + mpz_clear(adj); + } + delete[] phwi; } return Integer_expression::check_constant(val, utype, location); @@ -4690,29 +4710,33 @@ Unary_expression::do_get_tree(Translate_context* context) // need to check for nil. We don't bother to check for small // structs because we expect the system to crash on a nil // pointer dereference. - HOST_WIDE_INT s = int_size_in_bytes(TREE_TYPE(TREE_TYPE(expr))); - if (s == -1 || s >= 4096) + tree target_type_tree = TREE_TYPE(TREE_TYPE(expr)); + if (!VOID_TYPE_P(target_type_tree)) { - if (!DECL_P(expr)) - expr = save_expr(expr); - tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR, - boolean_type_node, - expr, - fold_convert(TREE_TYPE(expr), - null_pointer_node)); - tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc); - expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(expr), build3(COND_EXPR, - void_type_node, - compare, crash, - NULL_TREE), - expr); + HOST_WIDE_INT s = int_size_in_bytes(target_type_tree); + if (s == -1 || s >= 4096) + { + if (!DECL_P(expr)) + expr = save_expr(expr); + tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR, + boolean_type_node, + expr, + fold_convert(TREE_TYPE(expr), + null_pointer_node)); + tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, + loc); + expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, + TREE_TYPE(expr), build3(COND_EXPR, + void_type_node, + compare, crash, + NULL_TREE), + expr); + } } // If the type of EXPR is a recursive pointer type, then we // need to insert a cast before indirecting. - if (TREE_TYPE(TREE_TYPE(expr)) == ptr_type_node) + if (VOID_TYPE_P(target_type_tree)) { Type* pt = this->expr_->type()->points_to(); tree ind = type_to_tree(pt->get_backend(context->gogo())); @@ -5564,6 +5588,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, && op != OPERATOR_RSHIFT) { // May be a type error--let it be diagnosed later. + return this; } else if (is_comparison) { @@ -5667,6 +5692,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, && op != OPERATOR_RSHIFT) { // May be a type error--let it be diagnosed later. + return this; } else if (is_comparison) { @@ -5750,6 +5776,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, && left_type->base() != right_type->base()) { // May be a type error--let it be diagnosed later. + return this; } else if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) { @@ -8499,6 +8526,7 @@ Builtin_call_expression::do_check_types(Gogo*) case BUILTIN_INVALID: case BUILTIN_NEW: case BUILTIN_MAKE: + case BUILTIN_DELETE: return; case BUILTIN_LEN: @@ -8667,13 +8695,17 @@ Builtin_call_expression::do_check_types(Gogo*) this->report_error(_("too many arguments")); break; } + if (args->front()->type()->is_error() + || args->back()->type()->is_error()) + break; + + Array_type* at = args->front()->type()->array_type(); + Type* e = at->element_type(); // The language permits appending a string to a []byte, as a // special case. if (args->back()->type()->is_string_type()) { - const Array_type* at = args->front()->type()->array_type(); - const Type* e = at->element_type()->forwarded(); if (e->integer_type() != NULL && e->integer_type()->is_byte()) break; } @@ -8682,8 +8714,7 @@ Builtin_call_expression::do_check_types(Gogo*) // assignable to a slice of the element type of the first // argument. We already know the first argument is a slice // type. - Array_type* at = args->front()->type()->array_type(); - Type* arg2_type = Type::make_array_type(at->element_type(), NULL); + Type* arg2_type = Type::make_array_type(e, NULL); std::string reason; if (!Type::are_assignable(arg2_type, args->back()->type(), &reason)) { @@ -8979,7 +9010,10 @@ Builtin_call_expression::do_get_tree(Translate_context* context) fnname = "__go_print_slice"; } else - go_unreachable(); + { + go_assert(saw_errors()); + return error_mark_node; + } tree call = Gogo::call_builtin(pfndecl, location, @@ -9662,8 +9696,11 @@ Call_expression::result_count() const Temporary_statement* Call_expression::result(size_t i) const { - go_assert(this->results_ != NULL - && this->results_->size() > i); + if (this->results_ == NULL || this->results_->size() <= i) + { + go_assert(saw_errors()); + return NULL; + } return (*this->results_)[i]; } @@ -10150,6 +10187,11 @@ Call_expression::set_results(Translate_context* context, tree call_tree) go_assert(field != NULL_TREE); Temporary_statement* temp = this->result(i); + if (temp == NULL) + { + go_assert(saw_errors()); + return error_mark_node; + } Temporary_reference_expression* ref = Expression::make_temporary_reference(temp, loc); ref->set_is_lvalue(); @@ -10329,8 +10371,17 @@ tree Call_result_expression::do_get_tree(Translate_context* context) { Call_expression* ce = this->call_->call_expression(); - go_assert(ce != NULL); + if (ce == NULL) + { + go_assert(this->call_->is_error_expression()); + return error_mark_node; + } Temporary_statement* ts = ce->result(this->index_); + if (ts == NULL) + { + go_assert(saw_errors()); + return error_mark_node; + } Expression* ref = Expression::make_temporary_reference(ts, this->location()); return ref->get_tree(context); } @@ -11780,7 +11831,7 @@ Selector_expression::lower_method_expression(Gogo* gogo) p != method_parameters->end(); ++p, ++i) { - if (!p->name().empty() && p->name() != Import::import_marker) + if (!p->name().empty()) parameters->push_back(*p); else { @@ -13836,7 +13887,7 @@ tree Heap_composite_expression::do_get_tree(Translate_context* context) { tree expr_tree = this->expr_->get_tree(context); - if (expr_tree == error_mark_node) + if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node) return error_mark_node; tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree)); go_assert(TREE_CODE(expr_size) == INTEGER_CST); |