]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] merge master into dev.typeparams
authorRob Findley <rfindley@google.com>
Tue, 3 Nov 2020 17:31:40 +0000 (12:31 -0500)
committerRob Findley <rfindley@google.com>
Tue, 3 Nov 2020 17:31:40 +0000 (12:31 -0500)
Change-Id: I0e56b7b659ac84e14121325c560a242554196808

1  2 
src/cmd/compile/fmtmap_test.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/noder.go

index bcc82dda2fe7ffd188eb04f91167b60c02525f3a,0811df7f7b80074ede902181944f703c5dc89968..a7c1eca9dbe10734f38222320b119684a6860fce
@@@ -42,10 -42,6 +42,10 @@@ var knownFormats = map[string]string
        "*cmd/compile/internal/ssa.Value %s":              "",
        "*cmd/compile/internal/ssa.Value %v":              "",
        "*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
 +      "*cmd/compile/internal/syntax.CallExpr %s":        "",
 +      "*cmd/compile/internal/syntax.CallExpr %v":        "",
 +      "*cmd/compile/internal/syntax.FuncLit %s":         "",
 +      "*cmd/compile/internal/syntax.IndexExpr %s":       "",
        "*cmd/compile/internal/types.Field %p":            "",
        "*cmd/compile/internal/types.Field %v":            "",
        "*cmd/compile/internal/types.Sym %0S":             "",
        "*cmd/compile/internal/types.Type %p":             "",
        "*cmd/compile/internal/types.Type %s":             "",
        "*cmd/compile/internal/types.Type %v":             "",
 +      "*cmd/compile/internal/types2.Basic %s":           "",
 +      "*cmd/compile/internal/types2.Chan %s":            "",
 +      "*cmd/compile/internal/types2.Func %s":            "",
 +      "*cmd/compile/internal/types2.Initializer %s":     "",
 +      "*cmd/compile/internal/types2.Interface %s":       "",
 +      "*cmd/compile/internal/types2.MethodSet %s":       "",
 +      "*cmd/compile/internal/types2.Named %s":           "",
 +      "*cmd/compile/internal/types2.Named %v":           "",
 +      "*cmd/compile/internal/types2.Package %s":         "",
 +      "*cmd/compile/internal/types2.Package %v":         "",
 +      "*cmd/compile/internal/types2.Scope %p":           "",
 +      "*cmd/compile/internal/types2.Selection %s":       "",
 +      "*cmd/compile/internal/types2.Signature %s":       "",
 +      "*cmd/compile/internal/types2.TypeName %s":        "",
 +      "*cmd/compile/internal/types2.TypeName %v":        "",
 +      "*cmd/compile/internal/types2.TypeParam %s":       "",
 +      "*cmd/compile/internal/types2.Var %s":             "",
 +      "*cmd/compile/internal/types2.operand %s":         "",
 +      "*cmd/compile/internal/types2.substMap %s":        "",
        "*cmd/internal/obj.Addr %v":                       "",
        "*cmd/internal/obj.LSym %v":                       "",
        "*math/big.Float %f":                              "",
@@@ -90,8 -67,6 +90,8 @@@
        "[16]byte %x":                                     "",
        "[]*cmd/compile/internal/ssa.Block %v":            "",
        "[]*cmd/compile/internal/ssa.Value %v":            "",
 +      "[]*cmd/compile/internal/types2.Func %v":          "",
 +      "[]*cmd/compile/internal/types2.TypeName %s":      "",
        "[][]string %q":                                   "",
        "[]byte %s":                                       "",
        "[]byte %x":                                       "",
        "[]cmd/compile/internal/ssa.posetNode %v":         "",
        "[]cmd/compile/internal/ssa.posetUndo %v":         "",
        "[]cmd/compile/internal/syntax.token %s":          "",
 +      "[]cmd/compile/internal/types2.Type %s":           "",
 +      "[]int %v":                                        "",
        "[]string %v":                                     "",
        "[]uint32 %v":                                     "",
        "bool %v":                                         "",
        "cmd/compile/internal/gc.fmtMode %d":              "",
        "cmd/compile/internal/gc.initKind %d":             "",
        "cmd/compile/internal/gc.itag %v":                 "",
 +      "cmd/compile/internal/importer.itag %v":           "",
        "cmd/compile/internal/ssa.BranchPrediction %d":    "",
        "cmd/compile/internal/ssa.Edge %v":                "",
        "cmd/compile/internal/ssa.GCNode %v":              "",
        "cmd/compile/internal/ssa.ID %d":                  "",
        "cmd/compile/internal/ssa.ID %v":                  "",
