diff --git a/compiler/interface.go b/compiler/interface.go index 3908a69d1..5c7460a31 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -599,8 +599,21 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo case *types.Named: tn := t.Obj() if tn.Pkg() == nil || tn.Parent() == tn.Pkg().Scope() { - // Package-scope or builtin: the printed name is unique. - return "named:" + t.String(), false + name := tn.Name() + if tn.Pkg() != nil { + name = tn.Pkg().Path() + "." + name + } + isLocal := false + if targs := t.TypeArgs(); targs.Len() != 0 { + parts := make([]string, targs.Len()) + for i := range parts { + var local bool + parts[i], local = c.getTypeCodeName(targs.At(i)) + isLocal = isLocal || local + } + name += "[" + strings.Join(parts, ",") + "]" + } + return "named:" + name, isLocal } if tn.Parent() != nil { // Ordinary function-local type. Use the un-//line-adjusted @@ -707,8 +720,8 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo // Synthetic TypeNames are produced by generic instantiation: two // instantiations of the same generic function (e.g. F[int] and // F[string]) produce TypeNames with the same printed name and the -// same source position, so each is named with the enclosing -// instance's RelString as prefix. RelString encodes the type +// same source position, so each is named with the enclosing instance's +// canonical function name as prefix. The function name encodes the type // arguments, matching Go's runtime behavior, where F[int].Inner and // F[string].Inner are distinct types even when Inner does not mention // the type parameter. @@ -717,9 +730,9 @@ func (c *compilerContext) getTypeCodeName(t types.Type) (name string, isLocal bo // of F[int] is compiled in every package that calls F[int]); its // reflect/types.type:* global has LinkOnceODRLinkage and is merged by // name at link time. The chosen name therefore depends only on -// intrinsic SSA properties (RelString and the raw token.Pos used as a -// sort key), so any package compiling the same instance produces the -// same identifier. +// intrinsic SSA properties (the canonical function name and raw token.Pos), +// so any package compiling the same instance produces the same +// identifier. // // Ordinary function-local TypeNames (TypeName.Parent() != nil) are // not handled here: they are nameable only inside their declaring @@ -807,9 +820,8 @@ func (c *compilerContext) scanLocalTypes(ssaPkg *ssa.Package) { // registerSyntheticLocalTypes walks every type reachable from fn's // body and records each synthetic *types.Named (TypeName.Parent() == -// nil) in c.localTypeNames. Each is named with fn.RelString as the -// owning function plus a per-function counter assigned in source -// order. +// nil) in c.localTypeNames. Each is named with the canonical function +// name plus a per-function counter assigned in source order. // // First-writer-wins: a *types.Named already present in // c.localTypeNames is left alone, so a synthetic type reachable from @@ -920,7 +932,7 @@ func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) { sort.Slice(found, func(i, j int) bool { return found[i].Obj().Pos() < found[j].Obj().Pos() }) - enclosing := fn.RelString(nil) + enclosing := c.canonicalFunctionName(fn) for i, named := range found { c.localTypeNames.Set(named, fmt.Sprintf("%s.%s$%d", enclosing, named.Obj().Name(), i)) } @@ -929,7 +941,8 @@ func (c *compilerContext) registerSyntheticLocalTypes(fn *ssa.Function) { // getTypeMethodSet returns a reference (GEP) to a global method set. This // method set should be unreferenced after the interface lowering pass. func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value { - globalName := typ.String() + "$methodset" + typeName, _ := c.getTypeCodeName(typ) + globalName := typeName + "$methodset" global := c.mod.NamedGlobal(globalName) if global.IsNil() { ms := c.program.MethodSets.MethodSet(typ) diff --git a/compiler/symbol.go b/compiler/symbol.go index 2114aa611..16f5b85d8 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -320,13 +320,7 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo { } info := functionInfo{ // Pick the default linkName. - linkName: f.RelString(nil), - } - - // RelString is not unique for local type arguments, so add a suffix - // when needed. - if suffix := c.localTypeArgsSuffix(f); suffix != "" { - info.linkName += suffix + linkName: c.canonicalFunctionName(f), } // Check for a few runtime functions that are treated specially. @@ -353,24 +347,16 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo { return info } -func (c *compilerContext) localTypeArgsSuffix(f *ssa.Function) string { +func (c *compilerContext) canonicalFunctionName(f *ssa.Function) string { typeArgs := f.TypeArgs() if len(typeArgs) == 0 { - return "" + return f.RelString(nil) } - var hasLocal bool parts := make([]string, len(typeArgs)) for i, ta := range typeArgs { - name, isLocal := c.getTypeCodeName(ta) - if isLocal { - hasLocal = true - } - parts[i] = name + parts[i], _ = c.getTypeCodeName(ta) } - if !hasLocal { - return "" - } - return "$localtype:" + strings.Join(parts, ",") + return f.Origin().RelString(nil) + "[" + strings.Join(parts, ",") + "]" } // parsePragmas is used by getFunctionInfo to parse function pragmas such as diff --git a/compiler/testdata/generics.ll b/compiler/testdata/generics.ll index abe80e2ed..4896f9348 100644 --- a/compiler/testdata/generics.ll +++ b/compiler/testdata/generics.ll @@ -17,12 +17,12 @@ entry: ; Function Attrs: nounwind define hidden i32 @main.aliasSize32(ptr %context) unnamed_addr #1 { entry: - %0 = call i32 @"main.aliasSize[main.F]"(ptr undef) + %0 = call i32 @"main.aliasSize[basic:float32]"(ptr undef) ret i32 %0 } ; Function Attrs: nounwind -define linkonce_odr hidden i32 @"main.aliasSize[main.F]"(ptr %context) unnamed_addr #1 { +define linkonce_odr hidden i32 @"main.aliasSize[basic:float32]"(ptr %context) unnamed_addr #1 { entry: ret i32 4 } @@ -30,15 +30,21 @@ entry: ; Function Attrs: nounwind define hidden i32 @main.aliasSize64(ptr %context) unnamed_addr #1 { entry: - %0 = call i32 @"main.aliasSize[main.F]"(ptr undef) + %0 = call i32 @"main.aliasSize[basic:float64]"(ptr undef) ret i32 %0 } +; Function Attrs: nounwind +define linkonce_odr hidden i32 @"main.aliasSize[basic:float64]"(ptr %context) unnamed_addr #1 { +entry: + ret i32 8 +} + ; Function Attrs: nounwind define hidden void @main.main(ptr %context) unnamed_addr #1 { entry: - %0 = call %"main.Point[float32]" @"main.Add[float32]"(float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, ptr undef) - %1 = call %"main.Point[int]" @"main.Add[int]"(i32 0, i32 0, i32 0, i32 0, ptr undef) + %0 = call %"main.Point[float32]" @"main.Add[basic:float32]"(float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, ptr undef) + %1 = call %"main.Point[int]" @"main.Add[basic:int]"(i32 0, i32 0, i32 0, i32 0, ptr undef) %2 = call i32 @main.aliasSize32(ptr undef) call void @main.checkSize(i32 %2, ptr undef) #4 %3 = call i32 @main.aliasSize64(ptr undef) @@ -47,7 +53,7 @@ entry: } ; Function Attrs: nounwind -define linkonce_odr hidden %"main.Point[float32]" @"main.Add[float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, ptr %context) unnamed_addr #1 { +define linkonce_odr hidden %"main.Point[float32]" @"main.Add[basic:float32]"(float %a.X, float %a.Y, float %b.X, float %b.Y, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #4 @@ -110,7 +116,7 @@ declare void @main.checkSize(i32, ptr) #0 declare void @runtime.nilPanic(ptr) #0 ; Function Attrs: nounwind -define linkonce_odr hidden %"main.Point[int]" @"main.Add[int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, ptr %context) unnamed_addr #1 { +define linkonce_odr hidden %"main.Point[int]" @"main.Add[basic:int]"(i32 %a.X, i32 %a.Y, i32 %b.X, i32 %b.Y, ptr %context) unnamed_addr #1 { entry: %stackalloc = alloca i8, align 1 %a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #4 @@ -170,7 +176,7 @@ declare void @main.checkBool(i1, ptr) #0 ; Function Attrs: nounwind define hidden void @main.aliasMethod32(ptr %x.typecode, ptr %x.value, ptr %context) unnamed_addr #1 { entry: - %0 = call i1 @"interface:{Get:func:{}{named:main.aliasMethodResult[main.F]}}.$typeassert"(ptr %x.typecode) #4 + %0 = call i1 @"interface:{Get:func:{}{named:main.aliasMethodResult[basic:float32]}}.$typeassert"(ptr %x.typecode) #4 br i1 %0, label %typeassert.ok, label %typeassert.next typeassert.next: ; preds = %typeassert.ok, %entry @@ -181,7 +187,7 @@ typeassert.ok: ; preds = %entry br label %typeassert.next } -declare i1 @"interface:{Get:func:{}{named:main.aliasMethodResult[main.F]}}.$typeassert"(ptr) #3 +declare i1 @"interface:{Get:func:{}{named:main.aliasMethodResult[basic:float32]}}.$typeassert"(ptr) #3 attributes #0 = { "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } attributes #1 = { nounwind "target-features"="+bulk-memory,+bulk-memory-opt,+call-indirect-overlong,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types" } diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll index 5348018b8..d8b446b89 100644 --- a/compiler/testdata/pragma.ll +++ b/compiler/testdata/pragma.ll @@ -50,12 +50,12 @@ entry: ; Function Attrs: nounwind define hidden void @main.useGeneric(ptr %context) unnamed_addr #1 { entry: - call void @"main.noinlineGenericFunc[int8]"(ptr undef) + call void @"main.noinlineGenericFunc[basic:int8]"(ptr undef) ret void } ; Function Attrs: noinline nounwind -define linkonce_odr hidden void @"main.noinlineGenericFunc[int8]"(ptr %context) unnamed_addr #4 { +define linkonce_odr hidden void @"main.noinlineGenericFunc[basic:int8]"(ptr %context) unnamed_addr #4 { entry: ret void } diff --git a/testdata/localtypes.txt b/testdata/localtypes.txt index 85a851741..b0910553d 100644 --- a/testdata/localtypes.txt +++ b/testdata/localtypes.txt @@ -48,13 +48,13 @@ issue4931PairB labels: 0 issue4931MethodA labels: 0 issue4931MethodB labels: 0 ok: aliasSize[float32]==32 -BUG: aliasSize[float64]==64 +ok: aliasSize[float64]==64 ok: aliasLocal[float32] accepts own ok: aliasLocal[float64] accepts own -BUG: aliasLocal[float32] rejects [float64] -BUG: aliasLocal[float64] rejects [float32] +ok: aliasLocal[float32] rejects [float64] +ok: aliasLocal[float64] rejects [float32] ok: aliasBox[float32] implements Get() float32 -BUG: aliasBox[float64] implements Get() float64 +ok: aliasBox[float64] implements Get() float64 ok: aliasMethod[float32] accepts own ok: aliasMethod[float64] accepts own BUG: aliasMethod[float32] rejects [float64]