aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRandy Reddig <[email protected]>2024-10-22 18:05:04 +0200
committerGitHub <[email protected]>2024-10-22 18:05:04 +0200
commit24c11d4ba5f722ef646ae0e1ee06b90b2411590c (patch)
tree60df5e0afbebcc9e7d12195b8e3c784a8102d697
parent3dcac3b5396dfd71f52f398d9951a17d992fa6ba (diff)
downloadtinygo-24c11d4ba5f722ef646ae0e1ee06b90b2411590c.tar.gz
tinygo-24c11d4ba5f722ef646ae0e1ee06b90b2411590c.zip
compiler: conform to latest iteration of wasm types proposal (#4501)
compiler: align with current wasm types proposal https://github.com/golang/go/issues/66984 - Remove int and uint as allowed types in params, results, pointers, or struct fields - Only allow small integers in pointers, arrays, or struct fields - enforce structs.HostLayout usage per wasm types proposal https://github.com/golang/go/issues/66984 - require go1.23 for structs.HostLayout - use an interface to check if GoVersion() exists This permits TinyGo to compile with Go 1.21. - use goenv.Compare instead of WantGoVersion - testdata/wasmexport: use int32 instead of int - compiler/testdata: add structs.HostLayout - compiler/testdata: improve tests for structs.HostLayout
-rw-r--r--compiler/symbol.go35
-rw-r--r--compiler/testdata/errors.go44
-rw-r--r--testdata/wasmexport-noscheduler.go6
-rw-r--r--testdata/wasmexport.go10
4 files changed, 72 insertions, 23 deletions
diff --git a/compiler/symbol.go b/compiler/symbol.go
index e175bdd78..9b9b1d10e 100644
--- a/compiler/symbol.go
+++ b/compiler/symbol.go
@@ -12,6 +12,7 @@ import (
"strings"
"github.com/tinygo-org/tinygo/compiler/llvmutil"
+ "github.com/tinygo-org/tinygo/goenv"
"github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/ssa"
"tinygo.org/x/go-llvm"
@@ -422,14 +423,14 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
} else if f.Signature.Results().Len() == 1 {
result := f.Signature.Results().At(0)
- if !isValidWasmType(result.Type(), siteResult) {
+ if !c.isValidWasmType(result.Type(), siteResult) {
c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
}
}
for _, param := range f.Params {
// Check whether the type is allowed.
// Only a very limited number of types can be mapped to WebAssembly.
- if !isValidWasmType(param.Type(), siteParam) {
+ if !c.isValidWasmType(param.Type(), siteParam) {
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
}
}
@@ -442,13 +443,15 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
//
// This previously reflected the additional restrictions documented here:
// https://github.com/golang/go/issues/59149
-func isValidWasmType(typ types.Type, site wasmSite) bool {
+func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
switch typ := typ.Underlying().(type) {
case *types.Basic:
switch typ.Kind() {
case types.Bool:
return true
- case types.Int, types.Uint, types.Int8, types.Uint8, types.Int16, types.Uint16, types.Int32, types.Uint32, types.Int64, types.Uint64:
+ case types.Int8, types.Uint8, types.Int16, types.Uint16:
+ return site == siteIndirect
+ case types.Int32, types.Uint32, types.Int64, types.Uint64:
return true
case types.Float32, types.Float64:
return true
@@ -459,19 +462,35 @@ func isValidWasmType(typ types.Type, site wasmSite) bool {
return site == siteParam || site == siteIndirect
}
case *types.Array:
- return site == siteIndirect && isValidWasmType(typ.Elem(), siteIndirect)
+ return site == siteIndirect && c.isValidWasmType(typ.Elem(), siteIndirect)
case *types.Struct:
if site != siteIndirect {
return false
}
+ // Structs with no fields do not need structs.HostLayout
+ if typ.NumFields() == 0 {
+ return true
+ }
+ hasHostLayout := true // default to true before detecting Go version
+ // (*types.Package).GoVersion added in go1.21
+ if gv, ok := any(c.pkg).(interface{ GoVersion() string }); ok {
+ if goenv.Compare(gv.GoVersion(), "go1.23") >= 0 {
+ hasHostLayout = false // package structs added in go1.23
+ }
+ }
for i := 0; i < typ.NumFields(); i++ {
- if !isValidWasmType(typ.Field(i).Type(), siteIndirect) {
+ ftyp := typ.Field(i).Type()
+ if ftyp.String() == "structs.HostLayout" {
+ hasHostLayout = true
+ continue
+ }
+ if !c.isValidWasmType(ftyp, siteIndirect) {
return false
}
}
- return true
+ return hasHostLayout
case *types.Pointer:
- return isValidWasmType(typ.Elem(), siteIndirect)
+ return c.isValidWasmType(typ.Elem(), siteIndirect)
}
return false
}
diff --git a/compiler/testdata/errors.go b/compiler/testdata/errors.go
index 81e8a76a1..ae95b7523 100644
--- a/compiler/testdata/errors.go
+++ b/compiler/testdata/errors.go
@@ -1,6 +1,9 @@
package main
-import "unsafe"
+import (
+ "structs"
+ "unsafe"
+)
//go:wasmimport modulename empty
func empty()
@@ -14,31 +17,37 @@ func implementation() {
type Uint uint32
type S struct {
+ _ structs.HostLayout
a [4]uint32
b uintptr
- c int
d float32
e float64
}
//go:wasmimport modulename validparam
-func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S)
+func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint, f uintptr, g string, h *int32, i *S, j *struct{}, k *[8]uint8)
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [4]uint32
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type struct{a int}
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type chan struct{}
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type func()
+// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
+// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type uint
+// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type [8]int
//
//go:wasmimport modulename invalidparam
-func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func())
+func invalidparam(a [4]uint32, b []byte, c struct{ a int }, d chan struct{}, e func(), f int, g uint, h [8]int)
+
+// ERROR: //go:wasmimport modulename invalidparam_no_hostlayout: unsupported parameter type *struct{int}
+// ERROR: //go:wasmimport modulename invalidparam_no_hostlayout: unsupported parameter type *struct{string}
+//
+//go:wasmimport modulename invalidparam_no_hostlayout
+func invalidparam_no_hostlayout(a *struct{ int }, b *struct{ string })
//go:wasmimport modulename validreturn_int32
func validreturn_int32() int32
-//go:wasmimport modulename validreturn_int
-func validreturn_int() int
-
//go:wasmimport modulename validreturn_ptr_int32
func validreturn_ptr_int32() *int32
@@ -48,6 +57,12 @@ func validreturn_ptr_string() *string
//go:wasmimport modulename validreturn_ptr_struct
func validreturn_ptr_struct() *S
+//go:wasmimport modulename validreturn_ptr_struct
+func validreturn_ptr_empty_struct() *struct{}
+
+//go:wasmimport modulename validreturn_ptr_array
+func validreturn_ptr_array() *[8]uint8
+
//go:wasmimport modulename validreturn_unsafe_pointer
func validreturn_unsafe_pointer() unsafe.Pointer
@@ -56,11 +71,26 @@ func validreturn_unsafe_pointer() unsafe.Pointer
//go:wasmimport modulename manyreturns
func manyreturns() (int32, int32)
+// ERROR: //go:wasmimport modulename invalidreturn_int: unsupported result type int
+//
+//go:wasmimport modulename invalidreturn_int
+func invalidreturn_int() int
+
+// ERROR: //go:wasmimport modulename invalidreturn_int: unsupported result type uint
+//
+//go:wasmimport modulename invalidreturn_int
+func invalidreturn_uint() uint
+
// ERROR: //go:wasmimport modulename invalidreturn_func: unsupported result type func()
//
//go:wasmimport modulename invalidreturn_func
func invalidreturn_func() func()
+// ERROR: //go:wasmimport modulename invalidreturn_pointer_array_int: unsupported result type *[8]int
+//
+//go:wasmimport modulename invalidreturn_pointer_array_int
+func invalidreturn_pointer_array_int() *[8]int
+
// ERROR: //go:wasmimport modulename invalidreturn_slice_byte: unsupported result type []byte
//
//go:wasmimport modulename invalidreturn_slice_byte
diff --git a/testdata/wasmexport-noscheduler.go b/testdata/wasmexport-noscheduler.go
index 844c8d158..b996b2faa 100644
--- a/testdata/wasmexport-noscheduler.go
+++ b/testdata/wasmexport-noscheduler.go
@@ -18,16 +18,16 @@ func hello() {
}
//go:wasmexport add
-func add(a, b int) int {
+func add(a, b int32) int32 {
println("called add:", a, b)
return a + b
}
//go:wasmimport tester callOutside
-func callOutside(a, b int) int
+func callOutside(a, b int32) int32
//go:wasmexport reentrantCall
-func reentrantCall(a, b int) int {
+func reentrantCall(a, b int32) int32 {
println("reentrantCall:", a, b)
result := callOutside(a, b)
println("reentrantCall result:", result)
diff --git a/testdata/wasmexport.go b/testdata/wasmexport.go
index 9065d6e92..a21576127 100644
--- a/testdata/wasmexport.go
+++ b/testdata/wasmexport.go
@@ -21,15 +21,15 @@ func hello() {
}
//go:wasmexport add
-func add(a, b int) int {
+func add(a, b int32) int32 {
println("called add:", a, b)
addInputs <- a
addInputs <- b
return <-addOutput
}
-var addInputs = make(chan int)
-var addOutput = make(chan int)
+var addInputs = make(chan int32)
+var addOutput = make(chan int32)
func adder() {
for {
@@ -41,10 +41,10 @@ func adder() {
}
//go:wasmimport tester callOutside
-func callOutside(a, b int) int
+func callOutside(a, b int32) int32
//go:wasmexport reentrantCall
-func reentrantCall(a, b int) int {
+func reentrantCall(a, b int32) int32 {
println("reentrantCall:", a, b)
result := callOutside(a, b)
println("reentrantCall result:", result)