-       "cmd/compile/internal/ssa.LocPair %s":             "",
        "cmd/compile/internal/ssa.LocalSlot %s":           "",
        "cmd/compile/internal/ssa.LocalSlot %v":           "",
-       "cmd/compile/internal/ssa.Location %T":            "",
        "cmd/compile/internal/ssa.Location %s":            "",
        "cmd/compile/internal/ssa.Op %s":                  "",
        "cmd/compile/internal/ssa.Op %v":                  "",
        "cmd/compile/internal/ssa.regMask %d":             "",
        "cmd/compile/internal/ssa.register %d":            "",
        "cmd/compile/internal/ssa.relation %s":            "",
 +      "cmd/compile/internal/syntax.ChanDir %d":          "",
 +      "cmd/compile/internal/syntax.Decl %T":             "",
        "cmd/compile/internal/syntax.Error %q":            "",
 +      "cmd/compile/internal/syntax.Error %v":            "",
        "cmd/compile/internal/syntax.Expr %#v":            "",
 +      "cmd/compile/internal/syntax.Expr %T":             "",
 +      "cmd/compile/internal/syntax.Expr %s":             "",
        "cmd/compile/internal/syntax.LitKind %d":          "",
        "cmd/compile/internal/syntax.Node %T":             "",
        "cmd/compile/internal/syntax.Operator %s":         "",
        "cmd/compile/internal/types.EType %d":             "",
        "cmd/compile/internal/types.EType %s":             "",
        "cmd/compile/internal/types.EType %v":             "",
 +      "cmd/compile/internal/types2.Object %T":           "",
 +      "cmd/compile/internal/types2.Object %p":           "",
 +      "cmd/compile/internal/types2.Object %s":           "",
 +      "cmd/compile/internal/types2.Object %v":           "",
 +      "cmd/compile/internal/types2.Type %T":             "",
 +      "cmd/compile/internal/types2.Type %s":             "",
 +      "cmd/compile/internal/types2.Type %v":             "",
 +      "cmd/compile/internal/types2.color %s":            "",
        "cmd/internal/obj.ABI %v":                         "",
 +      "error %s":                                        "",
        "error %v":                                        "",
        "float64 %.2f":                                    "",
        "float64 %.3f":                                    "",
        "float64 %.6g":                                    "",
        "float64 %g":                                      "",
 +      "go/constant.Value %s":                            "",
        "int %#x":                                         "",
        "int %-12d":                                       "",
        "int %-6d":                                        "",
        "interface{} %q":                                  "",
        "interface{} %s":                                  "",
        "interface{} %v":                                  "",
 -      "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
 -      "map[*cmd/compile/internal/gc.Node][]*cmd/compile/internal/gc.Node %v": "",
 -      "map[cmd/compile/internal/ssa.ID]uint32 %v":                            "",
 +      "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v":           "",
 +      "map[*cmd/compile/internal/gc.Node][]*cmd/compile/internal/gc.Node %v":           "",
 +      "map[*cmd/compile/internal/types2.TypeParam]cmd/compile/internal/types2.Type %s": "",
 +      "map[cmd/compile/internal/ssa.ID]uint32 %v":                                      "",
        "map[int64]uint32 %v":  "",
        "math/big.Accuracy %s": "",
        "reflect.Type %s":      "",
        "string %-*s":          "",
        "string %-16s":         "",
        "string %-6s":          "",
 +      "string %T":            "",
        "string %q":            "",
        "string %s":            "",
        "string %v":            "",
        "uint64 %08x":          "",
        "uint64 %b":            "",
        "uint64 %d":            "",
 +      "uint64 %v":            "",
        "uint64 %x":            "",
        "uint8 %#x":            "",
        "uint8 %d":             "",
index 2a2b6bee011699aceb6b895863134f2b16a784d0,8b94c7f71b6d3b5645b22add049a1acb40ce8f6b..b6e52f482d44628bbcd3fdac62b38732fd3a18e6
@@@ -34,8 -34,6 +34,6 @@@ import 
        "strings"
  )
  
