@@ -12,6 +12,7 @@ import (
1212 "strings"
1313
1414 "github.com/tinygo-org/tinygo/compiler/llvmutil"
15+ "github.com/tinygo-org/tinygo/goenv"
1516 "github.com/tinygo-org/tinygo/loader"
1617 "golang.org/x/tools/go/ssa"
1718 "tinygo.org/x/go-llvm"
@@ -422,14 +423,14 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
422423 c .addError (f .Signature .Results ().At (1 ).Pos (), fmt .Sprintf ("%s: too many return values" , pragma ))
423424 } else if f .Signature .Results ().Len () == 1 {
424425 result := f .Signature .Results ().At (0 )
425- if ! isValidWasmType (result .Type (), siteResult ) {
426+ if ! c . isValidWasmType (result .Type (), siteResult ) {
426427 c .addError (result .Pos (), fmt .Sprintf ("%s: unsupported result type %s" , pragma , result .Type ().String ()))
427428 }
428429 }
429430 for _ , param := range f .Params {
430431 // Check whether the type is allowed.
431432 // Only a very limited number of types can be mapped to WebAssembly.
432- if ! isValidWasmType (param .Type (), siteParam ) {
433+ if ! c . isValidWasmType (param .Type (), siteParam ) {
433434 c .addError (param .Pos (), fmt .Sprintf ("%s: unsupported parameter type %s" , pragma , param .Type ().String ()))
434435 }
435436 }
@@ -442,7 +443,7 @@ func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string)
442443//
443444// This previously reflected the additional restrictions documented here:
444445// https://github.com/golang/go/issues/59149
445- func isValidWasmType (typ types.Type , site wasmSite ) bool {
446+ func ( c * compilerContext ) isValidWasmType (typ types.Type , site wasmSite ) bool {
446447 switch typ := typ .Underlying ().(type ) {
447448 case * types.Basic :
448449 switch typ .Kind () {
@@ -461,19 +462,35 @@ func isValidWasmType(typ types.Type, site wasmSite) bool {
461462 return site == siteParam || site == siteIndirect
462463 }
463464 case * types.Array :
464- return site == siteIndirect && isValidWasmType (typ .Elem (), siteIndirect )
465+ return site == siteIndirect && c . isValidWasmType (typ .Elem (), siteIndirect )
465466 case * types.Struct :
466467 if site != siteIndirect {
467468 return false
468469 }
470+ // Structs with no fields do not need structs.HostLayout
471+ if typ .NumFields () == 0 {
472+ return true
473+ }
474+ hasHostLayout := true // default to true before detecting Go version
475+ // (*types.Package).GoVersion added in go1.21
476+ if gv , ok := any (c .pkg ).(interface { GoVersion () string }); ok {
477+ if goenv .Compare (gv .GoVersion (), "go1.23" ) >= 0 {
478+ hasHostLayout = false // package structs added in go1.23
479+ }
480+ }
469481 for i := 0 ; i < typ .NumFields (); i ++ {
470- if ! isValidWasmType (typ .Field (i ).Type (), siteIndirect ) {
482+ ftyp := typ .Field (i ).Type ()
483+ if ftyp .String () == "structs.HostLayout" {
484+ hasHostLayout = true
485+ continue
486+ }
487+ if ! c .isValidWasmType (ftyp , siteIndirect ) {
471488 return false
472489 }
473490 }
474- return true
491+ return hasHostLayout
475492 case * types.Pointer :
476- return isValidWasmType (typ .Elem (), siteIndirect )
493+ return c . isValidWasmType (typ .Elem (), siteIndirect )
477494 }
478495 return false
479496}
0 commit comments