aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-05-16 00:02:03 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-05-16 00:02:03 +0000
commitd73b8f8417ebf6f0bbf64f237fa9db11cfc719f4 (patch)
treeb982f2031b658201fc0d5f049e5eaee1a3e90755 /gcc
parenta5768d38a66fc4136208bc8442a4118df2bd588f (diff)
downloadgcc-d73b8f8417ebf6f0bbf64f237fa9db11cfc719f4.zip
gcc-d73b8f8417ebf6f0bbf64f237fa9db11cfc719f4.tar.gz
gcc-d73b8f8417ebf6f0bbf64f237fa9db11cfc719f4.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/gogo.cc40
-rw-r--r--gcc/go/gofrontend/gogo.h5
-rw-r--r--gcc/go/gofrontend/types.cc11
-rw-r--r--gcc/go/gofrontend/types.h4
5 files changed, 59 insertions, 3 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 0221986..fec0e79 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 b076b87..daf2ba4 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<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.
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 994f233..787a3e3 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 f2056aa..8d542de 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 e0fcf0c..bae7fd3 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);