// first field is just the type descriptor of the object.
go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
"__type_descriptor") == 0);
- go_assert(TREE_TYPE(field) == TREE_TYPE(rhs_type_descriptor));
- elt->value = rhs_type_descriptor;
+ elt->value = fold_convert_loc(location.gcc_location(),
+ TREE_TYPE(field), rhs_type_descriptor);
}
else
{
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())
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);
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);
// 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()));
&& op != OPERATOR_RSHIFT)
{
// May be a type error--let it be diagnosed later.
+ return this;
}
else if (is_comparison)
{
&& op != OPERATOR_RSHIFT)
{
// May be a type error--let it be diagnosed later.
+ return this;
}
else if (is_comparison)
{
&& 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)
{
}
// String constant expressions.
- if (op == OPERATOR_PLUS
- && left->type()->is_string_type()
- && right->type()->is_string_type())
+ if (left->type()->is_string_type() && right->type()->is_string_type())
{
std::string left_string;
std::string right_string;
if (left->string_constant_value(&left_string)
&& right->string_constant_value(&right_string))
- return Expression::make_string(left_string + right_string, location);
+ {
+ if (op == OPERATOR_PLUS)
+ return Expression::make_string(left_string + right_string,
+ location);
+ else if (is_comparison)
+ {
+ int cmp = left_string.compare(right_string);
+ bool r;
+ switch (op)
+ {
+ case OPERATOR_EQEQ:
+ r = cmp == 0;
+ break;
+ case OPERATOR_NOTEQ:
+ r = cmp != 0;
+ break;
+ case OPERATOR_LT:
+ r = cmp < 0;
+ break;
+ case OPERATOR_LE:
+ r = cmp <= 0;
+ break;
+ case OPERATOR_GT:
+ r = cmp > 0;
+ break;
+ case OPERATOR_GE:
+ r = cmp >= 0;
+ break;
+ default:
+ go_unreachable();
+ }
+ return Expression::make_boolean(r, location);
+ }
+ }
}
// Special case for shift of a floating point constant.
this->set_is_error();
return this;
}
- this->lower_varargs(gogo, function, inserter, slice_type, 2);
+ Type* element_type = slice_type->array_type()->element_type();
+ this->lower_varargs(gogo, function, inserter,
+ Type::make_array_type(element_type, NULL),
+ 2);
}
break;
return Expression::make_error(this->location());
}
+ bool have_big_args = false;
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ int uintptr_bits = uintptr_type->integer_type()->bits();
+
++parg;
Expression* len_arg;
if (parg == args->end())
this->report_error(_("bad size for make"));
return Expression::make_error(this->location());
}
+ if (len_arg->type()->integer_type() != NULL
+ && len_arg->type()->integer_type()->bits() > uintptr_bits)
+ have_big_args = true;
++parg;
}
this->report_error(_("bad capacity when making slice"));
return Expression::make_error(this->location());
}
+ if (cap_arg->type()->integer_type() != NULL
+ && cap_arg->type()->integer_type()->bits() > uintptr_bits)
+ have_big_args = true;
++parg;
}
if (is_slice)
{
if (cap_arg == NULL)
- call = Runtime::make_call(Runtime::MAKESLICE1, loc, 2, type_arg,
- len_arg);
+ call = Runtime::make_call((have_big_args
+ ? Runtime::MAKESLICE1BIG
+ : Runtime::MAKESLICE1),
+ loc, 2, type_arg, len_arg);
else
- call = Runtime::make_call(Runtime::MAKESLICE2, loc, 3, type_arg,
- len_arg, cap_arg);
+ call = Runtime::make_call((have_big_args
+ ? Runtime::MAKESLICE2BIG
+ : Runtime::MAKESLICE2),
+ loc, 3, type_arg, len_arg, cap_arg);
}
else if (is_map)
- call = Runtime::make_call(Runtime::MAKEMAP, loc, 2, type_arg, len_arg);
+ call = Runtime::make_call((have_big_args
+ ? Runtime::MAKEMAPBIG
+ : Runtime::MAKEMAP),
+ loc, 2, type_arg, len_arg);
else if (is_chan)
- call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+ call = Runtime::make_call((have_big_args
+ ? Runtime::MAKECHANBIG
+ : Runtime::MAKECHAN),
+ loc, 2, type_arg, len_arg);
else
go_unreachable();
case BUILTIN_INVALID:
case BUILTIN_NEW:
case BUILTIN_MAKE:
+ case BUILTIN_DELETE:
return;
case BUILTIN_LEN:
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;
}
+ // The language says that the second argument must be
+ // assignable to a slice of the element type of the first
+ // argument. We already know the first argument is a slice
+ // type.
+ Type* arg2_type = Type::make_array_type(e, NULL);
std::string reason;
- if (!Type::are_assignable(args->front()->type(), args->back()->type(),
- &reason))
+ if (!Type::are_assignable(arg2_type, args->back()->type(), &reason))
{
if (reason.empty())
- this->report_error(_("arguments 1 and 2 have different types"));
+ this->report_error(_("argument 2 has invalid type"));
else
{
- error_at(this->location(),
- "arguments 1 and 2 have different types (%s)",
+ error_at(this->location(), "argument 2 has invalid type (%s)",
reason.c_str());
this->set_is_error();
}
fnname = "__go_print_slice";
}
else
- go_unreachable();
+ {
+ go_assert(saw_errors());
+ return error_mark_node;
+ }
tree call = Gogo::call_builtin(pfndecl,
location,
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];
}
// This is to support builtin math functions when using 80387 math.
tree excess_type = NULL_TREE;
- if (TREE_CODE(fndecl) == FUNCTION_DECL
+ if (optimize
+ && TREE_CODE(fndecl) == FUNCTION_DECL
&& DECL_IS_BUILTIN(fndecl)
&& DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
&& nargs > 0
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();
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);
}
if (array_type->length() == NULL && !DECL_P(array_tree))
array_tree = save_expr(array_tree);
- tree length_tree = array_type->length_tree(gogo, array_tree);
- if (length_tree == error_mark_node)
- return error_mark_node;
- length_tree = save_expr(length_tree);
- tree length_type = TREE_TYPE(length_tree);
+
+ tree length_tree = NULL_TREE;
+ if (this->end_ == NULL || this->end_->is_nil_expression())
+ {
+ length_tree = array_type->length_tree(gogo, array_tree);
+ if (length_tree == error_mark_node)
+ return error_mark_node;
+ length_tree = save_expr(length_tree);
+ }
+
+ tree capacity_tree = NULL_TREE;
+ if (this->end_ != NULL)
+ {
+ capacity_tree = array_type->capacity_tree(gogo, array_tree);
+ if (capacity_tree == error_mark_node)
+ return error_mark_node;
+ capacity_tree = save_expr(capacity_tree);
+ }
+
+ tree length_type = (length_tree != NULL_TREE
+ ? TREE_TYPE(length_tree)
+ : TREE_TYPE(capacity_tree));
tree bad_index = boolean_false_node;
? GE_EXPR
: GT_EXPR),
boolean_type_node, start_tree,
- length_tree));
+ (this->end_ == NULL
+ ? length_tree
+ : capacity_tree)));
int code = (array_type->length() != NULL
? (this->end_ == NULL
// Array slice.
- tree capacity_tree = array_type->capacity_tree(gogo, array_tree);
- if (capacity_tree == error_mark_node)
- return error_mark_node;
- capacity_tree = fold_convert_loc(loc.gcc_location(), length_type,
- capacity_tree);
-
tree end_tree;
if (this->end_->is_nil_expression())
end_tree = length_tree;
end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree);
- capacity_tree = save_expr(capacity_tree);
tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
boolean_type_node,
fold_build2_loc(loc.gcc_location(),
const Typed_identifier_list* method_parameters = method_type->parameters();
if (method_parameters != NULL)
{
+ int i = 0;
for (Typed_identifier_list::const_iterator p = method_parameters->begin();
p != method_parameters->end();
- ++p)
- parameters->push_back(*p);
+ ++p, ++i)
+ {
+ if (!p->name().empty())
+ parameters->push_back(*p);
+ else
+ {
+ char buf[20];
+ snprintf(buf, sizeof buf, "$param%d", i);
+ parameters->push_back(Typed_identifier(buf, p->type(),
+ p->location()));
+ }
+ }
}
const Typed_identifier_list* method_results = method_type->results();
}
Expression_list* args;
- if (method_parameters == NULL)
+ if (parameters->size() <= 1)
args = NULL;
else
{
args = new Expression_list();
- for (Typed_identifier_list::const_iterator p = method_parameters->begin();
- p != method_parameters->end();
- ++p)
+ Typed_identifier_list::const_iterator p = parameters->begin();
+ ++p;
+ for (; p != parameters->end(); ++p)
{
vno = gogo->lookup(p->name(), NULL);
go_assert(vno != NULL);
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);