aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-10-25 17:21:07 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-10-25 17:21:07 +0000
commitf29ce5f5f1f0deec646389d5a44bcedb6c543014 (patch)
tree39eed82e18e8d15063ea472730c729cf5fa49154
parent09367c0d60f551d7d05b6212b649a71636b623ce (diff)
downloadgcc-f29ce5f5f1f0deec646389d5a44bcedb6c543014.zip
gcc-f29ce5f5f1f0deec646389d5a44bcedb6c543014.tar.gz
gcc-f29ce5f5f1f0deec646389d5a44bcedb6c543014.tar.bz2
Implement predeclared delete function.
From-SVN: r180438
-rw-r--r--gcc/go/gofrontend/expressions.cc145
-rw-r--r--gcc/go/gofrontend/gogo.cc5
-rw-r--r--gcc/go/gofrontend/runtime.def3
-rw-r--r--libgo/runtime/go-map-delete.c2
-rw-r--r--libgo/runtime/map.goc6
5 files changed, 112 insertions, 49 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index cdf2bad..e308b9a 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -7048,6 +7048,7 @@ class Builtin_call_expression : public Call_expression
BUILTIN_CLOSE,
BUILTIN_COMPLEX,
BUILTIN_COPY,
+ BUILTIN_DELETE,
BUILTIN_IMAG,
BUILTIN_LEN,
BUILTIN_MAKE,
@@ -7113,6 +7114,8 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
this->code_ = BUILTIN_COMPLEX;
else if (name == "copy")
this->code_ = BUILTIN_COPY;
+ else if (name == "delete")
+ this->code_ = BUILTIN_DELETE;
else if (name == "imag")
this->code_ = BUILTIN_IMAG;
else if (name == "len")
@@ -7206,34 +7209,15 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
if (this->classification() == EXPRESSION_ERROR)
return this;
+ source_location loc = this->location();
+
if (this->is_varargs() && this->code_ != BUILTIN_APPEND)
{
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)
- {
- 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())
+ if (this->is_constant())
{
// We can only lower len and cap if there are no function calls
// in the arguments. Otherwise we have to make the call.
@@ -7254,8 +7238,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
Type* type;
if (this->integer_constant_value(true, ival, &type))
{
- Expression* ret = Expression::make_integer(&ival, type,
- this->location());
+ Expression* ret = Expression::make_integer(&ival, type, loc);
mpz_clear(ival);
return ret;
}
@@ -7265,8 +7248,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
mpfr_init(rval);
if (this->float_constant_value(rval, &type))
{
- Expression* ret = Expression::make_float(&rval, type,
- this->location());
+ Expression* ret = Expression::make_float(&rval, type, loc);
mpfr_clear(rval);
return ret;
}
@@ -7275,8 +7257,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
mpfr_init(imag);
if (this->complex_constant_value(rval, imag, &type))
{
- Expression* ret = Expression::make_complex(&rval, &imag, type,
- this->location());
+ Expression* ret = Expression::make_complex(&rval, &imag, type, loc);
mpfr_clear(rval);
mpfr_clear(imag);
return ret;
@@ -7284,34 +7265,100 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
mpfr_clear(rval);
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)
function->func_value()->set_calls_recover();
else
{
// Calling recover outside of a function always returns the
// nil empty interface.
- Type* eface = Type::make_interface_type(NULL, this->location());
- return Expression::make_cast(eface,
- Expression::make_nil(this->location()),
- this->location());
+ Type* eface = Type::make_interface_type(NULL, loc);
+ return Expression::make_cast(eface, Expression::make_nil(loc), loc);
}
- }
- else if (this->code_ == BUILTIN_APPEND)
- {
- // Lower the varargs.
- const Expression_list* args = this->args();
- if (args == NULL || args->empty())
- return this;
- 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();
+ break;
+
+ case BUILTIN_APPEND:
+ {
+ // Lower the varargs.
+ const Expression_list* args = this->args();
+ if (args == NULL || args->empty())
return this;
- }
- this->lower_varargs(gogo, function, inserter, slice_type, 2);
+ 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;
+ }
+ 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;
@@ -7845,6 +7892,7 @@ Builtin_call_expression::do_discarding_value()
case BUILTIN_CLOSE:
case BUILTIN_COPY:
+ case BUILTIN_DELETE:
case BUILTIN_PANIC:
case BUILTIN_PRINT:
case BUILTIN_PRINTLN:
@@ -7882,6 +7930,7 @@ Builtin_call_expression::do_type()
return Type::lookup_integer_type("int");
case BUILTIN_CLOSE:
+ case BUILTIN_DELETE:
case BUILTIN_PANIC:
case BUILTIN_PRINT:
case BUILTIN_PRINTLN:
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 9998ab8..18436ab 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -201,6 +201,11 @@ Gogo::Gogo(Backend* backend, int int_type_size, int pointer_size)
imag_type->set_is_varargs();
imag_type->set_is_builtin();
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.
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index a72942d..d742e5b 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -94,6 +94,9 @@ DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2",
DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2",
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.
DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0())
diff --git a/libgo/runtime/go-map-delete.c b/libgo/runtime/go-map-delete.c
index 9b19ff1..a8f928f 100644
--- a/libgo/runtime/go-map-delete.c
+++ b/libgo/runtime/go-map-delete.c
@@ -27,7 +27,7 @@ __go_map_delete (struct __go_map *map, const void *key)
void **pentry;
if (map == NULL)
- __go_panic_msg ("assignment to entry in nil map");
+ __go_panic_msg ("deletion of entry in nil map");
descriptor = map->__descriptor;
diff --git a/libgo/runtime/map.goc b/libgo/runtime/map.goc
index e19bc96..da67d49 100644
--- a/libgo/runtime/map.goc
+++ b/libgo/runtime/map.goc
@@ -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. */
func mapiterinit(h *Hmap, it *hiter) {