]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
compiler: avoid aliases in receiver types
authorIan Lance Taylor <iant@golang.org>
Mon, 19 Jul 2021 23:47:05 +0000 (16:47 -0700)
committerIan Lance Taylor <iant@golang.org>
Mon, 19 Jul 2021 23:47:05 +0000 (16:47 -0700)
If a package declares a method on an alias type, the alias would be
used in the export data.  This would then trigger a compiler
assertion on import: we should not be adding methods to aliases.

Fix the problem by ensuring that receiver types do not use alias types.
This seems preferable to consistently avoiding aliases in export data,
as aliases can cross packages.  And it's painful to try to patch this
while writing the export data, as at that point all the types are known.

Test case is https://golang.org/cl/335172.

Fixes golang/go#47131

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/335729

gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/types.cc

index 93b54fd8c118e722e897f5e94160592e14079f44..335982d2e804f106389ee3b8e4b23be4c1360b56 100644 (file)
@@ -5765,6 +5765,26 @@ Function::check_labels() const
     }
 }
 
+// Set the receiver type.  This is used to remove aliases.
+
+void
+Function::set_receiver_type(Type* rtype)
+{
+  Function_type* oft = this->type_;
+  Typed_identifier* rec = new Typed_identifier(oft->receiver()->name(),
+                                              rtype,
+                                              oft->receiver()->location());
+  Typed_identifier_list* parameters = NULL;
+  if (oft->parameters() != NULL)
+    parameters = oft->parameters()->copy();
+  Typed_identifier_list* results = NULL;
+  if (oft->results() != NULL)
+    results = oft->results()->copy();
+  Function_type* nft = Type::make_function_type(rec, parameters, results,
+                                               oft->location());
+  this->type_ = nft;
+}
+
 // Swap one function with another.  This is used when building the
 // thunk we use to call a function which calls recover.  It may not
 // work for any other case.
@@ -7287,6 +7307,26 @@ Function_declaration::set_nointerface()
   this->pragmas_ |= GOPRAGMA_NOINTERFACE;
 }
 
+// Set the receiver type.  This is used to remove aliases.
+
+void
+Function_declaration::set_receiver_type(Type* rtype)
+{
+  Function_type* oft = this->fntype_;
+  Typed_identifier* rec = new Typed_identifier(oft->receiver()->name(),
+                                              rtype,
+                                              oft->receiver()->location());
+  Typed_identifier_list* parameters = NULL;
+  if (oft->parameters() != NULL)
+    parameters = oft->parameters()->copy();
+  Typed_identifier_list* results = NULL;
+  if (oft->results() != NULL)
+    results = oft->results()->copy();
+  Function_type* nft = Type::make_function_type(rec, parameters, results,
+                                               oft->location());
+  this->fntype_ = nft;
+}
+
 // Import an inlinable function.  This is used for an inlinable
 // function whose body is recorded in the export data.  Parse the
 // export data into a Block and create a regular function using that
index f4155a29edb3bcf14c95634243d26958938f4f76..c49bc92b3e073a95e4f6eac7b137dfac42a43b96 100644 (file)
@@ -1724,6 +1724,10 @@ class Function
   set_is_referenced_by_inline()
   { this->is_referenced_by_inline_ = true; }
 
+  // Set the receiver type.  This is used to remove aliases.
+  void
+  set_receiver_type(Type* rtype);
+
   // Swap with another function.  Used only for the thunk which calls
   // recover.
   void
@@ -1990,6 +1994,10 @@ class Function_declaration
   set_is_on_inlinable_list()
   { this->is_on_inlinable_list_ = true; }
 
+  // Set the receiver type.  This is used to remove aliases.
+  void
+  set_receiver_type(Type* rtype);
+
   // Import the function body, creating a function.
   void
   import_function_body(Gogo*, Named_object*);
index 7d4c47f1c42621ea33606b7b509f55fd07788c2e..ecf382302f70d3296b5dc3c829799f71e5aef851 100644 (file)
@@ -10409,6 +10409,57 @@ Named_type::finalize_methods(Gogo* gogo)
       return;
     }
 
+  // Remove any aliases in the local method receiver types.
+  Bindings* methods = this->local_methods_;
+  if (methods != NULL)
+    {
+      for (Bindings::const_declarations_iterator p =
+            methods->begin_declarations();
+          p != methods->end_declarations();
+          ++p)
+       {
+         Named_object* no = p->second;
+         Function_type* fntype;
+         if (no->is_function())
+           fntype = no->func_value()->type();
+         else if (no->is_function_declaration())
+           fntype = no->func_declaration_value()->type();
+         else
+           {
+             go_assert(saw_errors());
+             continue;
+           }
+
+         Type* rtype = fntype->receiver()->type();
+         bool is_pointer = false;
+         Type* pt = rtype->points_to();
+         if (pt != NULL)
+           {
+             rtype = pt;
+             is_pointer = true;
+           }
+         if (rtype->named_type() != this)
+           {
+             if (rtype->unalias() != this)
+               {
+                 go_assert(saw_errors());
+                 continue;
+               }
+
+             rtype = this;
+             if (is_pointer)
+               rtype = Type::make_pointer_type(rtype);
+
+             if (no->is_function())
+               no->func_value()->set_receiver_type(rtype);
+             else if (no->is_function_declaration())
+               no->func_declaration_value()->set_receiver_type(rtype);
+             else
+               go_unreachable();
+           }
+       }
+    }
+
   Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
 }