diff --git a/cl/compile.go b/cl/compile.go index 5b6d7c9fbe..861f62db8d 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -1117,6 +1117,10 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { return } } + if isBlankFieldStore(va) { + _ = p.compileValue(b, v.Val) + return + } if p.rewrites != nil { if g, ok := va.(*ssa.Global); ok { if _, ok := p.rewriteInitStore(v, g); ok { @@ -1251,6 +1255,15 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr { panic(fmt.Sprintf("compileValue: unknown value - %T\n", v)) } +func isBlankFieldStore(addr ssa.Value) bool { + field, ok := addr.(*ssa.FieldAddr) + if !ok { + return false + } + _, st, ok := fieldAddrStruct(field) + return ok && st.Field(field.Field).Name() == "_" +} + const rangeOverFuncYieldSynthetic = "range-over-func yield" func (p *context) rangeFuncCallNeedsDeferDrain(call *ssa.CallCommon) bool { diff --git a/runtime/internal/lib/internal/reflectlite/type.go b/runtime/internal/lib/internal/reflectlite/type.go index 0c58860e37..2530a2a008 100644 --- a/runtime/internal/lib/internal/reflectlite/type.go +++ b/runtime/internal/lib/internal/reflectlite/type.go @@ -161,6 +161,9 @@ func (t rtype) PkgPath() string { if t.TFlag&abi.TFlagNamed == 0 { return "" } + if t.Kind() == abi.UnsafePointer { + return "unsafe" + } ut := t.uncommon() if ut == nil { return "" diff --git a/runtime/internal/lib/reflect/makefunc.go b/runtime/internal/lib/reflect/makefunc.go index 66afbaac4f..7488ca1b2e 100644 --- a/runtime/internal/lib/reflect/makefunc.go +++ b/runtime/internal/lib/reflect/makefunc.go @@ -57,7 +57,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { for i := 0; i < fd.nin; i++ { ins[i] = ffiToValue(ffi.Index(args, uintptr(i+1)), fd.ftyp.In[i]) } - fd.fn(ins) + validateMakeFuncResults(fd.fn(ins), fd.ftyp) }, unsafe.Pointer(&funcData{ftyp: ftyp, fn: fn, nin: len(ftyp.In)})) case 1: err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { @@ -66,12 +66,8 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { for i := 0; i < fd.nin; i++ { ins[i] = ffiToValue(ffi.Index(args, uintptr(i+1)), fd.ftyp.In[i]) } - out := fd.fn(ins) - if fd.ftyp.Out[0].IfaceIndir() { - c.Memmove(ret, out[0].ptr, fd.ftyp.Out[0].Size_) - } else { - *(*unsafe.Pointer)(ret) = unsafe.Pointer(out[0].ptr) - } + out := validateMakeFuncResults(fd.fn(ins), fd.ftyp) + storeMakeFuncResult(ret, out[0], fd.ftyp.Out[0]) }, unsafe.Pointer(&funcData{ftyp: ftyp, fn: fn, nin: len(ftyp.In)})) default: err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { @@ -80,15 +76,13 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { for i := 0; i < fd.nin; i++ { ins[i] = ffiToValue(ffi.Index(args, uintptr(i+1)), fd.ftyp.In[i]) } - outs := fd.fn(ins) + outs := validateMakeFuncResults(fd.fn(ins), fd.ftyp) var offset uintptr = 0 + alignment := uintptr(cif.RType.Alignment) for i, out := range outs { - if fd.ftyp.Out[i].IfaceIndir() { - c.Memmove(add(ret, offset, ""), out.ptr, fd.ftyp.Out[i].Size_) - } else { - *(*unsafe.Pointer)(add(ret, offset, "")) = unsafe.Pointer(out.ptr) - } - offset += fd.ftyp.Out[i].Size_ + typ := fd.ftyp.Out[i] + storeMakeFuncResult(add(ret, offset, ""), out, typ) + offset += (typ.Size_ + alignment - 1) &^ (alignment - 1) } }, unsafe.Pointer(&funcData{ftyp: ftyp, fn: fn, nin: len(ftyp.In)})) } @@ -103,6 +97,30 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { return Value{styp, unsafe.Pointer(fv), flagIndir | flag(Func)} } +func validateMakeFuncResults(out []Value, ftyp *funcType) []Value { + if len(out) != len(ftyp.Out) { + panic("reflect: wrong return count from function created by MakeFunc") + } + for i, typ := range ftyp.Out { + v := out[i] + if v.typ() == nil { + panic("reflect: function created by MakeFunc returned zero Value") + } + if v.flag&flagRO != 0 { + panic("reflect: function created by MakeFunc returned value obtained from unexported field") + } + out[i] = v.assignTo("reflect: function created by MakeFunc", typ, nil) + } + return out +} + +func storeMakeFuncResult(ret unsafe.Pointer, v Value, typ *abi.Type) { + if typ.Size_ == 0 { + return + } + c.Memmove(ret, toFFIArg(v, typ), typ.Size_) +} + func ffiToValue(ptr unsafe.Pointer, typ *abi.Type) (v Value) { kind := typ.Kind() v.typ_ = typ diff --git a/runtime/internal/lib/reflect/type.go b/runtime/internal/lib/reflect/type.go index fc57fa778f..8b240d0bfd 100644 --- a/runtime/internal/lib/reflect/type.go +++ b/runtime/internal/lib/reflect/type.go @@ -347,6 +347,9 @@ func (t *rtype) PkgPath() string { if t.t.TFlag&abi.TFlagNamed == 0 { return "" } + if t.t.Kind() == abi.UnsafePointer { + return "unsafe" + } ut := t.uncommon() if ut == nil { return "" diff --git a/runtime/internal/lib/reflect/value.go b/runtime/internal/lib/reflect/value.go index 5640d4f4b0..4e5a2fd339 100644 --- a/runtime/internal/lib/reflect/value.go +++ b/runtime/internal/lib/reflect/value.go @@ -2284,6 +2284,9 @@ func toFFIArg(v Value, typ *abi.Type) unsafe.Pointer { case abi.Chan: return unsafe.Pointer(&v.ptr) case abi.Func: + if v.flag&flagIndir != 0 { + return v.ptr + } return unsafe.Pointer(&v.ptr) case abi.Interface: i := v.Interface() diff --git a/ssa/abitype.go b/ssa/abitype.go index 37a0d7058b..fcef9bbff8 100644 --- a/ssa/abitype.go +++ b/ssa/abitype.go @@ -322,7 +322,7 @@ func (b Builder) abiExtendedFields(t types.Type, name string) (fields []llvm.Val for i := 0; i < n; i++ { if f := t.Field(i); !f.Exported() { if pkg := f.Pkg(); pkg != nil { - pkgPath = pkg.Path() + pkgPath = reflectPkgPath(pkg) break } } @@ -351,11 +351,21 @@ retry: goto retry case *types.Named: pkg := typ.Obj().Pkg() - return pkg, abi.PathOf(pkg) + return pkg, reflectPkgPath(pkg) } return nil, b.Pkg.Path() } +func reflectPkgPath(pkg *types.Package) string { + if pkg == nil { + return "" + } + if pkg.Path() == "command-line-arguments" && pkg.Name() != "" { + return pkg.Name() + } + return abi.PathOf(pkg) +} + func (b Builder) abiUncommonMethodSet(t types.Type) (mset *types.MethodSet, ok bool) { prog := b.Prog switch t := types.Unalias(t).(type) { diff --git a/test/go/reflect_type_metadata_makefunc_test.go b/test/go/reflect_type_metadata_makefunc_test.go new file mode 100644 index 0000000000..448e288ab0 --- /dev/null +++ b/test/go/reflect_type_metadata_makefunc_test.go @@ -0,0 +1,107 @@ +package gotest + +import ( + "os" + "path/filepath" + "testing" +) + +const reflectTypeMetadataMakeFuncProbe = `package main + +import ( + "fmt" + "reflect" + "strings" + "unsafe" +) + +type foo struct { + bar int +} + +var blankFieldEvalCount int + +func blankFieldValue() int { + blankFieldEvalCount++ + return 2 +} + +func boolLoop(next func() bool) bool { + for b := next(); b; b = next() { + return true + } + return false +} + +func errString(v any) string { + if s, ok := v.(interface{ Error() string }); ok { + return s.Error() + } + return reflect.ValueOf(v).String() +} + +func expectReflectMakeFuncPanic() { + defer func() { + err := recover() + if err == nil { + panic("MakeFunc call did not panic") + } + if got := errString(err); !strings.HasPrefix(got, "reflect:") { + panic("MakeFunc panic missing reflect prefix: " + got) + } + }() + + fn := reflect.MakeFunc(reflect.TypeOf(func() error { return nil }), func([]reflect.Value) []reflect.Value { + var out [1]reflect.Value + return out[:] + }).Interface().(func() error) + _ = fn() +} + +func main() { + if got := reflect.ValueOf(foo{}).Type().Field(0).PkgPath; got != "main" { + panic(fmt.Sprintf("field PkgPath = %q, want main", got)) + } + if got := reflect.TypeOf(unsafe.Pointer(nil)).PkgPath(); got != "unsafe" { + panic(fmt.Sprintf("unsafe.Pointer PkgPath = %q, want unsafe", got)) + } + + x := struct{ a, _, c int }{1, blankFieldValue(), 3} + if blankFieldEvalCount != 1 { + panic(fmt.Sprintf("blank field initializer evaluated %d times, want 1", blankFieldEvalCount)) + } + if got := reflect.ValueOf(x).Field(1).Int(); got != 0 { + panic(fmt.Sprintf("blank field reflect value = %d, want 0", got)) + } + + expectReflectMakeFuncPanic() + + nextFalse := reflect.MakeFunc(reflect.TypeOf((func() bool)(nil)), func([]reflect.Value) []reflect.Value { + return []reflect.Value{reflect.ValueOf(false)} + }) + if got := reflect.ValueOf(boolLoop).Call([]reflect.Value{nextFalse})[0].Bool(); got { + panic(fmt.Sprintf("false MakeFunc loop result = %v, want false", got)) + } + + nextTrue := reflect.MakeFunc(reflect.TypeOf((func() bool)(nil)), func([]reflect.Value) []reflect.Value { + return []reflect.Value{reflect.ValueOf(true)} + }) + if got := reflect.ValueOf(boolLoop).Call([]reflect.Value{nextTrue})[0].Bool(); !got { + panic(fmt.Sprintf("true MakeFunc loop result = %v, want true", got)) + } +} +` + +func TestReflectTypeMetadataMakeFuncProbe(t *testing.T) { + dir := t.TempDir() + mainFile := filepath.Join(dir, "main.go") + if err := os.WriteFile(mainFile, []byte(reflectTypeMetadataMakeFuncProbe), 0644); err != nil { + t.Fatal(err) + } + + runGoCmd(t, dir, "run", mainFile) + + root := findLLGoRoot(t) + t.Setenv("LLGO_ROOT", root) + runGoCmd(t, root, "run", "./cmd/llgo", "run", mainFile) +} diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index a5a66d10b4..5a09a750a3 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -2403,10 +2403,6 @@ xfails: directive: run case: fixedbugs/bug348.go reason: latest main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue10332.go - reason: latest main goroot run failure on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue14646.go @@ -2455,10 +2451,6 @@ xfails: directive: run case: fixedbugs/issue27518b.go reason: latest main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue28748.go - reason: latest main goroot run failure on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue29504.go @@ -2475,10 +2467,6 @@ xfails: directive: run case: fixedbugs/issue30116u.go reason: latest main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue31546.go - reason: latest main goroot run failure on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue32477.go @@ -2487,10 +2475,6 @@ xfails: directive: run case: fixedbugs/issue33724.go reason: latest main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue44830.go - reason: latest main goroot run failure on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue45045.go @@ -2503,14 +2487,6 @@ xfails: directive: run case: fixedbugs/issue46725.go reason: latest main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue52788.go - reason: latest main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue52788a.go - reason: latest main goroot run failure on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue54343.go @@ -2571,11 +2547,6 @@ xfails: directive: run case: fixedbugs/bug348.go reason: go1.25 goroot run failure on linux/amd64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/issue10332.go - reason: go1.25 goroot run failure on linux/amd64 - version: go1.25 platform: linux/amd64 directive: run @@ -2651,11 +2622,6 @@ xfails: directive: run case: fixedbugs/issue27518b.go reason: go1.25 goroot run failure on linux/amd64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/issue28748.go - reason: go1.25 goroot run failure on linux/amd64 - version: go1.25 platform: linux/amd64 directive: run @@ -2676,11 +2642,6 @@ xfails: directive: run case: fixedbugs/issue30116u.go reason: go1.25 goroot run failure on linux/amd64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/issue31546.go - reason: go1.25 goroot run failure on linux/amd64 - version: go1.25 platform: linux/amd64 directive: run @@ -2701,11 +2662,6 @@ xfails: directive: run case: fixedbugs/issue4066.go reason: go1.25 goroot run failure on darwin/arm64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/issue44830.go - reason: go1.25 goroot run failure on linux/amd64 - version: go1.25 platform: linux/amd64 directive: run @@ -2721,16 +2677,6 @@ xfails: directive: run case: fixedbugs/issue46725.go reason: go1.25 goroot run failure on linux/amd64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/issue52788.go - reason: go1.25 goroot run failure on linux/amd64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/issue52788a.go - reason: go1.25 goroot run failure on linux/amd64 - version: go1.25 platform: linux/amd64 directive: run @@ -2902,11 +2848,6 @@ xfails: directive: run case: fixedbugs/bug347.go reason: go1.24 goroot run failure on linux/amd64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/issue10332.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -2947,11 +2888,6 @@ xfails: directive: run case: fixedbugs/issue30116.go reason: go1.24 goroot run failure on linux/amd64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/issue31546.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -2962,11 +2898,6 @@ xfails: directive: run case: fixedbugs/issue46725.go reason: go1.24 goroot run failure on linux/amd64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/issue52788.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -3097,11 +3028,6 @@ xfails: directive: run case: fixedbugs/issue27518b.go reason: go1.24 goroot run failure on linux/amd64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/issue28748.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -3127,11 +3053,6 @@ xfails: directive: run case: fixedbugs/issue4066.go reason: go1.24 goroot run failure on darwin/arm64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/issue44830.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -3147,11 +3068,6 @@ xfails: directive: run case: recover4.go reason: go1.24 goroot run failure on linux/amd64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/issue52788a.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -3347,11 +3263,6 @@ xfails: directive: run case: fixedbugs/issue27518b.go reason: go1.26 goroot run failure on linux/amd64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/issue28748.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run @@ -3377,11 +3288,6 @@ xfails: directive: run case: fixedbugs/issue4066.go reason: go1.26 goroot run failure on darwin/arm64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/issue44830.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run @@ -3392,11 +3298,6 @@ xfails: directive: run case: fixedbugs/issue4562.go reason: go1.26 goroot run failure on linux/amd64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/issue52788a.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run @@ -3462,11 +3363,6 @@ xfails: directive: run case: fixedbugs/bug347.go reason: go1.26 goroot run failure on linux/amd64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/issue10332.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run @@ -3507,11 +3403,6 @@ xfails: directive: run case: fixedbugs/issue30116.go reason: go1.26 goroot run failure on linux/amd64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/issue31546.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run @@ -3522,11 +3413,6 @@ xfails: directive: run case: fixedbugs/issue46725.go reason: go1.26 goroot run failure on linux/amd64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/issue52788.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run