From d73b8f8417ebf6f0bbf64f237fa9db11cfc719f4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 16 May 2017 00:02:03 +0000 Subject: [PATCH] compiler: report correct errors for sink methods If somebody writes func (s []int) _() {} we should report an error. Before this patch we were silently accepting this code, because we didn't report any errors about the receiver if the method was a sink. This patch is unfortunately slightly complex to handle the case of func (x int) _() {} which we can only detect after define_global_names. This fixes blank1.go in the current gc testsuite. Reviewed-on: https://go-review.googlesource.com/43456 From-SVN: r248081 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/gogo.cc | 40 ++++++++++++++++++++++++++++++++++++-- gcc/go/gofrontend/gogo.h | 5 +++++ gcc/go/gofrontend/types.cc | 11 +++++++++++ gcc/go/gofrontend/types.h | 4 ++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 02219862b35..fec0e7978d5 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -2f21020c9f61b31bd04d5b814aaa27bf976bf07a +d3997526dc0710e6b9b727a41184ce1770805794 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index b076b87b491..daf2ba4cb0b 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1786,8 +1786,41 @@ Gogo::start_function(const std::string& name, Function_type* type, char buf[30]; snprintf(buf, sizeof buf, ".$sink%d", sink_count); ++sink_count; - ret = this->package_->bindings()->add_function(buf, NULL, function); + ret = Named_object::make_function(buf, NULL, function); ret->func_value()->set_is_sink(); + + if (!type->is_method()) + ret = this->package_->bindings()->add_named_object(ret); + else if (add_method_to_type) + { + // We should report errors even for sink methods. + Type* rtype = type->receiver()->type(); + // Avoid points_to and deref to avoid getting an error if + // the type is not yet defined. + if (rtype->classification() == Type::TYPE_POINTER) + rtype = rtype->points_to(); + while (rtype->named_type() != NULL + && rtype->named_type()->is_alias()) + rtype = rtype->named_type()->real_type()->forwarded(); + if (rtype->is_error_type()) + ; + else if (rtype->named_type() != NULL) + { + if (rtype->named_type()->named_object()->package() != NULL) + go_error_at(type->receiver()->location(), + "may not define methods on non-local type"); + } + else if (rtype->forward_declaration_type() != NULL) + { + // Go ahead and add the method in case we need to report + // an error when we see the definition. + rtype->forward_declaration_type()->add_existing_method(ret); + } + else + go_error_at(type->receiver()->location(), + ("invalid receiver type " + "(receiver must be a named type)")); + } } else if (!type->is_method()) { @@ -6985,7 +7018,10 @@ Type_declaration::define_methods(Named_type* nt) for (std::vector::const_iterator p = this->methods_.begin(); p != this->methods_.end(); ++p) - nt->add_existing_method(*p); + { + if (!(*p)->func_value()->is_sink()) + nt->add_existing_method(*p); + } } // We are using the type. Return true if we should issue a warning. diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 994f2339941..787a3e3658f 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -2114,6 +2114,11 @@ class Type_declaration add_method_declaration(const std::string& name, Package*, Function_type* type, Location location); + // Add an already created object as a method. + void + add_existing_method(Named_object* no) + { this->methods_.push_back(no); } + // Return whether any methods were defined. bool has_methods() const; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index f2056aa6208..8d542de1b3c 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -12210,6 +12210,17 @@ Forward_declaration_type::add_method_declaration(const std::string& name, return td->add_method_declaration(name, package, type, location); } +// Add an already created object as a method. + +void +Forward_declaration_type::add_existing_method(Named_object* nom) +{ + Named_object* no = this->named_object(); + if (no->is_unknown()) + no->declare_as_type(); + no->type_declaration_value()->add_existing_method(nom); +} + // Traversal. int diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index e0fcf0cc86a..bae7fd3a541 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -3379,6 +3379,10 @@ class Forward_declaration_type : public Type add_method_declaration(const std::string& name, Package*, Function_type*, Location); + // Add an already created object as a method to this type. + void + add_existing_method(Named_object*); + protected: int do_traverse(Traverse* traverse); -- 2.30.2