Use the object's package to mangle method names, rather than the receiver's package

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
GitOrigin-RevId: 545e7276a870c60d4d289b72b38e1529dae2acd7
diff --git a/irgen/typemap.go b/irgen/typemap.go
index 29cca05..91f4ca4 100644
--- a/irgen/typemap.go
+++ b/irgen/typemap.go
@@ -659,21 +659,25 @@
 		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/test/irgen/Inputs/mangling-synthetic-p.go b/test/irgen/Inputs/mangling-synthetic-p.go
new file mode 100644
index 0000000..c59588a
--- /dev/null
+++ b/test/irgen/Inputs/mangling-synthetic-p.go
@@ -0,0 +1,4 @@
+package p
+
+type U struct{}
+func (U) f()
diff --git a/test/irgen/mangling.go b/test/irgen/mangling-dot.go
similarity index 100%
rename from test/irgen/mangling.go
rename to test/irgen/mangling-dot.go
diff --git a/test/irgen/mangling-synthetic.go b/test/irgen/mangling-synthetic.go
new file mode 100644
index 0000000..b88e037
--- /dev/null
+++ b/test/irgen/mangling-synthetic.go
@@ -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()