Commit b4e9f704 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: remove support for textual export format

Fixes #15323.

Change-Id: I50e996e6fde6b24327cb45dd84da31deef4dcc56
Reviewed-on: https://go-review.googlesource.com/27171
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent e492d9f0
......@@ -174,8 +174,8 @@ const exportInlined = true // default: true
// errors.
// If disabled, only named types are tracked, possibly leading to slightly
// less efficient encoding in rare cases. It also prevents the export of
// some corner-case type declarations (but those are not handled correctly
// with with the textual export format either).
// some corner-case type declarations (but those were not handled correctly
// with the former textual export format either).
// TODO(gri) enable and remove once issues caused by it are fixed
const trackAllTypes = false
......
......@@ -80,7 +80,6 @@ func Import(in *bufio.Reader) {
p.pkg()
// defer some type-checking until all types are read in completely
// (parser.go:import_package)
tcok := typecheckok
typecheckok = true
defercheckwidth()
......
......@@ -9,14 +9,12 @@ import (
"bytes"
"cmd/internal/bio"
"fmt"
"sort"
"unicode"
"unicode/utf8"
)
var (
newexport bool // if set, use new export format
Debug_export int // if set, print debugging information about export data
Debug_export int // if set, print debugging information about export data
exportsize int
)
......@@ -94,18 +92,6 @@ func autoexport(n *Node, ctxt Class) {
}
}
func dumppkg(p *Pkg) {
if p == nil || p == localpkg || p.Exported || p == builtinpkg {
return
}
p.Exported = true
suffix := ""
if !p.Direct {
suffix = " // indirect"
}
exportf("\timport %s %q%s\n", p.Name, p.Path, suffix)
}
// Look for anything we need for the inline body
func reexportdeplist(ll Nodes) {
for _, n := range ll.Slice() {
......@@ -224,53 +210,6 @@ func reexportdep(n *Node) {
reexportdeplist(n.Nbody)
}
func dumpexportconst(s *Sym) {
n := typecheck(s.Def, Erv)
if n == nil || n.Op != OLITERAL {
Fatalf("dumpexportconst: oconst nil: %v", s)
}
t := n.Type // may or may not be specified
dumpexporttype(t)
if t != nil && !t.IsUntyped() {
exportf("\tconst %v %v = %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp), vconv(n.Val(), FmtSharp))
} else {
exportf("\tconst %v = %v\n", sconv(s, FmtSharp), vconv(n.Val(), FmtSharp))
}
}
func dumpexportvar(s *Sym) {
n := s.Def
n = typecheck(n, Erv|Ecall)
if n == nil || n.Type == nil {
Yyerror("variable exported but not defined: %v", s)
return
}
t := n.Type
dumpexporttype(t)
if t.Etype == TFUNC && n.Class == PFUNC {
if n.Func != nil && n.Func.Inl.Len() != 0 {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
typecheckinl(n)
}
// NOTE: The space after %#S here is necessary for ld's export data parser.
exportf("\tfunc %v %v { %v }\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp), hconv(n.Func.Inl, FmtSharp|FmtBody))
reexportdeplist(n.Func.Inl)
} else {
exportf("\tfunc %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp))
}
} else {
exportf("\tvar %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp))
}
}
// methodbyname sorts types by symbol name.
type methodbyname []*Field
......@@ -278,167 +217,44 @@ func (x methodbyname) Len() int { return len(x) }
func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name }
func dumpexporttype(t *Type) {
if t == nil {
return
}
if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
return
}
t.Printed = true
if t.Sym != nil {
dumppkg(t.Sym.Pkg)
}
switch t.Etype {
case TSTRUCT, TINTER:
for _, f := range t.Fields().Slice() {
dumpexporttype(f.Type)
}
case TFUNC:
dumpexporttype(t.Recvs())
dumpexporttype(t.Results())
dumpexporttype(t.Params())
case TMAP:
dumpexporttype(t.Val())
dumpexporttype(t.Key())
case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
dumpexporttype(t.Elem())
}
if t.Sym == nil {
return
}
var m []*Field
for _, f := range t.Methods().Slice() {
dumpexporttype(f.Type)
m = append(m, f)
}
sort.Sort(methodbyname(m))
exportf("\ttype %v %v\n", sconv(t.Sym, FmtSharp), Tconv(t, FmtSharp|FmtLong))
for _, f := range m {
if f.Nointerface {
exportf("\t//go:nointerface\n")
}
if f.Type.Nname() != nil && f.Type.Nname().Func.Inl.Len() != 0 { // nname was set by caninl
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
typecheckinl(f.Type.Nname())
}
exportf("\tfunc %v %v %v { %v }\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp), hconv(f.Type.Nname().Func.Inl, FmtSharp|FmtBody))
reexportdeplist(f.Type.Nname().Func.Inl)
} else {
exportf("\tfunc %v %v %v\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp))
}
}
}
func dumpsym(s *Sym) {
if s.Flags&SymExported != 0 {
return
}
s.Flags |= SymExported
if s.Def == nil {
Yyerror("unknown export symbol: %v", s)
return
}
// print("dumpsym %O %+S\n", s->def->op, s);
dumppkg(s.Pkg)
switch s.Def.Op {
default:
Yyerror("unexpected export symbol: %v %v", s.Def.Op, s)
case OLITERAL:
dumpexportconst(s)
case OTYPE:
if s.Def.Type.Etype == TFORW {
Yyerror("export of incomplete type %v", s)
} else {
dumpexporttype(s.Def.Type)
}
case ONAME:
dumpexportvar(s)
}
}
func dumpexport() {
if buildid != "" {
exportf("build id %q\n", buildid)
}
size := 0 // size of export section without enclosing markers
if newexport {
// binary export
// The linker also looks for the $$ marker - use char after $$ to distinguish format.
exportf("\n$$B\n") // indicate binary format
if debugFormat {
// save a copy of the export data
var copy bytes.Buffer
bcopy := bufio.NewWriter(&copy)
size = export(bcopy, Debug_export != 0)
bcopy.Flush() // flushing to bytes.Buffer cannot fail
if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
}
// export data must contain no '$' so that we can find the end by searching for "$$"
if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
Fatalf("export data contains $")
}
// verify that we can read the copied export data back in
// (use empty package map to avoid collisions)
savedPkgMap := pkgMap
savedPkgs := pkgs
pkgMap = make(map[string]*Pkg)
pkgs = nil
importpkg = mkpkg("")
Import(bufio.NewReader(&copy)) // must not die
importpkg = nil
pkgs = savedPkgs
pkgMap = savedPkgMap
} else {
size = export(bout.Writer, Debug_export != 0)
// The linker also looks for the $$ marker - use char after $$ to distinguish format.
exportf("\n$$B\n") // indicate binary export format
if debugFormat {
// save a copy of the export data
var copy bytes.Buffer
bcopy := bufio.NewWriter(&copy)
size = export(bcopy, Debug_export != 0)
bcopy.Flush() // flushing to bytes.Buffer cannot fail
if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
}
exportf("\n$$\n")
} else {
// textual export
lno := lineno
exportf("\n$$\n") // indicate textual format
exportsize = 0
exportf("package %s", localpkg.Name)
if safemode {
exportf(" safe")
// export data must contain no '$' so that we can find the end by searching for "$$"
// TODO(gri) is this still needed?
if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
Fatalf("export data contains $")
}
exportf("\n")
for _, p := range pkgs {
if p.Direct {
dumppkg(p)
}
}
// exportlist grows during iteration - cannot use range
for i := 0; i < len(exportlist); i++ {
n := exportlist[i]
lineno = n.Lineno
dumpsym(n.Sym)
}
size = exportsize
exportf("\n$$\n")
lineno = lno
// verify that we can read the copied export data back in
// (use empty package map to avoid collisions)
savedPkgMap := pkgMap
savedPkgs := pkgs
pkgMap = make(map[string]*Pkg)
pkgs = nil
importpkg = mkpkg("")
Import(bufio.NewReader(&copy)) // must not die
importpkg = nil
pkgs = savedPkgs
pkgMap = savedPkgMap
} else {
size = export(bout.Writer, Debug_export != 0)
}
exportf("\n$$\n")
if Debug_export != 0 {
fmt.Printf("export data size = %d bytes\n", size)
......
......@@ -73,7 +73,7 @@ const (
const (
FErr = iota
FDbg
FExp
_ // formerly FExp - leave gap for now just in case there's some hard-wired dependency on the const value
FTypeId
)
......@@ -113,7 +113,8 @@ func setfmode(flags *FmtFlag) (fm int, fb bool) {
if *flags&FmtSign != 0 {
fmtmode = FDbg
} else if *flags&FmtSharp != 0 {
fmtmode = FExp
// for textual export format - no longer supported
Fatalf("textual export format request")
} else if *flags&FmtLeft != 0 {
fmtmode = FTypeId
}
......@@ -340,7 +341,7 @@ func vconv(v Val, flag FmtFlag) string {
switch u := v.U.(type) {
case *Mpint:
if !u.Rune {
if (flag&FmtSharp != 0) || fmtmode == FExp {
if flag&FmtSharp != 0 {
return bconv(u, FmtSharp)
}
return bconv(u, 0)
......@@ -359,13 +360,13 @@ func vconv(v Val, flag FmtFlag) string {
return fmt.Sprintf("('\\x00' + %v)", u)
case *Mpflt:
if (flag&FmtSharp != 0) || fmtmode == FExp {
if flag&FmtSharp != 0 {
return fconv(u, 0)
}
return fconv(u, FmtSharp)
case *Mpcplx:
if (flag&FmtSharp != 0) || fmtmode == FExp {
if flag&FmtSharp != 0 {
return fmt.Sprintf("(%v+%vi)", &u.Real, &u.Imag)
}
if v.U.(*Mpcplx).Real.CmpFloat64(0) == 0 {
......@@ -474,14 +475,6 @@ func symfmt(s *Sym, flag FmtFlag) string {
return s.Pkg.Name + "." + s.Name // dcommontype, typehash
}
return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
case FExp:
if s.Name != "" && s.Name[0] == '.' {
Fatalf("exporting synthetic symbol %s", s.Name)
}
if s.Pkg != builtinpkg {
return fmt.Sprintf("@%q.%s", s.Pkg.Path, s.Name)
}
}
}
......@@ -493,8 +486,7 @@ func symfmt(s *Sym, flag FmtFlag) string {
p = s.Name[i+1:]
}
// exportname needs to see the name without the prefix too.
if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg {
if fmtmode == FDbg {
return fmt.Sprintf("@%q.%s", s.Pkg.Path, p)
}
......@@ -559,9 +551,7 @@ func typefmt(t *Type, flag FmtFlag) string {
if flag&FmtUnsigned != 0 {
return sconv(t.Sym, FmtUnsigned)
}
fallthrough
case FExp:
if t.Sym.Pkg == localpkg && t.Vargen != 0 {
return fmt.Sprintf("%v·%d", t.Sym, t.Vargen)
}
......@@ -660,15 +650,11 @@ func typefmt(t *Type, flag FmtFlag) string {
switch t.Results().NumFields() {
case 0:
break
// nothing to do
case 1:
if fmtmode != FExp {
buf.WriteString(" ")
buf.WriteString(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
break
}
fallthrough
buf.WriteString(" ")
buf.WriteString(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
default:
buf.WriteString(" ")
......@@ -733,25 +719,15 @@ func typefmt(t *Type, flag FmtFlag) string {
return "undefined"
case TUNSAFEPTR:
if fmtmode == FExp {
return "@\"unsafe\".Pointer"
}
return "unsafe.Pointer"
case TDDDFIELD:
if fmtmode == FExp {
Fatalf("cannot use TDDDFIELD with old exporter")
}
return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
case Txxx:
return "Txxx"
}
if fmtmode == FExp {
Fatalf("missing %v case during export", t.Etype)
}
// Don't know how to handle - fall back to detailed prints.
return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
}
......@@ -793,14 +769,6 @@ func stmtfmt(n *Node) string {
switch n.Op {
case ODCL:
if fmtmode == FExp {
switch n.Left.Class {
case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
goto ret
}
}
f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type)
case ODCLFIELD:
......@@ -814,10 +782,6 @@ func stmtfmt(n *Node) string {
// preceded by the DCL which will be re-parsed and typechecked to reproduce
// the "v = <N>" again.
case OAS, OASWB:
if fmtmode == FExp && n.Right == nil {
break
}
if n.Colas && !complexinit {
f += fmt.Sprintf("%v := %v", n.Left, n.Right)
} else {
......@@ -947,7 +911,6 @@ func stmtfmt(n *Node) string {
f += fmt.Sprintf("%v: ", n.Left)
}
ret:
if extrablock {
f += "}"
}
......@@ -1124,23 +1087,9 @@ func exprfmt(n *Node, prec int) string {
// Special case: name used as local variable in export.
// _ becomes ~b%d internally; print as _ for export
case ONAME:
if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
if fmtmode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
return "_"
}
if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen)
}
// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
// but for export, this should be rendered as (*pkg.T).meth.
// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
if n.Left.Type.IsPtr() {
return fmt.Sprintf("(%v).%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
} else {
return fmt.Sprintf("%v.%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
}
}
fallthrough
case OPACK, ONONAME:
......@@ -1209,63 +1158,20 @@ func exprfmt(n *Node, prec int) string {
return "composite literal"
}
if fmtmode == FExp && ptrlit {
// typecheck has overwritten OIND by OTYPE with pointer type.
return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Elem(), hconv(n.List, FmtComma))
}
return fmt.Sprintf("(%v{ %v })", n.Right, hconv(n.List, FmtComma))
case OPTRLIT:
if fmtmode == FExp && n.Left.Implicit {
return Nconv(n.Left, 0)
}
return fmt.Sprintf("&%v", n.Left)
case OSTRUCTLIT:
if fmtmode == FExp { // requires special handling of field names
var f string
if n.Implicit {
f += "{"
} else {
f += fmt.Sprintf("(%v{", n.Type)
}
for i1, n1 := range n.List.Slice() {
f += fmt.Sprintf(" %v:%v", sconv(n1.Left.Sym, FmtShort|FmtByte), n1.Right)
if i1+1 < n.List.Len() {
f += ","
} else {
f += " "
}
}
if !n.Implicit {
f += "})"
return f
}
f += "}"
return f
}
fallthrough
case OARRAYLIT, OMAPLIT:
case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
if fmtmode == FErr {
return fmt.Sprintf("%v literal", n.Type)
}
if fmtmode == FExp && n.Implicit {
return fmt.Sprintf("{ %v }", hconv(n.List, FmtComma))
}
return fmt.Sprintf("(%v{ %v })", n.Type, hconv(n.List, FmtComma))
case OKEY:
if n.Left != nil && n.Right != nil {
if fmtmode == FExp && n.Left.Type == structkey {
// requires special handling of field names
return fmt.Sprintf("%v:%v", sconv(n.Left.Sym, FmtShort|FmtByte), n.Right)
} else {
return fmt.Sprintf("%v:%v", n.Left, n.Right)
}
return fmt.Sprintf("%v:%v", n.Left, n.Right)
}
if n.Left == nil && n.Right != nil {
......@@ -1473,7 +1379,7 @@ func nodefmt(n *Node, flag FmtFlag) string {
// we almost always want the original, except in export mode for literals
// this saves the importer some work, and avoids us having to redo some
// special casing for package unsafe
if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
if n.Op != OLITERAL && n.Orig != nil {
n = n.Orig
}
......@@ -1643,7 +1549,7 @@ func Fldconv(f *Field, flag FmtFlag) string {
// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
// ~r%d is a (formerly) unnamed result.
if (fmtmode == FErr || fmtmode == FExp) && f.Nname != nil {
if fmtmode == FErr && f.Nname != nil {
if f.Nname.Orig != nil {
s = f.Nname.Orig.Sym
if s != nil && s.Name[0] == '~' {
......@@ -1666,12 +1572,6 @@ func Fldconv(f *Field, flag FmtFlag) string {
} else {
name = sconv(s, 0)
}
} else if fmtmode == FExp {
if f.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
name = fmt.Sprintf("@%q.?", s.Pkg.Path)
} else {
name = "?"
}
}
}
......@@ -1759,7 +1659,7 @@ func Nconv(n *Node, flag FmtFlag) string {
var str string
switch fmtmode {
case FErr, FExp:
case FErr:
str = nodefmt(n, flag)
case FDbg:
......
......@@ -469,12 +469,6 @@ l0:
l.nlsemi = true
goto lx
case '#', '$', '?', '@', '\\':
if importpkg != nil {
goto lx
}
fallthrough
default:
// anything else is illegal
Yyerror("syntax error: illegal character %#U", c)
......@@ -536,7 +530,7 @@ func (l *lexer) ident(c rune) {
// general case
for {
if c >= utf8.RuneSelf {
if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) {
if cp.Len() == 0 && unicode.IsDigit(c) {
Yyerror("identifier cannot begin with digit %#U", c)
}
......@@ -672,18 +666,10 @@ func (l *lexer) number(c rune) {
cp.WriteByte(byte(c))
c = l.getr()
}
// Falling through to exponent parsing here permits invalid
// floating-point numbers with fractional mantissa and base-2
// (p or P) exponent. We don't care because base-2 exponents
// can only show up in machine-generated textual export data
// which will use correct formatting.
}
// exponent
// base-2 exponent (p or P) is only allowed in export data (see #9036)
// TODO(gri) Once we switch to binary import data, importpkg will
// always be nil in this function. Simplify the code accordingly.
if c == 'e' || c == 'E' || importpkg != nil && (c == 'p' || c == 'P') {
if c == 'e' || c == 'E' {
isInt = false
cp.WriteByte(byte(c))
c = l.getr()
......@@ -1124,9 +1110,7 @@ redo:
case 0:
yyerrorl(lexlineno, "illegal NUL byte")
case '\n':
if importpkg == nil {
lexlineno++
}
lexlineno++
case utf8.RuneError:
if w == 1 {
yyerrorl(lexlineno, "illegal UTF-8 sequence")
......
......@@ -182,7 +182,6 @@ func Main() {
obj.Flagcount("live", "debug liveness analysis", &debuglive)
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
flag.BoolVar(&newexport, "newexport", true, "use new export format") // TODO(gri) remove eventually (issue 15323)
flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
flag.StringVar(&outfile, "o", "", "write output to `file`")
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
......@@ -644,24 +643,10 @@ func loadsys() {
iota_ = -1000000
incannedimport = 1
// The first byte in the binary export format is a 'c' or 'd'
// specifying the encoding format. We could just check that
// byte, but this is a perhaps more robust. Also, it is not
// speed-critical.
// TODO(gri) simplify once textual export format has gone
if strings.HasPrefix(runtimeimport, "package") {
// textual export format
importpkg = Runtimepkg
parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
importpkg = unsafepkg
parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
} else {
// binary export format
importpkg = Runtimepkg
Import(bufio.NewReader(strings.NewReader(runtimeimport)))
importpkg = unsafepkg
Import(bufio.NewReader(strings.NewReader(unsafeimport)))
}
importpkg = Runtimepkg
Import(bufio.NewReader(strings.NewReader(runtimeimport)))
importpkg = unsafepkg
Import(bufio.NewReader(strings.NewReader(unsafeimport)))
importpkg = nil
incannedimport = 0
......@@ -804,8 +789,8 @@ func importfile(f *Val, indent []byte) {
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
// In the importfile, if we find:
// $$\n (old format): position the input right after $$\n and return
// $$B\n (new format): import directly, then feed the lexer a dummy statement
// $$\n (textual format): not supported anymore
// $$B\n (binary format) : import directly, then feed the lexer a dummy statement
// look for $$
var c byte
......@@ -829,11 +814,9 @@ func importfile(f *Val, indent []byte) {
switch c {
case '\n':
// old export format
parse_import(imp, indent)
Yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
case 'B':
// new export format
if Debug_export != 0 {
fmt.Printf("importing %s (%s)\n", path_, file)
}
......
......@@ -66,16 +66,9 @@ func mkbuiltin(w io.Writer, name string) {
}
// Look for $$B that introduces binary export data.
textual := false // TODO(gri) remove once we switched to binary export format
i := bytes.Index(b, []byte("\n$$B\n"))
if i < 0 {
// Look for $$ that introduces textual export data.
i = bytes.Index(b, []byte("\n$$\n"))
if i < 0 {
log.Fatal("did not find beginning of export data")
}
textual = true
i-- // textual data doesn't have B
log.Fatal("did not find beginning of export data")
}
b = b[i+5:]
......@@ -87,27 +80,15 @@ func mkbuiltin(w io.Writer, name string) {
b = b[:i+4]
// Process and reformat export data.
const n = 40 // number of bytes per line
fmt.Fprintf(w, "\nconst %simport = \"\"", name)
if textual {
for _, p := range bytes.SplitAfter(b, []byte("\n")) {
// Chop leading white space.
p = bytes.TrimLeft(p, " \t")
if len(p) == 0 {
continue
}
fmt.Fprintf(w, " +\n\t%q", p)
}
} else {
const n = 40 // number of bytes per line
for len(b) > 0 {
i := len(b)
if i > n {
i = n
}
fmt.Fprintf(w, " +\n\t%q", b[:i])
b = b[i:]
for len(b) > 0 {
i := len(b)
if i > n {
i = n
}
fmt.Fprintf(w, " +\n\t%q", b[:i])
b = b[i:]
}
fmt.Fprintf(w, "\n")
}
This diff is collapsed.
This diff is collapsed.
......@@ -46,20 +46,6 @@ func compile(t *testing.T, dirname, filename string) string {
return filepath.Join(dirname, filename[:len(filename)-2]+"o")
}
// TODO(gri) Remove this function once we switched to new export format by default.
func compileNewExport(t *testing.T, dirname, filename string) string {
testenv.MustHaveGoBuild(t)
cmd := exec.Command("go", "tool", "compile", "-newexport", filename)
cmd.Dir = dirname
out, err := cmd.CombinedOutput()
if err != nil {
t.Logf("%s", out)
t.Fatalf("go tool compile %s failed: %s", filename, err)
}
// filename should end with ".go"
return filepath.Join(dirname, filename[:len(filename)-2]+"o")
}
func testPath(t *testing.T, path, srcDir string) *types.Package {
t0 := time.Now()
pkg, err := Import(make(map[string]*types.Package), path, srcDir)
......@@ -121,6 +107,8 @@ func TestImportTestdata(t *testing.T) {
// additional packages that are not strictly required for
// import processing alone (they are exported to err "on
// the safe side").
// TODO(gri) update the want list to be precise, now that
// the textual export data is gone.
got := fmt.Sprint(pkg.Imports())
for _, want := range []string{"go/ast", "go/token"} {
if !strings.Contains(got, want) {
......@@ -130,31 +118,6 @@ func TestImportTestdata(t *testing.T) {
}
}
// TODO(gri) Remove this function once we switched to new export format by default
// (and update the comment and want list in TestImportTestdata).
func TestImportTestdataNewExport(t *testing.T) {
// This package only handles gc export data.
if runtime.Compiler != "gc" {
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
return
}
if outFn := compileNewExport(t, "testdata", "exports.go"); outFn != "" {
defer os.Remove(outFn)
}
if pkg := testPath(t, "./testdata/exports", "."); pkg != nil {
// The package's Imports list must include all packages
// explicitly imported by exports.go, plus all packages
// referenced indirectly via exported objects in exports.go.
want := `[package ast ("go/ast") package token ("go/token")]`
got := fmt.Sprint(pkg.Imports())
if got != want {
t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
}
}
}
func TestImportStdLib(t *testing.T) {
skipSpecialPlatforms(t)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment