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
This commit is contained in:
Ian Lance Taylor 2017-05-16 00:02:03 +00:00
parent a5768d38a6
commit d73b8f8417
5 changed files with 59 additions and 3 deletions

View File

@ -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.

View File

@ -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<Named_object*>::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.

View File

@ -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;

View File

@ -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

View File

@ -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);