diff --git a/ast.go b/ast.go index d9ed444e..3aab851d 100644 --- a/ast.go +++ b/ast.go @@ -175,7 +175,7 @@ retry: func toBasicType(pkg *Package, t *types.Basic) ast.Expr { if t.Kind() == types.UnsafePointer { - return toObjectExpr(pkg, pkg.unsafe().Ref("Pointer")) + return toObjectExpr(pkg, unsafeRef("Pointer")) } if (t.Info() & types.IsUntyped) != 0 { panic("unexpected: untyped type") diff --git a/builtin.go b/builtin.go index 969fb6e8..c5cd2a60 100644 --- a/builtin.go +++ b/builtin.go @@ -38,6 +38,7 @@ func InitBuiltin(pkg *Package, builtin *types.Package, conf *Config) { initBuiltinAssignOps(builtin) initBuiltinFuncs(builtin) initBuiltinTIs(pkg) + initUnsafeFuncs(pkg) } // ---------------------------------------------------------------------------- @@ -390,13 +391,18 @@ func initBuiltinFuncs(builtin *types.Package) { // len & cap are special cases, because they may return a constant value. gbl.Insert(NewInstruction(token.NoPos, builtin, "len", lenInstr{})) gbl.Insert(NewInstruction(token.NoPos, builtin, "cap", capInstr{})) +} +func initUnsafeFuncs(pkg *Package) { + unsafe := types.NewPackage("unsafe", "unsafe") + gbl := unsafe.Scope() // unsafe gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Sizeof", unsafeSizeofInstr{})) gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Alignof", unsafeAlignofInstr{})) gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Offsetof", unsafeOffsetofInstr{})) gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Add", unsafeAddInstr{})) gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Slice", unsafeSliceInstr{})) + pkg.unsafe_.Types = unsafe } func newBFunc(builtin *types.Package, name string, t typeBFunc) types.Object { @@ -736,6 +742,10 @@ func init() { } } +func unsafeRef(name string) Ref { + return PkgRef{types.Unsafe}.Ref(name) +} + type unsafeSizeofInstr struct{} // func unsafe.Sizeof(x ArbitraryType) uintptr @@ -743,7 +753,7 @@ func (p unsafeSizeofInstr) Call(pkg *Package, args []*Element, flags InstrFlags, checkArgsCount(pkg, "unsafe.Sizeof", 1, len(args), src) typ := types.Default(realType(args[0].Type)) - fn := toObjectExpr(pkg, pkg.unsafe().Ref("Sizeof")) + fn := toObjectExpr(pkg, unsafeRef("Sizeof")) ret = &Element{ Val: &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val}}, Type: types.Typ[types.Uintptr], @@ -760,7 +770,7 @@ func (p unsafeAlignofInstr) Call(pkg *Package, args []*Element, flags InstrFlags checkArgsCount(pkg, "unsafe.Alignof", 1, len(args), src) typ := types.Default(realType(args[0].Type)) - fn := toObjectExpr(pkg, pkg.unsafe().Ref("Alignof")) + fn := toObjectExpr(pkg, unsafeRef("Alignof")) ret = &Element{ Val: &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val}}, Type: types.Typ[types.Uintptr], @@ -804,7 +814,7 @@ func (p unsafeOffsetofInstr) Call(pkg *Package, args []*Element, flags InstrFlag pkg.cb.panicCodeErrorf(pos, "%v", err) } //var offset int64 - fn := toObjectExpr(pkg, pkg.unsafe().Ref("Offsetof")) + fn := toObjectExpr(pkg, unsafeRef("Offsetof")) ret = &Element{ Val: &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val}}, Type: types.Typ[types.Uintptr], @@ -890,7 +900,7 @@ func (p unsafeAddInstr) Call(pkg *Package, args []*Element, flags InstrFlags, sr } pkg.cb.panicCodeErrorf(pos, "cannot use %v (type %v) as type int", s, t) } - fn := toObjectExpr(pkg, pkg.unsafe().Ref("Sizeof")).(*ast.SelectorExpr) + fn := toObjectExpr(pkg, unsafeRef("Sizeof")).(*ast.SelectorExpr) fn.Sel.Name = "Add" // only in go v1.7+ ret = &Element{ Val: &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val, args[1].Val}}, @@ -920,7 +930,7 @@ func (p unsafeSliceInstr) Call(pkg *Package, args []*Element, flags InstrFlags, } pkg.cb.panicCodeErrorf(pos, "non-integer len argument in unsafe.Slice - %v", t) } - fn := toObjectExpr(pkg, pkg.unsafe().Ref("Sizeof")).(*ast.SelectorExpr) + fn := toObjectExpr(pkg, unsafeRef("Sizeof")).(*ast.SelectorExpr) fn.Sel.Name = "Slice" // only in go v1.7+ ret = &Element{ Val: &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val, args[1].Val}}, diff --git a/builtin_test.go b/builtin_test.go index 2f3417ea..1b532383 100644 --- a/builtin_test.go +++ b/builtin_test.go @@ -1053,7 +1053,7 @@ func TestBuiltinCall(t *testing.T) { func TestUnsafe(t *testing.T) { pkg := NewPackage("", "foo", gblConf) - sizeof := pkg.unsafe().Ref("Sizeof") + sizeof := unsafeRef("Sizeof") expr := toObjectExpr(pkg, sizeof) if v, ok := expr.(*ast.SelectorExpr); ok { if id, ok := v.X.(*ast.Ident); !ok || id.Name != "unsafe" || v.Sel.Name != "Sizeof" { diff --git a/error_msg_test.go b/error_msg_test.go index 63d1623f..6a40e9ec 100644 --- a/error_msg_test.go +++ b/error_msg_test.go @@ -1133,7 +1133,7 @@ func TestErrUnsafe(t *testing.T) { codeErrorTest(t, `./foo.gop:6:15: missing argument to function call: unsafe.Sizeof()`, func(pkg *gox.Package) { - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). Val(builtin.Ref("Sizeof")).CallWith(0, 0, source("unsafe.Sizeof()", 6, 2)).EndStmt(). EndStmt(). @@ -1142,7 +1142,7 @@ func TestErrUnsafe(t *testing.T) { codeErrorTest(t, `./foo.gop:6:15: too many arguments to function call: unsafe.Sizeof(1, 2)`, func(pkg *gox.Package) { - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). Val(builtin.Ref("Sizeof")).Val(1).Val(2).CallWith(2, 0, source("unsafe.Sizeof(1, 2)", 6, 2)).EndStmt(). EndStmt(). @@ -1151,7 +1151,7 @@ func TestErrUnsafe(t *testing.T) { codeErrorTest(t, `./foo.gop:6:17: invalid expression unsafe.Offsetof(1)`, func(pkg *gox.Package) { - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). Val(builtin.Ref("Offsetof")).Val(1).CallWith(1, 0, source("unsafe.Offsetof(1)", 6, 2)).EndStmt(). EndStmt(). @@ -1168,7 +1168,7 @@ func TestErrUnsafe(t *testing.T) { foo := pkg.NewType("foo").InitType(pkg, typ) recv := pkg.NewParam(token.NoPos, "a", foo) pkg.NewFunc(recv, "Bar", nil, nil, false).BodyStart(pkg).End() - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). NewVar(foo, "a"). Val(builtin.Ref("Offsetof")).VarVal("a").MemberVal("Bar").CallWith(1, 0, source("unsafe.Offsetof(a.Bar)", 14, 2)).EndStmt(). @@ -1177,7 +1177,7 @@ func TestErrUnsafe(t *testing.T) { }) codeErrorTest(t, `./foo.gop:17:26: invalid expression unsafe.Offsetof(t.M.m): selector implies indirection of embedded t.M`, func(pkg *gox.Package) { - builtin := pkg.Builtin() + builtin := pkg.Unsafe() fieldsM := []*types.Var{ types.NewField(token.NoPos, pkg.Types, "m", types.Typ[types.Int], false), types.NewField(token.NoPos, pkg.Types, "n", types.Typ[types.String], false), @@ -1199,7 +1199,7 @@ func TestErrUnsafe(t *testing.T) { `./foo.gop:7:12: cannot use a (type int) as type unsafe.Pointer in argument to unsafe.Add`, func(pkg *gox.Package) { tyInt := types.Typ[types.Int] - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). NewVar(tyInt, "a"). Val(builtin.Ref("Add")).Val(ctxRef(pkg, "a"), source("a", 7, 14)).Val(10).CallWith(2, 0, source("unsafe.Add(a, 10)", 7, 2)).EndStmt(). @@ -1209,7 +1209,7 @@ func TestErrUnsafe(t *testing.T) { `./foo.gop:7:12: cannot use "hello" (type untyped string) as type int`, func(pkg *gox.Package) { tyUP := types.Typ[types.UnsafePointer] - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). NewVar(tyUP, "a"). Val(builtin.Ref("Add")).Val(ctxRef(pkg, "a"), source("a", 7, 14)).Val("hello", source(`"hello"`, 7, 16)).CallWith(2, 0, source("unsafe.Add(a, 10)", 7, 2)).EndStmt(). @@ -1219,7 +1219,7 @@ func TestErrUnsafe(t *testing.T) { `./foo.gop:7:14: first argument to unsafe.Slice must be pointer; have int`, func(pkg *gox.Package) { tyInt := types.Typ[types.Int] - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). NewVar(tyInt, "a"). Val(builtin.Ref("Slice")).VarVal("a").Val(10).CallWith(2, 0, source(`unsafe.Slice(a, 10)`, 7, 2)).EndStmt(). @@ -1229,7 +1229,7 @@ func TestErrUnsafe(t *testing.T) { `./foo.gop:7:14: non-integer len argument in unsafe.Slice - untyped string`, func(pkg *gox.Package) { tyInt := types.Typ[types.Int] - builtin := pkg.Builtin() + builtin := pkg.Unsafe() pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). NewVarStart(nil, "ar"). Val(1).Val(2).Val(3).ArrayLit(types.NewArray(tyInt, 3), 3).EndInit(1). diff --git a/import.go b/import.go index bb648358..a4906830 100644 --- a/import.go +++ b/import.go @@ -549,10 +549,6 @@ func (p *Package) big() PkgRef { return p.pkgBig } -func (p *Package) unsafe() PkgRef { - return PkgRef{types.Unsafe} -} - // ---------------------------------------------------------------------------- type null struct{} diff --git a/package.go b/package.go index 7dd65dc4..aebfea97 100644 --- a/package.go +++ b/package.go @@ -323,6 +323,7 @@ type Package struct { files map[string]*File file *File conf *Config + unsafe_ PkgRef builtin PkgRef pkgBig PkgRef utBigInt *types.Named @@ -420,6 +421,11 @@ func (p *Package) Builtin() PkgRef { return p.builtin } +// Builtin returns the unsafe package. +func (p *Package) Unsafe() PkgRef { + return p.unsafe_ +} + // CB returns the code builder. func (p *Package) CB() *CodeBuilder { return &p.cb diff --git a/package_test.go b/package_test.go index 552b2b2c..fa456027 100644 --- a/package_test.go +++ b/package_test.go @@ -1770,11 +1770,12 @@ func TestUnsafeFunc(t *testing.T) { tyT := pkg.NewType("T").InitType(pkg, typ) tyUintptr := types.Typ[types.Uintptr] builtin := pkg.Builtin() + unsafe := pkg.Unsafe() pkg.NewFunc(nil, "test", nil, nil, false).BodyStart(pkg). NewVar(tyT, "a").NewVar(tyUintptr, "r"). - VarRef(ctxRef(pkg, "r")).Val(builtin.Ref("Sizeof")).VarVal("a").Call(1).Assign(1).EndStmt(). - VarRef(ctxRef(pkg, "r")).Val(builtin.Ref("Alignof")).VarVal("a").Call(1).Assign(1).EndStmt(). - VarRef(ctxRef(pkg, "r")).Val(builtin.Ref("Offsetof")).VarVal("a").MemberVal("y").Call(1).Assign(1).EndStmt(). + VarRef(ctxRef(pkg, "r")).Val(unsafe.Ref("Sizeof")).VarVal("a").Call(1).Assign(1).EndStmt(). + VarRef(ctxRef(pkg, "r")).Val(unsafe.Ref("Alignof")).VarVal("a").Call(1).Assign(1).EndStmt(). + VarRef(ctxRef(pkg, "r")).Val(unsafe.Ref("Offsetof")).VarVal("a").MemberVal("y").Call(1).Assign(1).EndStmt(). Val(builtin.Ref("println")).VarRef(ctxRef(pkg, "r")).Call(1).EndStmt(). End() domTest(t, pkg, `package main @@ -1800,6 +1801,7 @@ func test() { func TestUnsafeFunc2(t *testing.T) { pkg := newMainPackage() builtin := pkg.Builtin() + unsafe := pkg.Unsafe() tyUP := types.Typ[types.UnsafePointer] tyInt := types.Typ[types.Int] pkg.NewFunc(nil, "test17", nil, nil, false).BodyStart(pkg). @@ -1807,8 +1809,8 @@ func TestUnsafeFunc2(t *testing.T) { NewVarStart(nil, "ar"). Val(1).Val(2).Val(3).ArrayLit(types.NewArray(tyInt, 3), 3).EndInit(1). NewVar(types.NewSlice(tyInt), "r2"). - VarRef(ctxRef(pkg, "r")).Val(builtin.Ref("Add")).VarVal("a").Val(10).Call(2).Assign(1).EndStmt(). - VarRef(ctxRef(pkg, "r2")).Val(builtin.Ref("Slice")).Val(ctxRef(pkg, "ar")).Val(0).Index(1, false).UnaryOp(token.AND).Val(3).Call(2).Assign(1).EndStmt(). + VarRef(ctxRef(pkg, "r")).Val(unsafe.Ref("Add")).VarVal("a").Val(10).Call(2).Assign(1).EndStmt(). + VarRef(ctxRef(pkg, "r2")).Val(unsafe.Ref("Slice")).Val(ctxRef(pkg, "ar")).Val(0).Index(1, false).UnaryOp(token.AND).Val(3).Call(2).Assign(1).EndStmt(). Val(builtin.Ref("println")).VarRef(ctxRef(pkg, "r")).VarRef(ctxRef(pkg, "r2")).Call(2).EndStmt(). End() domTest(t, pkg, `package main @@ -1829,7 +1831,7 @@ func test17() { func TestUnsafeConst(t *testing.T) { pkg := newMainPackage() - builtin := pkg.Builtin() + unsafe_ := pkg.Unsafe() fieldsM := []*types.Var{ types.NewField(token.NoPos, pkg.Types, "m", types.Typ[types.Int], false), types.NewField(token.NoPos, pkg.Types, "n", types.Typ[types.String], false), @@ -1845,17 +1847,17 @@ func TestUnsafeConst(t *testing.T) { tyT := pkg.NewType("T").InitType(pkg, typT) pkg.CB().NewVar(tyT, "t") pkg.CB().NewConstStart(nil, "c1"). - Val(builtin.Ref("Sizeof")).Val(100).Call(1).EndInit(1) + Val(unsafe_.Ref("Sizeof")).Val(100).Call(1).EndInit(1) pkg.CB().NewConstStart(nil, "c2"). - Val(builtin.Ref("Sizeof")).Val(ctxRef(pkg, "t")).Call(1).EndInit(1) + Val(unsafe_.Ref("Sizeof")).Val(ctxRef(pkg, "t")).Call(1).EndInit(1) pkg.CB().NewConstStart(nil, "c3"). - Val(builtin.Ref("Alignof")).Val("hello").Call(1).EndInit(1) + Val(unsafe_.Ref("Alignof")).Val("hello").Call(1).EndInit(1) pkg.CB().NewConstStart(nil, "c4"). - Val(builtin.Ref("Alignof")).Val(ctxRef(pkg, "t")).Call(1).EndInit(1) + Val(unsafe_.Ref("Alignof")).Val(ctxRef(pkg, "t")).Call(1).EndInit(1) pkg.CB().NewConstStart(nil, "c5"). - Val(builtin.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("y").Call(1).EndInit(1) + Val(unsafe_.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("y").Call(1).EndInit(1) pkg.CB().NewConstStart(nil, "c6"). - Val(builtin.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("n").Call(1).EndInit(1) + Val(unsafe_.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("n").Call(1).EndInit(1) domTest(t, pkg, `package main @@ -1880,19 +1882,19 @@ const c4 = unsafe.Alignof(t) const c5 = unsafe.Offsetof(t.y) const c6 = unsafe.Offsetof(t.n) `) - c1 := pkg.CB().Val(builtin.Ref("Sizeof")).Val(ctxRef(pkg, "t")).Call(1).Get(-1) + c1 := pkg.CB().Val(unsafe_.Ref("Sizeof")).Val(ctxRef(pkg, "t")).Call(1).Get(-1) if v, ok := constant.Int64Val(c1.CVal); !ok || uintptr(v) != (unsafe.Sizeof(int(0))*2+unsafe.Sizeof("")*2) { t.Fatalf("unsafe.Sizeof(t) %v", c1.CVal) } - c2 := pkg.CB().Val(builtin.Ref("Alignof")).Val(ctxRef(pkg, "t")).Call(1).Get(-1) + c2 := pkg.CB().Val(unsafe_.Ref("Alignof")).Val(ctxRef(pkg, "t")).Call(1).Get(-1) if v, ok := constant.Int64Val(c2.CVal); !ok || uintptr(v) != unsafe.Alignof("") { t.Fatalf("unsafe.Alignof(t) %v", c2.CVal) } - c3 := pkg.CB().Val(builtin.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("y").Call(1).Get(-1) + c3 := pkg.CB().Val(unsafe_.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("y").Call(1).Get(-1) if v, ok := constant.Int64Val(c3.CVal); !ok || uintptr(v) != unsafe.Sizeof(int(0)) { t.Fatalf("unsafe.Offsetof(t.y) %v", c3.CVal) } - c4 := pkg.CB().Val(builtin.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("n").Call(1).Get(-1) + c4 := pkg.CB().Val(unsafe_.Ref("Offsetof")).Val(ctxRef(pkg, "t")).MemberVal("n").Call(1).Get(-1) if v, ok := constant.Int64Val(c4.CVal); !ok || uintptr(v) != (unsafe.Sizeof(int(0))*2+unsafe.Sizeof("")) { t.Fatalf("unsafe.Offsetof(t.n) %v", c4.CVal) }