mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
compiler: disambiguate generic instances with function-local type aliases
x/tools go/ssa names instantiations using the type argument's String(). Function-local aliases like `type F = float64` therefore collide when two callers use distinct aliases named F (Go 1.27's internal/strconv.ftoa32 and ftoa64 do exactly this). Extend localTypeArgsSuffix to detect local aliases and include their declaration position, so the float32 and float64 instantiations get distinct LLVM symbols. Fixes wrong float formatting in strconv/math on Go 1.27, and adds a regression test to testdata/localtypes.go. Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -365,6 +366,22 @@ func (c *compilerContext) localTypeArgsSuffix(f *ssa.Function) string {
|
||||
if isLocal {
|
||||
hasLocal = true
|
||||
}
|
||||
// A function-local type alias (e.g. `type F = float64` inside a
|
||||
// function body) is invisible to getTypeCodeName because it calls
|
||||
// types.Unalias first. Two callers that use distinct aliases with
|
||||
// the same name (e.g. Go 1.27's internal/strconv.ftoa32 and ftoa64
|
||||
// both declare a local `type F = ...`) then produce identical
|
||||
// RelStrings for their shortFloat[F] instantiations and collide on
|
||||
// mod.NamedFunction. Treat these aliases as local so the suffix
|
||||
// disambiguates them.
|
||||
if alias, ok := ta.(*types.Alias); ok {
|
||||
if obj := alias.Obj(); obj.Pkg() != nil && obj.Parent() != obj.Pkg().Scope() {
|
||||
hasLocal = true
|
||||
pos := c.program.Fset.PositionFor(obj.Pos(), false)
|
||||
parts[i] = fmt.Sprintf("%s$alias:%s:%d:%d", name, filepath.Base(pos.Filename), pos.Line, pos.Column)
|
||||
continue
|
||||
}
|
||||
}
|
||||
parts[i] = name
|
||||
}
|
||||
if !hasLocal {
|
||||
|
||||
Vendored
+31
-1
@@ -1,6 +1,9 @@
|
||||
package main
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type checker = func(any) bool
|
||||
|
||||
@@ -216,6 +219,28 @@ func issue5180CopyIgnoreNilMembers() (ok bool) {
|
||||
return ok
|
||||
}
|
||||
|
||||
// aliasSize is the pattern used by Go 1.27's internal/strconv.ftoa32 and
|
||||
// ftoa64 (and by shortFloat in internal/strconv/uscale.go): a generic
|
||||
// function parameterized on F={float32|float64} that switches on
|
||||
// unsafe.Sizeof(F(0)). Callers pass F via a function-local `type F = ...`
|
||||
// alias. If the two instantiations share an SSA function name (because
|
||||
// x/tools' go/ssa targstr uses the alias's declared name), TinyGo's
|
||||
// getFunction reuses the first LLVM function for the second call and the
|
||||
// second instantiation returns the first's result.
|
||||
func aliasSize[F float32 | float64]() int {
|
||||
return 8 * int(unsafe.Sizeof(F(0)))
|
||||
}
|
||||
|
||||
func aliasSizeCaller32() int {
|
||||
type F = float32
|
||||
return aliasSize[F]()
|
||||
}
|
||||
|
||||
func aliasSizeCaller64() int {
|
||||
type F = float64
|
||||
return aliasSize[F]()
|
||||
}
|
||||
|
||||
func main() {
|
||||
expect("issue5180 TestCopy1", issue5180Copy1())
|
||||
expect("issue5180 TestCopyIgnoreNilMembers", issue5180CopyIgnoreNilMembers())
|
||||
@@ -300,4 +325,9 @@ func main() {
|
||||
println("issue4931PairB labels:", issue4931PairB())
|
||||
println("issue4931MethodA labels:", issue4931MethodA())
|
||||
println("issue4931MethodB labels:", issue4931MethodB())
|
||||
|
||||
// Generic instances distinguished only by function-local type aliases
|
||||
// must not share bodies either (the Go 1.27 strconv shortFloat pattern).
|
||||
expect("aliasSize[float32]==32", aliasSizeCaller32() == 32)
|
||||
expect("aliasSize[float64]==64", aliasSizeCaller64() == 64)
|
||||
}
|
||||
|
||||
Vendored
+2
@@ -47,3 +47,5 @@ issue4931PairA labels: 0
|
||||
issue4931PairB labels: 0
|
||||
issue4931MethodA labels: 0
|
||||
issue4931MethodB labels: 0
|
||||
ok: aliasSize[float32]==32
|
||||
ok: aliasSize[float64]==64
|
||||
|
||||
Reference in New Issue
Block a user