- var imported_unsafe bool
  var (
        buildid      string
        spectre      string
@@@ -217,7 -215,6 +215,7 @@@ func Main(archInit func(*Arch)) 
        objabi.Flagcount("B", "disable bounds checking", &Debug.B)
        objabi.Flagcount("C", "disable printing of columns in error messages", &Debug.C)
        objabi.Flagcount("E", "debug symbol export", &Debug.E)
 +      objabi.Flagcount("G", "accept generic code", &Debug.G)
        objabi.Flagcount("K", "debug missing line numbers", &Debug.K)
        objabi.Flagcount("L", "show full file names in error messages", &Debug.L)
        objabi.Flagcount("N", "disable optimizations", &Debug.N)
        flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
        flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
        flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
+       objabi.Flagfn1("embedcfg", "read go:embed configuration from `file`", readEmbedCfg)
        objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
        objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
        flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
        loadsys()
  
        timings.Start("fe", "parse")
 -      lines := parseFiles(flag.Args())
 +      lines := parseFiles(flag.Args(), Debug.G != 0)
        timings.Stop()
        timings.AddEvent(int64(lines), "lines")
 +      if Debug.G != 0 {
 +              // can only parse generic code for now
 +              if nerrors+nsavederrors != 0 {
 +                      errorexit()
 +              }
 +              return
 +      }
  
        finishUniverse()
  
        timings.Start("fe", "typecheck", "top1")
        for i := 0; i < len(xtop); i++ {
                n := xtop[i]
-               if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
+               if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
                        xtop[i] = typecheck(n, ctxStmt)
                }
        }
        timings.Start("fe", "typecheck", "top2")
        for i := 0; i < len(xtop); i++ {
                n := xtop[i]
-               if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
+               if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
                        xtop[i] = typecheck(n, ctxStmt)
                }
        }
                })
        }
  
+       for _, n := range xtop {
+               if n.Op == ODCLFUNC {
+                       devirtualize(n)
+               }
+       }
+       Curfn = nil
        // Phase 6: Escape analysis.
        // Required for moving heap allocations onto stack,
        // which in turn is required by the closure implementation,
@@@ -1185,7 -1183,6 +1191,6 @@@ func importfile(f *Val) *types.Pkg 
        }
  
        if path_ == "unsafe" {
-               imported_unsafe = true
                return unsafepkg
        }
  
index 9685794ec4f5d0deadd70ae966c863b50f380622,67d24ef0bc70672be7c579b9ee211066b34d80c6..14bacc14a8b39845683aa0baaa900d1854a28b07
@@@ -6,18 -6,16 +6,19 @@@ package g
  
  import (
        "fmt"
 +      "io"
        "os"
        "path/filepath"
        "runtime"
        "strconv"
        "strings"
+       "unicode"
        "unicode/utf8"
  
 +      "cmd/compile/internal/importer"
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/types"
 +      "cmd/compile/internal/types2"
        "cmd/internal/obj"
        "cmd/internal/objabi"
        "cmd/internal/src"
@@@ -27,7 -25,7 +28,7 @@@
  // Each declaration in every *syntax.File is converted to a syntax tree
  // and its root represented by *Node is appended to xtop.
  // Returns the total count of parsed lines.
 -func parseFiles(filenames []string) uint {
 +func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
        noders := make([]*noder, 0, len(filenames))
        // Limit the number of simultaneously open files.
        sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
                        }
                        defer f.Close()
  
 -                      p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
 +                      mode := syntax.CheckBranches
 +                      if allowGenerics {
 +                              mode |= syntax.AllowGenerics
 +                      }
 +                      p.file, _ = syntax.Parse(base, f, p.error, p.pragma, mode) // errors are tracked via p.error
                }(filename)
        }
  
 -      var lines uint
 +      if allowGenerics {
 +              nodersmap := make(map[string]*noder)
 +              var files []*syntax.File
 +              for _, p := range noders {
 +                      for e := range p.err {
 +                              p.yyerrorpos(e.Pos, "%s", e.Msg)
 +                      }
 +
 +                      nodersmap[p.file.Pos().RelFilename()] = p
 +                      files = append(files, p.file)
 +                      lines += p.file.EOF.Line()
 +
 +                      if nsyntaxerrors != 0 {
 +                              errorexit()
 +                      }
 +              }
 +
 +              conf := types2.Config{
 +                      InferFromConstraints: true,
 +                      Error: func(err error) {
 +                              terr := err.(types2.Error)
 +                              if len(terr.Msg) > 0 && terr.Msg[0] == '\t' {
 +                                      // types2 reports error clarifications via separate
 +                                      // error messages which are indented with a tab.
 +                                      // Ignore them to satisfy tools and tests that expect
 +                                      // only one error in such cases.
 +                                      // TODO(gri) Need to adjust error reporting in types2.
 +                                      return
 +                              }
 +                              p := nodersmap[terr.Pos.RelFilename()]
 +                              yyerrorl(p.makeXPos(terr.Pos), "%s", terr.Msg)
 +                      },
 +                      Importer: &gcimports{
 +                              packages: make(map[string]*types2.Package),
 +                      },
 +              }
 +              conf.Check(Ctxt.Pkgpath, files, nil)
 +              return
 +      }
 +
        for _, p := range noders {
                for e := range p.err {
                        p.yyerrorpos(e.Pos, "%s", e.Msg)
                }
  
                p.node()
 -              lines += p.file.Lines
 +              lines += p.file.EOF.Line()
                p.file = nil // release memory
  
                if nsyntaxerrors != 0 {
        }
  
        localpkg.Height = myheight
 +      return
 +}
 +
 +// Temporary import helper to get type2-based type-checking going.
 +type gcimports struct {
 +      packages map[string]*types2.Package
 +      lookup   func(path string) (io.ReadCloser, error)
 +}
 +
 +func (m *gcimports) Import(path string) (*types2.Package, error) {
 +      return m.ImportFrom(path, "" /* no vendoring */, 0)
 +}
  
 -      return lines
 +func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) {
 +      if mode != 0 {
 +              panic("mode must be 0")
 +      }
 +      return importer.Import(m.packages, path, srcDir, m.lookup)
  }
  
  // makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase.
