summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/expressions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r--gcc/go/gofrontend/expressions.cc137
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);