Use the object's package to mangle method names, rather than the receiver's package
authorPeter Collingbourne <peter@pcc.me.uk>
Tue, 16 Dec 2014 20:04:55 +0000 (20:04 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Tue, 16 Dec 2014 20:04:55 +0000 (20:04 +0000)
If we use the receiver's package, we can end up with identical manglings
for different functions. Consider:

package p
type U struct{}
func (U) f()

package q
import "p"
type T struct { p.U }
func (T) f()

The method set of *T has two synthetic methods named (*T).f(); one forwards to
(T).f(), and the other to (U).f(). Previously, we were distinguishing them
by the receiver's package, and in this case because both methods have the
same receiver, they received the same name.

The methods are correctly distinguished by the package owning the identifier
"f", which is available via f.Object().Pkg().

Differential Revision: http://reviews.llvm.org/D6673

llvm-svn: 224357

llgo/irgen/typemap.go
llgo/test/irgen/Inputs/mangling-synthetic-p.go [new file with mode: 0644]
llgo/test/irgen/mangling-dot.go [moved from llgo/test/irgen/mangling.go with 100% similarity]
llgo/test/irgen/mangling-synthetic.go [new file with mode: 0644]

index 29cca05..91f4ca4 100644 (file)
@@ -659,21 +659,25 @@ func (ctx *manglerContext) mangleFunctionName(f *ssa.Function) string {
                return b.String()
        }
 
-       pkg := f.Pkg
-       var pkgobj *types.Package
-       if pkg != nil {
-               pkgobj = pkg.Object
-       } else if f.Signature.Recv() != nil {
-               pkgobj = f.Signature.Recv().Pkg()
-       } else {
+       // Synthetic bound and thunk functions are special cases; they can only be
+       // distinguished using private data that is only exposed via String().
+       if strings.HasSuffix(f.Name(), "$bound") || strings.HasSuffix(f.Name(), "$thunk") {
                b.WriteString(f.String())
                return b.String()
        }
 
+       var pkg *types.Package
+       if f.Pkg != nil {
+               pkg = f.Pkg.Object
+       } else if !f.Object().Exported() {
+               pkg = f.Object().Pkg()
+       }
+
        if pkg != nil {
-               ctx.manglePackagePath(pkgobj.Path(), &b)
+               ctx.manglePackagePath(pkg.Path(), &b)
                b.WriteRune('.')
        }
+
        if f.Signature.Recv() == nil && f.Name() == "init" {
                b.WriteString(".import")
        } else {
diff --git a/llgo/test/irgen/Inputs/mangling-synthetic-p.go b/llgo/test/irgen/Inputs/mangling-synthetic-p.go
new file mode 100644 (file)
index 0000000..c59588a
--- /dev/null
@@ -0,0 +1,4 @@
+package p
+
+type U struct{}
+func (U) f()
diff --git a/llgo/test/irgen/mangling-synthetic.go b/llgo/test/irgen/mangling-synthetic.go
new file mode 100644 (file)
index 0000000..b88e037
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: llgo -fgo-pkgpath=p -c -o %T/p.o %S/Inputs/mangling-synthetic-p.go
+// RUN: llgo -fgo-pkgpath=q -I %T -S -emit-llvm -o - %s | FileCheck %s
+
+package q
+
+import "p"
+
+// CHECK-DAG: define linkonce_odr void @p.f.N3_q.T(i8*)
+// CHECK-DAG: define linkonce_odr void @p.f.pN3_q.T(i8*)
+type T struct { p.U }
+
+// CHECK-DAG: declare void @q.f.N3_q.T(i8*)
+// CHECK-DAG: define linkonce_odr void @q.f.pN3_q.T(i8*)
+func (T) f()