@@@ -152,7 -91,11 +153,11 @@@ func (p *noder) makeSrcPosBase(b0 *synt
                } else {
                        // line directive base
                        p0 := b0.Pos()
-                       p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line(), p0.Col())
+                       p0b := p0.Base()
+                       if p0b == b0 {
+                               panic("infinite recursion in makeSrcPosBase")
+                       }
+                       p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col())
                        b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
                }
                p.basemap[b0] = b1
@@@ -192,11 -135,13 +197,13 @@@ type noder struct 
                base *src.PosBase
        }
  
-       file       *syntax.File
-       linknames  []linkname
-       pragcgobuf [][]string
-       err        chan syntax.Error
-       scope      ScopeID
+       file           *syntax.File
+       linknames      []linkname
+       pragcgobuf     [][]string
+       err            chan syntax.Error
+       scope          ScopeID
+       importedUnsafe bool
+       importedEmbed  bool
  
        // scopeVars is a stack tracking the number of variables declared in the
        // current function at the moment each open scope was opened.
@@@ -298,7 -243,8 +305,8 @@@ type linkname struct 
  
  func (p *noder) node() {
        types.Block = 1
-       imported_unsafe = false
+       p.importedUnsafe = false
+       p.importedEmbed = false
  
        p.setlineno(p.file.PkgName)
        mkpackage(p.file.PkgName.Value)
        xtop = append(xtop, p.decls(p.file.DeclList)...)
  
        for _, n := range p.linknames {
-               if !imported_unsafe {
+               if !p.importedUnsafe {
                        p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
                        continue
                }
@@@ -386,7 -332,6 +394,6 @@@ func (p *noder) importDecl(imp *syntax.
  
        val := p.basicLit(imp.Path)
        ipkg := importfile(&val)
        if ipkg == nil {
                if nerrors == 0 {
                        Fatalf("phase error in import")
                return
        }
  
+       if ipkg == unsafepkg {
+               p.importedUnsafe = true
+       }
+       if ipkg.Path == "embed" {
+               p.importedEmbed = true
+       }
        ipkg.Direct = true
  
        var my *types.Sym
@@@ -435,6 -387,20 +449,20 @@@ func (p *noder) varDecl(decl *syntax.Va
        }
  
        if pragma, ok := decl.Pragma.(*Pragma); ok {
+               if len(pragma.Embeds) > 0 {
+                       if !p.importedEmbed {
+                               // This check can't be done when building the list pragma.Embeds
+                               // because that list is created before the noder starts walking over the file,
+                               // so at that point it hasn't seen the imports.
+                               // We're left to check now, just before applying the //go:embed lines.
+                               for _, e := range pragma.Embeds {
+                                       p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
+                               }
+                       } else {
+                               exprs = varEmbed(p, names, typ, exprs, pragma.Embeds)
+                       }
+                       pragma.Embeds = nil
+               }
                p.checkUnused(pragma)
        }
  
@@@ -517,17 -483,17 +545,17 @@@ func (p *noder) typeDecl(decl *syntax.T
  
        param := n.Name.Param
        param.Ntype = typ
-       param.Alias = decl.Alias
+       param.SetAlias(decl.Alias)
        if pragma, ok := decl.Pragma.(*Pragma); ok {
                if !decl.Alias {
-                       param.Pragma = pragma.Flag & TypePragmas
+                       param.SetPragma(pragma.Flag & TypePragmas)
                        pragma.Flag &^= TypePragmas
                }
                p.checkUnused(pragma)
        }
  
        nod := p.nod(decl, ODCLTYPE, n, nil)
-       if param.Alias && !langSupported(1, 9, localpkg) {
+       if param.Alias() && !langSupported(1, 9, localpkg) {
                yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
        }
        return nod
@@@ -1555,13 -1521,15 +1583,15 @@@ var allowedStdPragmas = map[string]bool
        "go:cgo_import_dynamic": true,
        "go:cgo_ldflag":         true,
        "go:cgo_dynamic_linker": true,
+       "go:embed":              true,
        "go:generate":           true,
  }
  
  // *Pragma is the value stored in a syntax.Pragma during parsing.
  type Pragma struct {
-       Flag PragmaFlag  // collected bits
-       Pos  []PragmaPos // position of each individual flag
+       Flag   PragmaFlag  // collected bits
+       Pos    []PragmaPos // position of each individual flag
+       Embeds []PragmaEmbed
  }
  
  type PragmaPos struct {
        Pos  syntax.Pos
  }
  
+ type PragmaEmbed struct {
+       Pos      syntax.Pos
+       Patterns []string
+ }
  func (p *noder) checkUnused(pragma *Pragma) {
        for _, pos := range pragma.Pos {
                if pos.Flag&pragma.Flag != 0 {
                        p.yyerrorpos(pos.Pos, "misplaced compiler directive")
                }
        }
+       if len(pragma.Embeds) > 0 {
+               for _, e := range pragma.Embeds {
+                       p.yyerrorpos(e.Pos, "misplaced go:embed directive")
+               }
+       }
  }
  
  func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
                        p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"})
                }
        }
+       if len(pragma.Embeds) > 0 {
+               for _, e := range pragma.Embeds {
+                       p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"})
+               }
+       }
  }
  
  // pragma is called concurrently if files are parsed concurrently.
@@@ -1627,6 -1610,17 +1672,17 @@@ func (p *noder) pragma(pos syntax.Pos, 
                }
                p.linknames = append(p.linknames, linkname{pos, f[1], target})
  
+       case text == "go:embed", strings.HasPrefix(text, "go:embed "):
+               args, err := parseGoEmbed(text[len("go:embed"):])
+               if err != nil {
+                       p.error(syntax.Error{Pos: pos, Msg: err.Error()})
+               }
+               if len(args) == 0 {
+                       p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."})
+                       break
+               }
+               pragma.Embeds = append(pragma.Embeds, PragmaEmbed{pos, args})
        case strings.HasPrefix(text, "go:cgo_import_dynamic "):
                // This is permitted for general use because Solaris
                // code relies on it in golang.org/x/sys/unix and others.
@@@ -1699,3 -1693,64 +1755,64 @@@ func mkname(sym *types.Sym) *Node 
        }
        return n
  }
+ // parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
+ // It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
+ // go/build/read.go also processes these strings and contains similar logic.
+ func parseGoEmbed(args string) ([]string, error) {
+       var list []string
+       for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
+               var path string
+       Switch:
+               switch args[0] {
+               default:
+                       i := len(args)
+                       for j, c := range args {
+                               if unicode.IsSpace(c) {
+                                       i = j
+                                       break
+                               }
+                       }
+                       path = args[:i]
+                       args = args[i:]
+               case '`':
+                       i := strings.Index(args[1:], "`")
+                       if i < 0 {
+                               return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+                       }
+                       path = args[1 : 1+i]
+                       args = args[1+i+1:]
+               case '"':
+                       i := 1
+                       for ; i < len(args); i++ {
+                               if args[i] == '\\' {
+                                       i++
+                                       continue
+                               }
+                               if args[i] == '"' {
+                                       q, err := strconv.Unquote(args[:i+1])
+                                       if err != nil {
+                                               return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
+                                       }
+                                       path = q
+                                       args = args[i+1:]
+                                       break Switch
+                               }
+                       }
+                       if i >= len(args) {
+                               return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+                       }
+               }
+               if args != "" {
+                       r, _ := utf8.DecodeRuneInString(args)
+                       if !unicode.IsSpace(r) {
+                               return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+                       }
+               }
+               list = append(list, path)
+       }
+       return list, nil
+ }