Commit f29ce5f5 by Ian Lance Taylor

Implement predeclared delete function.

From-SVN: r180438
parent 09367c0d
...@@ -7048,6 +7048,7 @@ class Builtin_call_expression : public Call_expression ...@@ -7048,6 +7048,7 @@ class Builtin_call_expression : public Call_expression
BUILTIN_CLOSE, BUILTIN_CLOSE,
BUILTIN_COMPLEX, BUILTIN_COMPLEX,
BUILTIN_COPY, BUILTIN_COPY,
BUILTIN_DELETE,
BUILTIN_IMAG, BUILTIN_IMAG,
BUILTIN_LEN, BUILTIN_LEN,
BUILTIN_MAKE, BUILTIN_MAKE,
...@@ -7113,6 +7114,8 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo, ...@@ -7113,6 +7114,8 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
this->code_ = BUILTIN_COMPLEX; this->code_ = BUILTIN_COMPLEX;
else if (name == "copy") else if (name == "copy")
this->code_ = BUILTIN_COPY; this->code_ = BUILTIN_COPY;
else if (name == "delete")
this->code_ = BUILTIN_DELETE;
else if (name == "imag") else if (name == "imag")
this->code_ = BUILTIN_IMAG; this->code_ = BUILTIN_IMAG;
else if (name == "len") else if (name == "len")
...@@ -7206,34 +7209,15 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -7206,34 +7209,15 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
if (this->classification() == EXPRESSION_ERROR) if (this->classification() == EXPRESSION_ERROR)
return this; return this;
source_location loc = this->location();
if (this->is_varargs() && this->code_ != BUILTIN_APPEND) if (this->is_varargs() && this->code_ != BUILTIN_APPEND)
{ {
this->report_error(_("invalid use of %<...%> with builtin function")); this->report_error(_("invalid use of %<...%> with builtin function"));
return Expression::make_error(this->location()); return Expression::make_error(loc);
} }
if (this->code_ == BUILTIN_NEW) if (this->is_constant())
{
const Expression_list* args = this->args();
if (args == NULL || args->size() < 1)
this->report_error(_("not enough arguments"));
else if (args->size() > 1)
this->report_error(_("too many arguments"));
else
{
Expression* arg = args->front();
if (!arg->is_type_expression())
{
error_at(arg->location(), "expected type");
this->set_is_error();
}
else
return Expression::make_allocation(arg->type(), this->location());
}
}
else if (this->code_ == BUILTIN_MAKE)
return this->lower_make();
else if (this->is_constant())
{ {
// We can only lower len and cap if there are no function calls // We can only lower len and cap if there are no function calls
// in the arguments. Otherwise we have to make the call. // in the arguments. Otherwise we have to make the call.
...@@ -7254,8 +7238,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -7254,8 +7238,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
Type* type; Type* type;
if (this->integer_constant_value(true, ival, &type)) if (this->integer_constant_value(true, ival, &type))
{ {
Expression* ret = Expression::make_integer(&ival, type, Expression* ret = Expression::make_integer(&ival, type, loc);
this->location());
mpz_clear(ival); mpz_clear(ival);
return ret; return ret;
} }
...@@ -7265,8 +7248,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -7265,8 +7248,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
mpfr_init(rval); mpfr_init(rval);
if (this->float_constant_value(rval, &type)) if (this->float_constant_value(rval, &type))
{ {
Expression* ret = Expression::make_float(&rval, type, Expression* ret = Expression::make_float(&rval, type, loc);
this->location());
mpfr_clear(rval); mpfr_clear(rval);
return ret; return ret;
} }
...@@ -7275,8 +7257,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -7275,8 +7257,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
mpfr_init(imag); mpfr_init(imag);
if (this->complex_constant_value(rval, imag, &type)) if (this->complex_constant_value(rval, imag, &type))
{ {
Expression* ret = Expression::make_complex(&rval, &imag, type, Expression* ret = Expression::make_complex(&rval, &imag, type, loc);
this->location());
mpfr_clear(rval); mpfr_clear(rval);
mpfr_clear(imag); mpfr_clear(imag);
return ret; return ret;
...@@ -7284,34 +7265,100 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -7284,34 +7265,100 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
mpfr_clear(rval); mpfr_clear(rval);
mpfr_clear(imag); mpfr_clear(imag);
} }
else if (this->code_ == BUILTIN_RECOVER)
switch (this->code_)
{ {
default:
break;
case BUILTIN_NEW:
{
const Expression_list* args = this->args();
if (args == NULL || args->size() < 1)
this->report_error(_("not enough arguments"));
else if (args->size() > 1)
this->report_error(_("too many arguments"));
else
{
Expression* arg = args->front();
if (!arg->is_type_expression())
{
error_at(arg->location(), "expected type");
this->set_is_error();
}
else
return Expression::make_allocation(arg->type(), loc);
}
}
break;
case BUILTIN_MAKE:
return this->lower_make();
case BUILTIN_RECOVER:
if (function != NULL) if (function != NULL)
function->func_value()->set_calls_recover(); function->func_value()->set_calls_recover();
else else
{ {
// Calling recover outside of a function always returns the // Calling recover outside of a function always returns the
// nil empty interface. // nil empty interface.
Type* eface = Type::make_interface_type(NULL, this->location()); Type* eface = Type::make_interface_type(NULL, loc);
return Expression::make_cast(eface, return Expression::make_cast(eface, Expression::make_nil(loc), loc);
Expression::make_nil(this->location()),
this->location());
} }
} break;
else if (this->code_ == BUILTIN_APPEND)
{ case BUILTIN_APPEND:
// Lower the varargs. {
const Expression_list* args = this->args(); // Lower the varargs.
if (args == NULL || args->empty()) const Expression_list* args = this->args();
return this; if (args == NULL || args->empty())
Type* slice_type = args->front()->type();
if (!slice_type->is_slice_type())
{
error_at(args->front()->location(), "argument 1 must be a slice");
this->set_is_error();
return this; return this;
} Type* slice_type = args->front()->type();
this->lower_varargs(gogo, function, inserter, slice_type, 2); if (!slice_type->is_slice_type())
{
error_at(args->front()->location(), "argument 1 must be a slice");
this->set_is_error();
return this;
}
this->lower_varargs(gogo, function, inserter, slice_type, 2);
}
break;
case BUILTIN_DELETE:
{
// Lower to a runtime function call.
const Expression_list* args = this->args();
if (args == NULL || args->size() < 2)
this->report_error(_("not enough arguments"));
else if (args->size() > 2)
this->report_error(_("too many arguments"));
else if (args->front()->type()->map_type() == NULL)
this->report_error(_("argument 1 must be a map"));
else
{
// Since this function returns no value it must appear in
// a statement by itself, so we don't have to worry about
// order of evaluation of values around it. Evaluate the
// map first to get order of evaluation right.
Map_type* mt = args->front()->type()->map_type();
Temporary_statement* map_temp =
Statement::make_temporary(mt, args->front(), loc);
inserter->insert(map_temp);
Temporary_statement* key_temp =
Statement::make_temporary(mt->key_type(), args->back(), loc);
inserter->insert(key_temp);
Expression* e1 = Expression::make_temporary_reference(map_temp,
loc);
Expression* e2 = Expression::make_temporary_reference(key_temp,
loc);
e2 = Expression::make_unary(OPERATOR_AND, e2, loc);
return Runtime::make_call(Runtime::MAPDELETE, this->location(),
2, e1, e2);
}
}
break;
} }
return this; return this;
...@@ -7845,6 +7892,7 @@ Builtin_call_expression::do_discarding_value() ...@@ -7845,6 +7892,7 @@ Builtin_call_expression::do_discarding_value()
case BUILTIN_CLOSE: case BUILTIN_CLOSE:
case BUILTIN_COPY: case BUILTIN_COPY:
case BUILTIN_DELETE:
case BUILTIN_PANIC: case BUILTIN_PANIC:
case BUILTIN_PRINT: case BUILTIN_PRINT:
case BUILTIN_PRINTLN: case BUILTIN_PRINTLN:
...@@ -7882,6 +7930,7 @@ Builtin_call_expression::do_type() ...@@ -7882,6 +7930,7 @@ Builtin_call_expression::do_type()
return Type::lookup_integer_type("int"); return Type::lookup_integer_type("int");
case BUILTIN_CLOSE: case BUILTIN_CLOSE:
case BUILTIN_DELETE:
case BUILTIN_PANIC: case BUILTIN_PANIC:
case BUILTIN_PRINT: case BUILTIN_PRINT:
case BUILTIN_PRINTLN: case BUILTIN_PRINTLN:
......
...@@ -201,6 +201,11 @@ Gogo::Gogo(Backend* backend, int int_type_size, int pointer_size) ...@@ -201,6 +201,11 @@ Gogo::Gogo(Backend* backend, int int_type_size, int pointer_size)
imag_type->set_is_varargs(); imag_type->set_is_varargs();
imag_type->set_is_builtin(); imag_type->set_is_builtin();
this->globals_->add_function_declaration("imag", NULL, imag_type, loc); this->globals_->add_function_declaration("imag", NULL, imag_type, loc);
Function_type* delete_type = Type::make_function_type(NULL, NULL, NULL, loc);
delete_type->set_is_varargs();
delete_type->set_is_builtin();
this->globals_->add_function_declaration("delete", NULL, delete_type, loc);
} }
// Munge name for use in an error message. // Munge name for use in an error message.
......
...@@ -94,6 +94,9 @@ DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2", ...@@ -94,6 +94,9 @@ DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2",
DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2", DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2",
P4(MAP, POINTER, POINTER, BOOL), R0()) P4(MAP, POINTER, POINTER, BOOL), R0())
// Delete a key from a map.
DEF_GO_RUNTIME(MAPDELETE, "runtime.mapdelete", P2(MAP, POINTER), R0())
// Begin a range over a map. // Begin a range over a map.
DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0()) DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0())
......
...@@ -27,7 +27,7 @@ __go_map_delete (struct __go_map *map, const void *key) ...@@ -27,7 +27,7 @@ __go_map_delete (struct __go_map *map, const void *key)
void **pentry; void **pentry;
if (map == NULL) if (map == NULL)
__go_panic_msg ("assignment to entry in nil map"); __go_panic_msg ("deletion of entry in nil map");
descriptor = map->__descriptor; descriptor = map->__descriptor;
......
...@@ -45,6 +45,12 @@ func mapassign2(h *Hmap, key *byte, val *byte, p bool) { ...@@ -45,6 +45,12 @@ func mapassign2(h *Hmap, key *byte, val *byte, p bool) {
} }
} }
/* Delete a key from a map. */
func mapdelete(h *Hmap, key *byte) {
__go_map_delete(h, key);
}
/* Initialize a range over a map. */ /* Initialize a range over a map. */
func mapiterinit(h *Hmap, it *hiter) { func mapiterinit(h *Hmap, it *hiter) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment