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.
Этот коммит содержится в:
родитель
41e787d504
коммит
b08ff17f6b
4 изменённых файлов: 101 добавлений и 14 удалений
|
@ -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.
|
||||
|
|
42
compiler/testdata/errors.go
предоставленный
42
compiler/testdata/errors.go
предоставленный
|
@ -1 +1,43 @@
|
|||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:wasmimport modulename empty
|
||||
func empty()
|
||||
|
||||
// ERROR: can only use //go:wasmimport on declarations
|
||||
//
|
||||
//go:wasmimport modulename implementation
|
||||
func implementation() {
|
||||
}
|
||||
|
||||
type Uint uint32
|
||||
|
||||
//go:wasmimport modulename validparam
|
||||
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
|
||||
//
|
||||
//go:wasmimport modulename invalidparam
|
||||
func invalidparam(a int, b string, c []byte, d *int32)
|
||||
|
||||
//go:wasmimport modulename validreturn
|
||||
func validreturn() int32
|
||||
|
||||
// ERROR: //go:wasmimport modulename manyreturns: too many return values
|
||||
//
|
||||
//go:wasmimport modulename manyreturns
|
||||
func manyreturns() (int32, int32)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidreturn: unsupported result type int
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn
|
||||
func invalidreturn() int
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
|
||||
//
|
||||
//go:wasmimport modulename invalidUnsafePointerReturn
|
||||
func invalidUnsafePointerReturn() unsafe.Pointer
|
||||
|
|
4
compiler/testdata/pragma.go
предоставленный
4
compiler/testdata/pragma.go
предоставленный
|
@ -62,10 +62,6 @@ func exportedFunctionInSection() {
|
|||
//go:wasmimport modulename import1
|
||||
func declaredImport()
|
||||
|
||||
//go:wasmimport modulename import2
|
||||
func definedImport() {
|
||||
}
|
||||
|
||||
// This function should not: it's only a declaration and not a definition.
|
||||
//
|
||||
//go:section .special_function_section
|
||||
|
|
6
compiler/testdata/pragma.ll
предоставленный
6
compiler/testdata/pragma.ll
предоставленный
|
@ -62,12 +62,6 @@ entry:
|
|||
|
||||
declare void @main.declaredImport() #7
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.definedImport(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче