aboutsummaryrefslogtreecommitdiffhomepage
path: root/compiler/symbol.go
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2023-05-19 15:34:05 +0200
committerRon Evans <[email protected]>2023-05-20 11:24:20 +0200
commitb08ff17f6bb16089f87cd2345960e3bb974fd4bf (patch)
treebc4eff02c3354b75335efd17dae5f36f17c8d08c /compiler/symbol.go
parent41e787d504da37d447e6b209c25c7dff23062c7a (diff)
downloadtinygo-b08ff17f6bb16089f87cd2345960e3bb974fd4bf.tar.gz
tinygo-b08ff17f6bb16089f87cd2345960e3bb974fd4bf.zip
compiler: disallow most types in //go:wasmimport
This is for compatibility with upstream Go. See https://github.com/golang/go/issues/59149 for more context.
Diffstat (limited to 'compiler/symbol.go')
-rw-r--r--compiler/symbol.go63
1 files changed, 59 insertions, 4 deletions
diff --git a/compiler/symbol.go b/compiler/symbol.go
index 7d9fcc2ff..6426604ec 100644
--- a/compiler/symbol.go
+++ b/compiler/symbol.go
@@ -4,6 +4,7 @@ package compiler
// pragmas, determines the link name, etc.
import (
+ "fmt"
"go/ast"
"go/token"
"go/types"
@@ -247,14 +248,14 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
linkName: f.RelString(nil),
}
// Check for //go: pragmas, which may change the link name (among others).
- info.parsePragmas(f)
+ c.parsePragmas(&info, f)
c.functionInfos[f] = info
return info
}
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
// //export or //go:noinline.
-func (info *functionInfo) parsePragmas(f *ssa.Function) {
+func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
if f.Syntax() == nil {
return
}
@@ -294,10 +295,12 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
info.module = parts[1]
case "//go:wasmimport":
// Import a WebAssembly function, for example a WASI function.
- // For details, see: https://github.com/golang/go/issues/38248
- if len(parts) != 3 || len(f.Blocks) != 0 {
+ // Original proposal: https://github.com/golang/go/issues/38248
+ // Allow globally: https://github.com/golang/go/issues/59149
+ if len(parts) != 3 {
continue
}
+ c.checkWasmImport(f, comment.Text)
info.exported = true
info.module = parts[1]
info.importName = parts[2]
@@ -358,6 +361,58 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
}
}
+// Check whether this function cannot be used in //go:wasmimport. It will add an
+// error if this is the case.
+//
+// The list of allowed types is based on this proposal:
+// https://github.com/golang/go/issues/59149
+func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
+ if c.pkg.Path() == "runtime" {
+ // The runtime is a special case. Allow all kinds of parameters
+ // (importantly, including pointers).
+ return
+ }
+ if f.Blocks != nil {
+ // Defined functions cannot be exported.
+ c.addError(f.Pos(), fmt.Sprintf("can only use //go:wasmimport on declarations"))
+ return
+ }
+ if f.Signature.Results().Len() > 1 {
+ 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(), true) {
+ 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(), false) {
+ c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
+ }
+ }
+}
+
+// Check whether the type maps directly to a WebAssembly type, according to:
+// https://github.com/golang/go/issues/59149
+func isValidWasmType(typ types.Type, isReturn bool) bool {
+ switch typ := typ.Underlying().(type) {
+ case *types.Basic:
+ switch typ.Kind() {
+ case types.Int32, types.Uint32, types.Int64, types.Uint64:
+ return true
+ case types.Float32, types.Float64:
+ return true
+ case types.UnsafePointer:
+ if !isReturn {
+ return true
+ }
+ }
+ }
+ return false
+}
+
// getParams returns the function parameters, including the receiver at the
// start. This is an alternative to the Params member of *ssa.Function, which is
// not yet populated when the package has not yet been built.