2015-08-13 19:05:37 -07:00
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Binary package import.
2016-05-25 11:23:56 -07:00
// See bexport.go for the export data format and how
// to make a format change.
2015-08-13 19:05:37 -07:00
package gc
import (
2016-03-11 13:39:20 -05:00
"bufio"
2015-08-13 19:05:37 -07:00
"cmd/compile/internal/big"
"encoding/binary"
2015-10-22 18:56:45 -07:00
"fmt"
2016-08-25 16:53:10 -07:00
"strconv"
"strings"
2015-08-13 19:05:37 -07:00
)
// The overall structure of Import is symmetric to Export: For each
// export method in bexport.go there is a matching and symmetric method
// in bimport.go. Changing the export format requires making symmetric
// changes to bimport.go and bexport.go.
2016-03-18 17:21:32 -07:00
type importer struct {
2016-08-25 16:53:10 -07:00
in * bufio . Reader
buf [ ] byte // reused for reading strings
version int // export format version
2016-04-12 18:00:04 -07:00
2016-04-13 17:53:03 -07:00
// object lists, in order of deserialization
2016-05-05 18:03:59 -07:00
strList [ ] string
pkgList [ ] * Pkg
typList [ ] * Type
funcList [ ] * Node // nil entry means already declared
trackAllTypes bool
2016-04-13 17:53:03 -07:00
2016-05-05 09:39:50 -07:00
// for delayed type verification
cmpList [ ] struct { pt , t * Type }
2016-04-13 17:53:03 -07:00
// position encoding
2016-04-22 14:50:20 -07:00
posInfoFormat bool
prevFile string
prevLine int
2016-03-18 17:21:32 -07:00
// debugging support
debugFormat bool
read int // bytes read
}
2015-08-13 19:05:37 -07:00
// Import populates importpkg from the serialized package data.
2016-03-11 13:39:20 -05:00
func Import ( in * bufio . Reader ) {
2016-04-13 17:53:03 -07:00
p := importer {
in : in ,
2016-08-25 16:53:10 -07:00
version : - 1 , // unknown version
2016-04-13 17:53:03 -07:00
strList : [ ] string { "" } , // empty string is mapped to 0
}
2015-08-13 19:05:37 -07:00
2016-08-19 18:10:00 -07:00
// read version info
2016-08-25 16:53:10 -07:00
var versionstr string
2016-08-19 18:10:00 -07:00
if b := p . rawByte ( ) ; b == 'c' || b == 'd' {
// Go1.7 encoding; first byte encodes low-level
// encoding format (compact vs debug).
// For backward-compatibility only (avoid problems with
// old installed packages). Newly compiled packages use
// the extensible format string.
// TODO(gri) Remove this support eventually; after Go1.8.
if b == 'd' {
p . debugFormat = true
}
p . trackAllTypes = p . rawByte ( ) == 'a'
p . posInfoFormat = p . bool ( )
2016-08-25 16:53:10 -07:00
versionstr = p . string ( )
if versionstr == "v1" {
p . version = 0
2016-08-19 18:10:00 -07:00
}
} else {
// Go1.8 extensible encoding
2016-08-25 16:53:10 -07:00
// read version string and extract version number (ignore anything after the version number)
versionstr = p . rawStringln ( b )
if s := strings . SplitN ( versionstr , " " , 3 ) ; len ( s ) >= 2 && s [ 0 ] == "version" {
if v , err := strconv . Atoi ( s [ 1 ] ) ; err == nil && v > 0 {
p . version = v
}
2016-08-19 18:10:00 -07:00
}
2016-08-25 16:53:10 -07:00
}
// read version specific flags - extend as necessary
switch p . version {
// case 2:
// ...
// fallthrough
case 1 :
2016-08-19 18:10:00 -07:00
p . debugFormat = p . rawStringln ( p . rawByte ( ) ) == "debug"
p . trackAllTypes = p . bool ( )
p . posInfoFormat = p . bool ( )
2016-08-25 16:53:10 -07:00
case 0 :
// Go1.7 encoding format - nothing to do here
default :
formatErrorf ( "unknown export format version %d (%q)" , p . version , versionstr )
2015-08-13 19:05:37 -07:00
}
// --- generic export data ---
// populate typList with predeclared "known" types
p . typList = append ( p . typList , predeclared ( ) ... )
// read package data
p . pkg ( )
// defer some type-checking until all types are read in completely
tcok := typecheckok
typecheckok = true
defercheckwidth ( )
2016-03-18 17:21:32 -07:00
// read objects
2015-08-13 19:05:37 -07:00
2016-04-12 11:31:16 -07:00
// phase 1
2016-03-18 17:21:32 -07:00
objcount := 0
for {
tag := p . tagOrIndex ( )
if tag == endTag {
break
}
p . obj ( tag )
objcount ++
2015-08-13 19:05:37 -07:00
}
2016-03-18 17:21:32 -07:00
// self-verification
if count := p . int ( ) ; count != objcount {
2016-08-25 16:53:10 -07:00
formatErrorf ( "got %d objects; want %d" , objcount , count )
2016-03-18 17:21:32 -07:00
}
2015-08-13 19:05:37 -07:00
2016-03-18 17:21:32 -07:00
// --- compiler-specific export data ---
2015-08-13 19:05:37 -07:00
2016-04-12 11:31:16 -07:00
// read compiler-specific flags
2016-05-20 11:19:19 -07:00
2016-04-12 11:31:16 -07:00
// phase 2
2016-03-18 17:21:32 -07:00
objcount = 0
for {
tag := p . tagOrIndex ( )
if tag == endTag {
break
2015-10-22 18:56:45 -07:00
}
2016-03-18 17:21:32 -07:00
p . obj ( tag )
objcount ++
2015-08-13 19:05:37 -07:00
}
2016-03-18 17:21:32 -07:00
// self-verification
if count := p . int ( ) ; count != objcount {
2016-08-25 16:53:10 -07:00
formatErrorf ( "got %d objects; want %d" , objcount , count )
2015-08-13 19:05:37 -07:00
}
2016-04-12 18:00:04 -07:00
// read inlineable functions bodies
2016-03-18 17:21:32 -07:00
if dclcontext != PEXTERN {
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected context %d" , dclcontext )
2016-03-18 17:21:32 -07:00
}
2016-04-12 18:00:04 -07:00
objcount = 0
for i0 := - 1 ; ; {
i := p . int ( ) // index of function with inlineable body
if i < 0 {
break
}
// don't process the same function twice
if i <= i0 {
2016-08-25 16:53:10 -07:00
formatErrorf ( "index not increasing: %d <= %d" , i , i0 )
2016-04-12 18:00:04 -07:00
}
i0 = i
2016-03-18 17:21:32 -07:00
if Funcdepth != 0 {
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected Funcdepth %d" , Funcdepth )
2015-10-22 18:56:45 -07:00
}
2016-04-12 18:00:04 -07:00
// Note: In the original code, funchdr and funcbody are called for
// all functions (that were not yet imported). Now, we are calling
// them only for functions with inlineable bodies. funchdr does
// parameter renaming which doesn't matter if we don't have a body.
if f := p . funcList [ i ] ; f != nil {
// function not yet imported - read body and set it
2016-03-18 17:21:32 -07:00
funchdr ( f )
2016-04-26 14:11:38 -07:00
body := p . stmtList ( )
if body == nil {
// Make sure empty body is not interpreted as
// no inlineable body (see also parser.fnbody)
// (not doing so can cause significant performance
// degradation due to unnecessary calls to empty
// functions).
body = [ ] * Node { Nod ( OEMPTY , nil , nil ) }
}
f . Func . Inl . Set ( body )
2016-03-18 17:21:32 -07:00
funcbody ( f )
} else {
// function already imported - read body but discard declarations
dclcontext = PDISCARD // throw away any declarations
p . stmtList ( )
dclcontext = PEXTERN
}
2016-04-12 18:00:04 -07:00
objcount ++
}
// self-verification
if count := p . int ( ) ; count != objcount {
2016-08-25 16:53:10 -07:00
formatErrorf ( "got %d functions; want %d" , objcount , count )
2016-03-18 17:21:32 -07:00
}
if dclcontext != PEXTERN {
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected context %d" , dclcontext )
2015-08-13 19:05:37 -07:00
}
2016-05-05 09:39:50 -07:00
p . verifyTypes ( )
2015-08-13 19:05:37 -07:00
// --- end of export data ---
typecheckok = tcok
resumecheckwidth ( )
testdclstack ( ) // debugging only
}
2016-08-25 16:53:10 -07:00
func formatErrorf ( format string , args ... interface { } ) {
if debugFormat {
Fatalf ( format , args ... )
}
Yyerror ( "cannot import %q due to version skew - reinstall package (%s)" ,
importpkg . Path , fmt . Sprintf ( format , args ... ) )
errorexit ( )
}
2016-05-05 09:39:50 -07:00
func ( p * importer ) verifyTypes ( ) {
for _ , pair := range p . cmpList {
pt := pair . pt
t := pair . t
if ! Eqtype ( pt . Orig , t ) {
2016-08-25 16:53:10 -07:00
formatErrorf ( "inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)" , pt . Sym , Tconv ( pt , FmtLong ) , pt . Sym . Importdef . Path , Tconv ( t , FmtLong ) , importpkg . Path )
2016-05-05 09:39:50 -07:00
}
}
}
2016-08-24 13:12:34 -07:00
// numImport tracks how often a package with a given name is imported.
// It is used to provide a better error message (by using the package
// path to disambiguate) if a package that appears multiple times with
// the same name appears in an error message.
var numImport = make ( map [ string ] int )
2015-08-13 19:05:37 -07:00
func ( p * importer ) pkg ( ) * Pkg {
// if the package was seen before, i is its index (>= 0)
i := p . tagOrIndex ( )
if i >= 0 {
return p . pkgList [ i ]
}
// otherwise, i is the package tag (< 0)
if i != packageTag {
2016-08-25 16:53:10 -07:00
formatErrorf ( "expected package tag, found tag = %d" , i )
2015-08-13 19:05:37 -07:00
}
// read package data
name := p . string ( )
path := p . string ( )
// we should never see an empty package name
if name == "" {
2016-08-25 16:53:10 -07:00
formatErrorf ( "empty package name for path %q" , path )
2015-08-13 19:05:37 -07:00
}
// we should never see a bad import path
if isbadimport ( path ) {
2016-08-25 16:53:10 -07:00
formatErrorf ( "bad package path %q for package %s" , path , name )
2015-08-13 19:05:37 -07:00
}
2016-04-12 21:58:44 -07:00
// an empty path denotes the package we are currently importing;
// it must be the first package we see
if ( path == "" ) != ( len ( p . pkgList ) == 0 ) {
2016-08-25 16:53:10 -07:00
formatErrorf ( "package path %q for pkg index %d" , path , len ( p . pkgList ) )
2016-04-12 21:58:44 -07:00
}
2016-08-24 13:12:34 -07:00
// add package to pkgList
2015-08-13 19:05:37 -07:00
pkg := importpkg
if path != "" {
pkg = mkpkg ( path )
}
if pkg . Name == "" {
pkg . Name = name
2016-06-21 14:27:40 -07:00
numImport [ name ] ++
2015-08-13 19:05:37 -07:00
} else if pkg . Name != name {
2016-08-25 16:53:10 -07:00
Yyerror ( "conflicting package names %s and %s for path %q" , pkg . Name , name , path )
2016-06-21 14:27:40 -07:00
}
if incannedimport == 0 && myimportpath != "" && path == myimportpath {
Yyerror ( "import %q: package depends on %q (import cycle)" , importpkg . Path , path )
errorexit ( )
2015-08-13 19:05:37 -07:00
}
p . pkgList = append ( p . pkgList , pkg )
return pkg
}
2016-03-18 17:21:32 -07:00
func idealType ( typ * Type ) * Type {
if typ . IsUntyped ( ) {
// canonicalize ideal types
typ = Types [ TIDEAL ]
}
return typ
}
func ( p * importer ) obj ( tag int ) {
switch tag {
case constTag :
2016-04-13 17:53:03 -07:00
p . pos ( )
2016-03-18 17:21:32 -07:00
sym := p . qualifiedName ( )
typ := p . typ ( )
val := p . value ( typ )
importconst ( sym , idealType ( typ ) , nodlit ( val ) )
case typeTag :
p . typ ( )
case varTag :
2016-04-13 17:53:03 -07:00
p . pos ( )
2016-03-18 17:21:32 -07:00
sym := p . qualifiedName ( )
typ := p . typ ( )
importvar ( sym , typ )
case funcTag :
2016-04-13 17:53:03 -07:00
p . pos ( )
2016-03-18 17:21:32 -07:00
sym := p . qualifiedName ( )
params := p . paramList ( )
result := p . paramList ( )
sig := functype ( nil , params , result )
importsym ( sym , ONAME )
if sym . Def != nil && sym . Def . Op == ONAME {
2016-04-12 18:00:04 -07:00
// function was imported before (via another import)
if ! Eqtype ( sig , sym . Def . Type ) {
2016-08-25 16:53:10 -07:00
formatErrorf ( "inconsistent definition for func %v during import\n\t%v\n\t%v" , sym , sym . Def . Type , sig )
2016-03-18 17:21:32 -07:00
}
2016-04-12 18:00:04 -07:00
p . funcList = append ( p . funcList , nil )
2016-03-18 17:21:32 -07:00
break
}
2016-04-12 18:00:04 -07:00
n := newfuncname ( sym )
n . Type = sig
declare ( n , PFUNC )
p . funcList = append ( p . funcList , n )
importlist = append ( importlist , n )
2016-03-18 17:21:32 -07:00
if Debug [ 'E' ] > 0 {
fmt . Printf ( "import [%q] func %v \n" , importpkg . Path , n )
2016-04-24 13:50:26 -07:00
if Debug [ 'm' ] > 2 && n . Func . Inl . Len ( ) != 0 {
2016-03-18 17:21:32 -07:00
fmt . Printf ( "inl body: %v\n" , n . Func . Inl )
}
}
default :
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected object (tag = %d)" , tag )
2015-08-13 19:05:37 -07:00
}
}
2016-04-13 17:53:03 -07:00
func ( p * importer ) pos ( ) {
2016-04-22 14:50:20 -07:00
if ! p . posInfoFormat {
return
}
2016-04-13 17:53:03 -07:00
file := p . prevFile
line := p . prevLine
if delta := p . int ( ) ; delta != 0 {
2016-04-28 12:43:12 -07:00
// line changed
2016-04-13 17:53:03 -07:00
line += delta
2016-04-28 12:43:12 -07:00
} else if n := p . int ( ) ; n >= 0 {
// file changed
file = p . prevFile [ : n ] + p . string ( )
2016-04-13 17:53:03 -07:00
p . prevFile = file
2016-04-28 12:43:12 -07:00
line = p . int ( )
2016-04-13 17:53:03 -07:00
}
p . prevLine = line
// TODO(gri) register new position
}
2015-09-24 23:21:18 +02:00
func ( p * importer ) newtyp ( etype EType ) * Type {
2015-08-13 19:05:37 -07:00
t := typ ( etype )
2016-05-05 18:03:59 -07:00
if p . trackAllTypes {
p . typList = append ( p . typList , t )
}
2015-08-13 19:05:37 -07:00
return t
}
2016-05-05 09:39:50 -07:00
// This is like the function importtype but it delays the
// type identity check for types that have been seen already.
// importer.importtype and importtype and (export.go) need to
// remain in sync.
func ( p * importer ) importtype ( pt , t * Type ) {
// override declaration in unsafe.go for Pointer.
// there is no way in Go code to define unsafe.Pointer
// so we have to supply it.
if incannedimport != 0 && importpkg . Name == "unsafe" && pt . Nod . Sym . Name == "Pointer" {
t = Types [ TUNSAFEPTR ]
}
if pt . Etype == TFORW {
n := pt . Nod
copytype ( pt . Nod , t )
pt . Nod = n // unzero nod
pt . Sym . Importdef = importpkg
pt . Sym . Lastlineno = lineno
declare ( n , PEXTERN )
checkwidth ( pt )
} else {
// pt.Orig and t must be identical. Since t may not be
// fully set up yet, collect the types and verify identity
// later.
p . cmpList = append ( p . cmpList , struct { pt , t * Type } { pt , t } )
}
if Debug [ 'E' ] != 0 {
fmt . Printf ( "import type %v %v\n" , pt , Tconv ( t , FmtLong ) )
}
}
2015-08-13 19:05:37 -07:00
func ( p * importer ) typ ( ) * Type {
// if the type was seen before, i is its index (>= 0)
i := p . tagOrIndex ( )
if i >= 0 {
return p . typList [ i ]
}
// otherwise, i is the type tag (< 0)
var t * Type
switch i {
case namedTag :
2016-03-08 18:57:19 +00:00
// parser.go:hidden_importsym
2016-04-13 17:53:03 -07:00
p . pos ( )
2015-08-13 19:05:37 -07:00
tsym := p . qualifiedName ( )
2016-03-08 18:57:19 +00:00
// parser.go:hidden_pkgtype
2015-08-13 19:05:37 -07:00
t = pkgtype ( tsym )
p . typList = append ( p . typList , t )
// read underlying type
2016-03-08 18:57:19 +00:00
// parser.go:hidden_type
2015-08-13 19:05:37 -07:00
t0 := p . typ ( )
2016-05-05 18:03:59 -07:00
if p . trackAllTypes {
// If we track all types, we cannot check equality of previously
// imported types until later. Use customized version of importtype.
p . importtype ( t , t0 )
} else {
importtype ( t , t0 )
}
2015-08-13 19:05:37 -07:00
// interfaces don't have associated methods
2016-03-30 14:56:08 -07:00
if t0 . IsInterface ( ) {
2015-08-13 19:05:37 -07:00
break
}
2016-03-18 17:21:32 -07:00
// set correct import context (since p.typ() may be called
// while importing the body of an inlined function)
savedContext := dclcontext
dclcontext = PEXTERN
2015-08-13 19:05:37 -07:00
// read associated methods
for i := p . int ( ) ; i > 0 ; i -- {
2016-03-08 18:57:19 +00:00
// parser.go:hidden_fndcl
2016-03-18 17:21:32 -07:00
2016-04-13 17:53:03 -07:00
p . pos ( )
2016-03-18 17:21:32 -07:00
sym := p . fieldSym ( )
2015-08-13 19:05:37 -07:00
recv := p . paramList ( ) // TODO(gri) do we need a full param list for the receiver?
params := p . paramList ( )
result := p . paramList ( )
2016-08-16 17:32:54 -07:00
nointerface := p . bool ( )
2016-07-01 10:51:59 -07:00
2016-08-25 16:40:50 +10:00
n := methodname ( newname ( sym ) , recv [ 0 ] . Right )
2016-03-08 10:26:20 -08:00
n . Type = functype ( recv [ 0 ] , params , result )
2015-08-13 19:05:37 -07:00
checkwidth ( n . Type )
2016-07-01 10:51:59 -07:00
addmethod ( sym , n . Type , tsym . Pkg , false , nointerface )
2016-04-12 18:00:04 -07:00
p . funcList = append ( p . funcList , n )
importlist = append ( importlist , n )
2015-08-13 19:05:37 -07:00
2016-03-08 18:57:19 +00:00
// (comment from parser.go)
2015-08-13 19:05:37 -07:00
// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
2016-03-01 23:21:55 +00:00
// out by typecheck's lookdot as this $$.ttype. So by providing
2015-08-13 19:05:37 -07:00
// this back link here we avoid special casing there.
2016-03-30 16:59:53 -07:00
n . Type . SetNname ( n )
2015-08-13 19:05:37 -07:00
2016-03-18 17:21:32 -07:00
if Debug [ 'E' ] > 0 {
fmt . Printf ( "import [%q] meth %v \n" , importpkg . Path , n )
2016-04-24 13:50:26 -07:00
if Debug [ 'm' ] > 2 && n . Func . Inl . Len ( ) != 0 {
2016-03-18 17:21:32 -07:00
fmt . Printf ( "inl body: %v\n" , n . Func . Inl )
2015-10-22 18:56:45 -07:00
}
}
2015-08-13 19:05:37 -07:00
}
2016-03-18 17:21:32 -07:00
dclcontext = savedContext
2016-04-18 14:02:08 -07:00
case arrayTag :
2015-08-13 19:05:37 -07:00
t = p . newtyp ( TARRAY )
2016-04-18 14:02:08 -07:00
bound := p . int64 ( )
2016-04-01 20:11:30 -07:00
elem := p . typ ( )
2016-04-18 14:02:08 -07:00
t . Extra = & ArrayType { Elem : elem , Bound : bound }
case sliceTag :
t = p . newtyp ( TSLICE )
elem := p . typ ( )
t . Extra = SliceType { Elem : elem }
2015-08-13 19:05:37 -07:00
case dddTag :
2016-03-27 12:30:16 -07:00
t = p . newtyp ( TDDDFIELD )
2016-04-01 20:11:30 -07:00
t . Extra = DDDFieldType { T : p . typ ( ) }
2015-08-13 19:05:37 -07:00
case structTag :
t = p . newtyp ( TSTRUCT )
tostruct0 ( t , p . fieldList ( ) )
case pointerTag :
t = p . newtyp ( Tptr )
2016-04-01 20:11:30 -07:00
t . Extra = PtrType { Elem : p . typ ( ) }
2015-08-13 19:05:37 -07:00
case signatureTag :
t = p . newtyp ( TFUNC )
params := p . paramList ( )
result := p . paramList ( )
functype0 ( t , nil , params , result )
case interfaceTag :
t = p . newtyp ( TINTER )
if p . int ( ) != 0 {
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected embedded interface" )
2015-08-13 19:05:37 -07:00
}
tointerface0 ( t , p . methodList ( ) )
case mapTag :
t = p . newtyp ( TMAP )
2016-04-01 20:11:30 -07:00
mt := t . MapType ( )
mt . Key = p . typ ( )
mt . Val = p . typ ( )
2015-08-13 19:05:37 -07:00
case chanTag :
t = p . newtyp ( TCHAN )
2016-04-01 20:11:30 -07:00
ct := t . ChanType ( )
ct . Dir = ChanDir ( p . int ( ) )
ct . Elem = p . typ ( )
2015-08-13 19:05:37 -07:00
default :
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected type (tag = %d)" , i )
2015-08-13 19:05:37 -07:00
}
if t == nil {
2016-08-25 16:53:10 -07:00
formatErrorf ( "nil type (type tag = %d)" , i )
2015-08-13 19:05:37 -07:00
}
return t
}
func ( p * importer ) qualifiedName ( ) * Sym {
name := p . string ( )
pkg := p . pkg ( )
return pkg . Lookup ( name )
}
2016-03-08 18:57:19 +00:00
// parser.go:hidden_structdcl_list
2016-04-13 17:53:03 -07:00
func ( p * importer ) fieldList ( ) ( fields [ ] * Node ) {
if n := p . int ( ) ; n > 0 {
fields = make ( [ ] * Node , n )
for i := range fields {
fields [ i ] = p . field ( )
}
2015-08-13 19:05:37 -07:00
}
2016-04-13 17:53:03 -07:00
return
2015-08-13 19:05:37 -07:00
}
2016-03-08 18:57:19 +00:00
// parser.go:hidden_structdcl
2015-08-13 19:05:37 -07:00
func ( p * importer ) field ( ) * Node {
2016-04-13 17:53:03 -07:00
p . pos ( )
2015-08-13 19:05:37 -07:00
sym := p . fieldName ( )
typ := p . typ ( )
2016-04-25 13:24:48 -07:00
note := p . string ( )
2015-08-13 19:05:37 -07:00
var n * Node
if sym . Name != "" {
n = Nod ( ODCLFIELD , newname ( sym ) , typenod ( typ ) )
} else {
// anonymous field - typ must be T or *T and T must be a type name
s := typ . Sym
2016-03-30 15:09:25 -07:00
if s == nil && typ . IsPtr ( ) {
2016-04-01 20:11:30 -07:00
s = typ . Elem ( ) . Sym // deref
2015-08-13 19:05:37 -07:00
}
pkg := importpkg
if sym != nil {
pkg = sym . Pkg
}
n = embedded ( s , pkg )
n . Right = typenod ( typ )
}
2016-04-25 13:24:48 -07:00
n . SetVal ( Val { U : note } )
2015-08-13 19:05:37 -07:00
return n
}
2016-03-08 18:57:19 +00:00
// parser.go:hidden_interfacedcl_list
2016-04-13 17:53:03 -07:00
func ( p * importer ) methodList ( ) ( methods [ ] * Node ) {
if n := p . int ( ) ; n > 0 {
methods = make ( [ ] * Node , n )
for i := range methods {
methods [ i ] = p . method ( )
}
2015-08-13 19:05:37 -07:00
}
2016-04-13 17:53:03 -07:00
return
2015-08-13 19:05:37 -07:00
}
2016-03-08 18:57:19 +00:00
// parser.go:hidden_interfacedcl
2015-08-13 19:05:37 -07:00
func ( p * importer ) method ( ) * Node {
2016-04-13 17:53:03 -07:00
p . pos ( )
2015-08-13 19:05:37 -07:00
sym := p . fieldName ( )
params := p . paramList ( )
result := p . paramList ( )
return Nod ( ODCLFIELD , newname ( sym ) , typenod ( functype ( fakethis ( ) , params , result ) ) )
}
2016-03-08 18:57:19 +00:00
// parser.go:sym,hidden_importsym
2015-08-13 19:05:37 -07:00
func ( p * importer ) fieldName ( ) * Sym {
name := p . string ( )
2016-08-26 13:06:59 -07:00
if p . version == 0 && name == "_" {
// version 0 didn't export a package for _ fields
// but used the builtin package instead
return builtinpkg . Lookup ( name )
}
2015-08-13 19:05:37 -07:00
pkg := localpkg
2016-08-23 16:02:19 -07:00
if name != "" && ! exportname ( name ) {
2015-08-13 19:05:37 -07:00
if name == "?" {
name = ""
}
pkg = p . pkg ( )
}
return pkg . Lookup ( name )
}
2016-03-08 18:57:19 +00:00
// parser.go:ohidden_funarg_list
2016-03-08 10:26:20 -08:00
func ( p * importer ) paramList ( ) [ ] * Node {
2015-08-13 19:05:37 -07:00
i := p . int ( )
if i == 0 {
return nil
}
// negative length indicates unnamed parameters
named := true
if i < 0 {
i = - i
named = false
}
// i > 0
2016-03-08 21:53:33 +01:00
n := make ( [ ] * Node , i )
for i := range n {
n [ i ] = p . param ( named )
2015-08-13 19:05:37 -07:00
}
return n
}
2016-03-08 18:57:19 +00:00
// parser.go:hidden_funarg
2015-08-13 19:05:37 -07:00
func ( p * importer ) param ( named bool ) * Node {
typ := p . typ ( )
isddd := false
2016-03-27 12:30:16 -07:00
if typ . Etype == TDDDFIELD {
2016-03-31 15:18:39 -07:00
// TDDDFIELD indicates wrapped ... slice type
2016-04-01 20:11:30 -07:00
typ = typSlice ( typ . DDDField ( ) )
2015-08-13 19:05:37 -07:00
isddd = true
}
n := Nod ( ODCLFIELD , nil , typenod ( typ ) )
n . Isddd = isddd
if named {
name := p . string ( )
if name == "" {
2016-08-25 16:53:10 -07:00
formatErrorf ( "expected named parameter" )
2015-08-13 19:05:37 -07:00
}
2016-03-18 17:21:32 -07:00
// TODO(gri) Supply function/method package rather than
// encoding the package for each parameter repeatedly.
2016-05-02 17:03:36 -07:00
pkg := localpkg
if name != "_" {
pkg = p . pkg ( )
}
2016-03-18 17:21:32 -07:00
n . Left = newname ( pkg . Lookup ( name ) )
2015-08-13 19:05:37 -07:00
}
// TODO(gri) This is compiler-specific (escape info).
// Move into compiler-specific section eventually?
2016-04-25 13:24:48 -07:00
n . SetVal ( Val { U : p . string ( ) } )
2015-08-13 19:05:37 -07:00
return n
}
func ( p * importer ) value ( typ * Type ) ( x Val ) {
switch tag := p . tagOrIndex ( ) ; tag {
case falseTag :
x . U = false
2015-10-22 18:56:45 -07:00
2015-08-13 19:05:37 -07:00
case trueTag :
x . U = true
2015-10-22 18:56:45 -07:00
2015-08-13 19:05:37 -07:00
case int64Tag :
u := new ( Mpint )
2016-03-20 13:55:42 -07:00
u . SetInt64 ( p . int64 ( ) )
2015-08-13 19:05:37 -07:00
u . Rune = typ == idealrune
x . U = u
2015-10-22 18:56:45 -07:00
2015-08-13 19:05:37 -07:00
case floatTag :
f := newMpflt ( )
p . float ( f )
2016-03-30 15:09:25 -07:00
if typ == idealint || typ . IsInteger ( ) {
2015-08-13 19:05:37 -07:00
// uncommon case: large int encoded as float
u := new ( Mpint )
2016-03-20 13:55:42 -07:00
u . SetFloat ( f )
2015-08-13 19:05:37 -07:00
x . U = u
break
}
x . U = f
2015-10-22 18:56:45 -07:00
2015-08-13 19:05:37 -07:00
case complexTag :
u := new ( Mpcplx )
p . float ( & u . Real )
p . float ( & u . Imag )
x . U = u
2015-10-22 18:56:45 -07:00
2015-08-13 19:05:37 -07:00
case stringTag :
x . U = p . string ( )
2015-10-22 18:56:45 -07:00
2016-03-18 11:13:24 -04:00
case unknownTag :
2016-08-25 16:53:10 -07:00
formatErrorf ( "unknown constant (importing package with errors)" )
2016-03-18 11:13:24 -04:00
2015-10-22 18:56:45 -07:00
case nilTag :
x . U = new ( NilVal )
2015-08-13 19:05:37 -07:00
default :
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected value tag %d" , tag )
2015-08-13 19:05:37 -07:00
}
// verify ideal type
2016-04-01 13:36:24 -07:00
if typ . IsUntyped ( ) && untype ( x . Ctype ( ) ) != typ {
2016-08-25 16:53:10 -07:00
formatErrorf ( "value %v and type %v don't match" , x , typ )
2015-08-13 19:05:37 -07:00
}
return
}
func ( p * importer ) float ( x * Mpflt ) {
sign := p . int ( )
if sign == 0 {
2016-03-20 13:55:42 -07:00
x . SetFloat64 ( 0 )
2015-08-13 19:05:37 -07:00
return
}
exp := p . int ( )
mant := new ( big . Int ) . SetBytes ( [ ] byte ( p . string ( ) ) )
m := x . Val . SetInt ( mant )
m . SetMantExp ( m , exp - mant . BitLen ( ) )
if sign < 0 {
m . Neg ( m )
}
}
// ----------------------------------------------------------------------------
// Inlined function bodies
2016-03-18 17:21:32 -07:00
// Approach: Read nodes and use them to create/declare the same data structures
// as done originally by the (hidden) parser by closely following the parser's
// original code. In other words, "parsing" the import data (which happens to
// be encoded in binary rather textual form) is the best way at the moment to
// re-establish the syntax tree's invariants. At some future point we might be
// able to avoid this round-about way and create the rewritten nodes directly,
// possibly avoiding a lot of duplicate work (name resolution, type checking).
2016-04-13 13:17:30 -07:00
//
// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
// unrefined nodes (since this is what the importer uses). The respective case
// entries are unreachable in the importer.
2016-03-18 17:21:32 -07:00
func ( p * importer ) stmtList ( ) [ ] * Node {
var list [ ] * Node
for {
n := p . node ( )
if n == nil {
break
}
// OBLOCK nodes may be created when importing ODCL nodes - unpack them
if n . Op == OBLOCK {
list = append ( list , n . List . Slice ( ) ... )
} else {
list = append ( list , n )
}
}
return list
}
func ( p * importer ) exprList ( ) [ ] * Node {
var list [ ] * Node
for {
n := p . expr ( )
if n == nil {
break
}
list = append ( list , n )
}
2016-03-11 13:40:01 -08:00
return list
}
2016-03-18 17:21:32 -07:00
func ( p * importer ) elemList ( ) [ ] * Node {
2016-03-03 14:11:17 -08:00
c := p . int ( )
2016-03-18 17:21:32 -07:00
list := make ( [ ] * Node , c )
for i := range list {
list [ i ] = Nod ( OKEY , mkname ( p . fieldSym ( ) ) , p . expr ( ) )
2015-10-22 18:56:45 -07:00
}
2016-03-18 17:21:32 -07:00
return list
}
func ( p * importer ) expr ( ) * Node {
n := p . node ( )
if n != nil && n . Op == OBLOCK {
Fatalf ( "unexpected block node: %v" , n )
}
return n
2015-10-22 18:56:45 -07:00
}
2016-03-18 17:21:32 -07:00
// TODO(gri) split into expr and stmt
2015-10-22 18:56:45 -07:00
func ( p * importer ) node ( ) * Node {
2016-03-18 17:21:32 -07:00
switch op := p . op ( ) ; op {
// expressions
// case OPAREN:
// unreachable - unpacked by exporter
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case ODDDARG:
// unimplemented
// case OREGISTER:
// unimplemented
2015-10-22 18:56:45 -07:00
case OLITERAL :
typ := p . typ ( )
2016-03-18 17:21:32 -07:00
n := nodlit ( p . value ( typ ) )
if ! typ . IsUntyped ( ) {
2016-08-23 11:20:34 -07:00
// Type-checking simplifies unsafe.Pointer(uintptr(c))
// to unsafe.Pointer(c) which then cannot type-checked
// again. Re-introduce explicit uintptr(c) conversion.
// (issue 16317).
2016-08-21 17:08:04 +02:00
if typ . IsUnsafePtr ( ) {
conv := Nod ( OCALL , typenod ( Types [ TUINTPTR ] ) , nil )
conv . List . Set1 ( n )
n = conv
}
2016-03-18 17:21:32 -07:00
conv := Nod ( OCALL , typenod ( typ ) , nil )
conv . List . Set1 ( n )
n = conv
}
return n
2015-10-22 18:56:45 -07:00
2016-05-11 12:40:17 -07:00
case ONAME :
2016-03-18 17:21:32 -07:00
return mkname ( p . sym ( ) )
2015-10-22 18:56:45 -07:00
2016-05-11 12:40:17 -07:00
// case OPACK, ONONAME:
// unreachable - should have been resolved by typechecking
2016-03-18 17:21:32 -07:00
case OTYPE :
if p . bool ( ) {
return mkname ( p . sym ( ) )
}
return typenod ( p . typ ( ) )
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
// unreachable - should have been resolved by typechecking
// case OCLOSURE:
// unimplemented
2015-10-22 18:56:45 -07:00
case OPTRLIT :
2016-03-18 17:21:32 -07:00
n := p . expr ( )
2016-05-08 20:59:53 -07:00
if ! p . bool ( ) /* !implicit, i.e. '&' operator */ {
2016-03-18 17:21:32 -07:00
if n . Op == OCOMPLIT {
// Special case for &T{...}: turn into (*T){...}.
n . Right = Nod ( OIND , n . Right , nil )
n . Right . Implicit = true
} else {
n = Nod ( OADDR , n , nil )
}
}
return n
2015-10-22 18:56:45 -07:00
case OSTRUCTLIT :
2016-05-08 20:59:53 -07:00
n := Nod ( OCOMPLIT , nil , typenod ( p . typ ( ) ) )
n . List . Set ( p . elemList ( ) ) // special handling of field names
2016-03-18 17:21:32 -07:00
return n
2015-10-22 18:56:45 -07:00
2016-05-08 20:59:53 -07:00
// case OARRAYLIT, OMAPLIT:
// unreachable - mapped to case OCOMPLIT below by exporter
case OCOMPLIT :
n := Nod ( OCOMPLIT , nil , typenod ( p . typ ( ) ) )
2016-03-18 17:21:32 -07:00
n . List . Set ( p . exprList ( ) )
return n
2015-10-22 18:56:45 -07:00
case OKEY :
2016-03-18 17:21:32 -07:00
left , right := p . exprsOrNil ( )
return Nod ( OKEY , left , right )
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case OCALLPART:
// unimplemented
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
// unreachable - mapped to case OXDOT below by exporter
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
case OXDOT :
2015-10-22 18:56:45 -07:00
// see parser.new_dotname
2016-05-11 12:40:17 -07:00
return NodSym ( OXDOT , p . expr ( ) , p . fieldSym ( ) )
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case ODOTTYPE, ODOTTYPE2:
// unreachable - mapped to case ODOTTYPE below by exporter
case ODOTTYPE :
n := Nod ( ODOTTYPE , p . expr ( ) , nil )
2015-10-22 18:56:45 -07:00
if p . bool ( ) {
2016-03-18 17:21:32 -07:00
n . Right = p . expr ( )
2015-10-22 18:56:45 -07:00
} else {
2016-03-18 17:21:32 -07:00
n . Right = typenod ( p . typ ( ) )
2015-10-22 18:56:45 -07:00
}
2016-03-18 17:21:32 -07:00
return n
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
// unreachable - mapped to cases below by exporter
2015-10-22 18:56:45 -07:00
2016-04-21 11:55:33 -07:00
case OINDEX :
2016-03-18 17:21:32 -07:00
return Nod ( op , p . expr ( ) , p . expr ( ) )
2016-04-21 11:55:33 -07:00
case OSLICE , OSLICE3 :
n := Nod ( op , p . expr ( ) , nil )
low , high := p . exprsOrNil ( )
var max * Node
if n . Op . IsSlice3 ( ) {
max = p . expr ( )
}
n . SetSliceBounds ( low , high , max )
return n
2016-03-18 17:21:32 -07:00
// case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
// unreachable - mapped to OCONV case below by exporter
case OCONV :
n := Nod ( OCALL , typenod ( p . typ ( ) ) , nil )
2016-05-11 13:39:36 -07:00
n . List . Set ( p . exprList ( ) )
2016-03-18 17:21:32 -07:00
return n
2016-05-11 13:39:36 -07:00
case OCOPY , OCOMPLEX , OREAL , OIMAG , OAPPEND , OCAP , OCLOSE , ODELETE , OLEN , OMAKE , ONEW , OPANIC , ORECOVER , OPRINT , OPRINTN :
2016-03-18 17:21:32 -07:00
n := builtinCall ( op )
2016-05-11 13:39:36 -07:00
n . List . Set ( p . exprList ( ) )
if op == OAPPEND {
2016-03-18 17:21:32 -07:00
n . Isddd = p . bool ( )
}
return n
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
// unreachable - mapped to OCALL case below by exporter
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
case OCALL :
n := Nod ( OCALL , p . expr ( ) , nil )
n . List . Set ( p . exprList ( ) )
2015-10-22 18:56:45 -07:00
n . Isddd = p . bool ( )
2016-03-18 17:21:32 -07:00
return n
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
case OMAKEMAP , OMAKECHAN , OMAKESLICE :
n := builtinCall ( OMAKE )
n . List . Append ( typenod ( p . typ ( ) ) )
n . List . Append ( p . exprList ( ) ... )
return n
// unary expressions
case OPLUS , OMINUS , OADDR , OCOM , OIND , ONOT , ORECV :
return Nod ( op , p . expr ( ) , nil )
// binary expressions
case OADD , OAND , OANDAND , OANDNOT , ODIV , OEQ , OGE , OGT , OLE , OLT ,
OLSH , OMOD , OMUL , ONE , OOR , OOROR , ORSH , OSEND , OSUB , OXOR :
return Nod ( op , p . expr ( ) , p . expr ( ) )
case OADDSTR :
list := p . exprList ( )
x := list [ 0 ]
for _ , y := range list [ 1 : ] {
x = Nod ( OADD , x , y )
}
return x
// case OCMPSTR, OCMPIFACE:
// unreachable - mapped to std comparison operators by exporter
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
case ODCLCONST :
// TODO(gri) these should not be exported in the first place
return Nod ( OEMPTY , nil , nil )
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// --------------------------------------------------------------------
2015-10-22 18:56:45 -07:00
// statements
case ODCL :
2016-03-18 17:21:32 -07:00
var lhs * Node
if p . bool ( ) {
lhs = p . expr ( )
} else {
lhs = dclname ( p . sym ( ) )
}
// TODO(gri) avoid list created here!
return liststmt ( variter ( [ ] * Node { lhs } , typenod ( p . typ ( ) ) , nil ) )
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case ODCLFIELD:
// unimplemented
2016-04-13 13:17:30 -07:00
// case OAS, OASWB:
// unreachable - mapped to OAS case below by exporter
case OAS :
return Nod ( OAS , p . expr ( ) , p . expr ( ) )
2015-10-22 18:56:45 -07:00
case OASOP :
2016-03-18 17:21:32 -07:00
n := Nod ( OASOP , nil , nil )
2015-10-22 18:56:45 -07:00
n . Etype = EType ( p . int ( ) )
2016-03-18 17:21:32 -07:00
n . Left = p . expr ( )
if ! p . bool ( ) {
n . Right = Nodintconst ( 1 )
n . Implicit = true
} else {
n . Right = p . expr ( )
}
return n
2015-10-22 18:56:45 -07:00
2016-04-13 13:17:30 -07:00
// case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
// unreachable - mapped to OAS2 case below by exporter
2015-10-22 18:56:45 -07:00
2016-04-13 13:17:30 -07:00
case OAS2 :
2016-03-18 17:21:32 -07:00
n := Nod ( OAS2 , nil , nil )
n . List . Set ( p . exprList ( ) )
n . Rlist . Set ( p . exprList ( ) )
return n
2015-10-22 18:56:45 -07:00
case ORETURN :
2016-03-18 17:21:32 -07:00
n := Nod ( ORETURN , nil , nil )
n . List . Set ( p . exprList ( ) )
return n
// case ORETJMP:
// unreachable - generated by compiler for trampolin routines (not exported)
2015-10-22 18:56:45 -07:00
case OPROC , ODEFER :
2016-03-18 17:21:32 -07:00
return Nod ( op , p . expr ( ) , nil )
2015-10-22 18:56:45 -07:00
case OIF :
2016-03-18 17:21:32 -07:00
markdcl ( )
n := Nod ( OIF , nil , nil )
n . Ninit . Set ( p . stmtList ( ) )
n . Left = p . expr ( )
n . Nbody . Set ( p . stmtList ( ) )
n . Rlist . Set ( p . stmtList ( ) )
popdcl ( )
return n
2015-10-22 18:56:45 -07:00
case OFOR :
2016-03-18 17:21:32 -07:00
markdcl ( )
n := Nod ( OFOR , nil , nil )
n . Ninit . Set ( p . stmtList ( ) )
n . Left , n . Right = p . exprsOrNil ( )
n . Nbody . Set ( p . stmtList ( ) )
popdcl ( )
return n
2015-10-22 18:56:45 -07:00
case ORANGE :
2016-03-18 17:21:32 -07:00
markdcl ( )
n := Nod ( ORANGE , nil , nil )
n . List . Set ( p . stmtList ( ) )
n . Right = p . expr ( )
n . Nbody . Set ( p . stmtList ( ) )
popdcl ( )
return n
2015-10-22 18:56:45 -07:00
case OSELECT , OSWITCH :
2016-03-18 17:21:32 -07:00
markdcl ( )
n := Nod ( op , nil , nil )
n . Ninit . Set ( p . stmtList ( ) )
n . Left , _ = p . exprsOrNil ( )
n . List . Set ( p . stmtList ( ) )
popdcl ( )
return n
2015-10-22 18:56:45 -07:00
2016-04-13 13:17:30 -07:00
// case OCASE, OXCASE:
// unreachable - mapped to OXCASE case below by exporter
case OXCASE :
2016-03-18 17:21:32 -07:00
markdcl ( )
n := Nod ( OXCASE , nil , nil )
cmd/compile: correctly import labels, gotos, and fallthroughs
The importer had several bugs with respect to labels and gotos:
- it didn't create a new ONAME node for label names (label dcl,
goto, continue, and break)
- it overwrote the symbol for gotos with the dclstack
- it didn't set the dclstack for labels
In the process changed export format slightly to always assume
a label name for labels and gotos, and never assume a label for
fallthroughs.
For fallthroughs and switch cases, now also set Xoffset like in
the parser. (Not setting it, i.e., using 0 was ok since this is
only used for verifying correct use of fallthroughs, which was
checked already. But it's an extra level of verification of the
import.)
Fixes #15838.
Change-Id: I3637f6314b8651c918df0c8cd70cd858c92bd483
Reviewed-on: https://go-review.googlesource.com/23445
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 16:38:02 -07:00
n . Xoffset = int64 ( block )
2016-03-18 17:21:32 -07:00
n . List . Set ( p . exprList ( ) )
// TODO(gri) eventually we must declare variables for type switch
// statements (type switch statements are not yet exported)
n . Nbody . Set ( p . stmtList ( ) )
popdcl ( )
return n
2015-10-22 18:56:45 -07:00
2016-04-13 13:17:30 -07:00
// case OFALL:
// unreachable - mapped to OXFALL case below by exporter
cmd/compile: correctly import labels, gotos, and fallthroughs
The importer had several bugs with respect to labels and gotos:
- it didn't create a new ONAME node for label names (label dcl,
goto, continue, and break)
- it overwrote the symbol for gotos with the dclstack
- it didn't set the dclstack for labels
In the process changed export format slightly to always assume
a label name for labels and gotos, and never assume a label for
fallthroughs.
For fallthroughs and switch cases, now also set Xoffset like in
the parser. (Not setting it, i.e., using 0 was ok since this is
only used for verifying correct use of fallthroughs, which was
checked already. But it's an extra level of verification of the
import.)
Fixes #15838.
Change-Id: I3637f6314b8651c918df0c8cd70cd858c92bd483
Reviewed-on: https://go-review.googlesource.com/23445
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 16:38:02 -07:00
case OXFALL :
n := Nod ( OXFALL , nil , nil )
n . Xoffset = int64 ( block )
return n
case OBREAK , OCONTINUE :
2016-03-18 17:21:32 -07:00
left , _ := p . exprsOrNil ( )
cmd/compile: correctly import labels, gotos, and fallthroughs
The importer had several bugs with respect to labels and gotos:
- it didn't create a new ONAME node for label names (label dcl,
goto, continue, and break)
- it overwrote the symbol for gotos with the dclstack
- it didn't set the dclstack for labels
In the process changed export format slightly to always assume
a label name for labels and gotos, and never assume a label for
fallthroughs.
For fallthroughs and switch cases, now also set Xoffset like in
the parser. (Not setting it, i.e., using 0 was ok since this is
only used for verifying correct use of fallthroughs, which was
checked already. But it's an extra level of verification of the
import.)
Fixes #15838.
Change-Id: I3637f6314b8651c918df0c8cd70cd858c92bd483
Reviewed-on: https://go-review.googlesource.com/23445
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 16:38:02 -07:00
if left != nil {
left = newname ( left . Sym )
}
2016-03-18 17:21:32 -07:00
return Nod ( op , left , nil )
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
// case OEMPTY:
// unreachable - not emitted by exporter
2015-10-22 18:56:45 -07:00
cmd/compile: correctly import labels, gotos, and fallthroughs
The importer had several bugs with respect to labels and gotos:
- it didn't create a new ONAME node for label names (label dcl,
goto, continue, and break)
- it overwrote the symbol for gotos with the dclstack
- it didn't set the dclstack for labels
In the process changed export format slightly to always assume
a label name for labels and gotos, and never assume a label for
fallthroughs.
For fallthroughs and switch cases, now also set Xoffset like in
the parser. (Not setting it, i.e., using 0 was ok since this is
only used for verifying correct use of fallthroughs, which was
checked already. But it's an extra level of verification of the
import.)
Fixes #15838.
Change-Id: I3637f6314b8651c918df0c8cd70cd858c92bd483
Reviewed-on: https://go-review.googlesource.com/23445
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 16:38:02 -07:00
case OGOTO , OLABEL :
n := Nod ( op , newname ( p . expr ( ) . Sym ) , nil )
n . Sym = dclstack // context, for goto restrictions
2016-03-18 17:21:32 -07:00
return n
case OEND :
return nil
2015-10-22 18:56:45 -07:00
default :
2016-05-08 20:59:53 -07:00
Fatalf ( "cannot import %s (%d) node\n" +
"==> please file an issue and assign to gri@\n" , op , op )
2016-03-18 17:21:32 -07:00
panic ( "unreachable" ) // satisfy compiler
2015-10-22 18:56:45 -07:00
}
2016-03-18 17:21:32 -07:00
}
2015-10-22 18:56:45 -07:00
2016-03-18 17:21:32 -07:00
func builtinCall ( op Op ) * Node {
return Nod ( OCALL , mkname ( builtinpkg . Lookup ( goopnames [ op ] ) ) , nil )
2015-10-22 18:56:45 -07:00
}
2016-03-18 17:21:32 -07:00
func ( p * importer ) exprsOrNil ( ) ( a , b * Node ) {
2015-10-22 18:56:45 -07:00
ab := p . int ( )
if ab & 1 != 0 {
2016-03-18 17:21:32 -07:00
a = p . expr ( )
2015-10-22 18:56:45 -07:00
}
if ab & 2 != 0 {
2016-03-18 17:21:32 -07:00
b = p . expr ( )
2015-08-13 19:05:37 -07:00
}
2015-10-22 18:56:45 -07:00
return
}
2016-03-18 17:21:32 -07:00
func ( p * importer ) fieldSym ( ) * Sym {
name := p . string ( )
pkg := localpkg
if ! exportname ( name ) {
pkg = p . pkg ( )
}
return pkg . Lookup ( name )
}
2015-10-22 18:56:45 -07:00
func ( p * importer ) sym ( ) * Sym {
2016-03-18 17:21:32 -07:00
name := p . string ( )
pkg := localpkg
if name != "_" {
pkg = p . pkg ( )
}
return pkg . Lookup ( name )
2015-10-22 18:56:45 -07:00
}
func ( p * importer ) bool ( ) bool {
return p . int ( ) != 0
2015-08-13 19:05:37 -07:00
}
2015-10-22 18:56:45 -07:00
func ( p * importer ) op ( ) Op {
return Op ( p . int ( ) )
2015-08-13 19:05:37 -07:00
}
// ----------------------------------------------------------------------------
// Low-level decoders
func ( p * importer ) tagOrIndex ( ) int {
if p . debugFormat {
p . marker ( 't' )
}
return int ( p . rawInt64 ( ) )
}
func ( p * importer ) int ( ) int {
x := p . int64 ( )
if int64 ( int ( x ) ) != x {
2016-08-25 16:53:10 -07:00
formatErrorf ( "exported integer too large" )
2015-08-13 19:05:37 -07:00
}
return int ( x )
}
func ( p * importer ) int64 ( ) int64 {
if p . debugFormat {
p . marker ( 'i' )
}
return p . rawInt64 ( )
}
func ( p * importer ) string ( ) string {
2016-05-04 15:13:36 -07:00
if p . debugFormat {
2015-08-13 19:05:37 -07:00
p . marker ( 's' )
}
2016-04-13 17:53:03 -07:00
// if the string was seen before, i is its index (>= 0)
// (the empty string is at index 0)
i := p . rawInt64 ( )
if i >= 0 {
return p . strList [ i ]
2015-08-13 19:05:37 -07:00
}
2016-04-13 17:53:03 -07:00
// otherwise, i is the negative string length (< 0)
if n := int ( - i ) ; n <= cap ( p . buf ) {
p . buf = p . buf [ : n ]
} else {
p . buf = make ( [ ] byte , n )
}
for i := range p . buf {
p . buf [ i ] = p . rawByte ( )
}
s := string ( p . buf )
p . strList = append ( p . strList , s )
return s
2015-08-13 19:05:37 -07:00
}
func ( p * importer ) marker ( want byte ) {
2016-04-13 17:53:03 -07:00
if got := p . rawByte ( ) ; got != want {
2016-08-25 16:53:10 -07:00
formatErrorf ( "incorrect marker: got %c; want %c (pos = %d)" , got , want , p . read )
2015-08-13 19:05:37 -07:00
}
pos := p . read
if n := int ( p . rawInt64 ( ) ) ; n != pos {
2016-08-25 16:53:10 -07:00
formatErrorf ( "incorrect position: got %d; want %d" , n , pos )
2015-08-13 19:05:37 -07:00
}
}
2016-08-19 18:10:00 -07:00
// rawInt64 should only be used by low-level decoders.
2015-08-13 19:05:37 -07:00
func ( p * importer ) rawInt64 ( ) int64 {
i , err := binary . ReadVarint ( p )
if err != nil {
2016-08-25 16:53:10 -07:00
formatErrorf ( "read error: %v" , err )
2015-08-13 19:05:37 -07:00
}
return i
}
2016-08-19 18:10:00 -07:00
// rawStringln should only be used to read the initial version string.
func ( p * importer ) rawStringln ( b byte ) string {
p . buf = p . buf [ : 0 ]
for b != '\n' {
p . buf = append ( p . buf , b )
b = p . rawByte ( )
}
return string ( p . buf )
}
2015-08-13 19:05:37 -07:00
// needed for binary.ReadVarint in rawInt64
func ( p * importer ) ReadByte ( ) ( byte , error ) {
2016-04-13 17:53:03 -07:00
return p . rawByte ( ) , nil
2015-08-13 19:05:37 -07:00
}
2015-10-23 16:01:09 -07:00
2016-04-13 17:53:03 -07:00
// rawByte is the bottleneck interface for reading from p.in.
2015-10-23 16:01:09 -07:00
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
2016-04-13 17:53:03 -07:00
// rawByte should only be used by low-level decoders.
func ( p * importer ) rawByte ( ) byte {
2016-03-11 13:39:20 -05:00
c , err := p . in . ReadByte ( )
2015-10-23 16:01:09 -07:00
p . read ++
2016-03-11 13:39:20 -05:00
if err != nil {
2016-08-25 16:53:10 -07:00
formatErrorf ( "read error: %v" , err )
2015-10-23 16:01:09 -07:00
}
if c == '|' {
2016-03-11 13:39:20 -05:00
c , err = p . in . ReadByte ( )
2015-10-23 16:01:09 -07:00
p . read ++
2016-03-11 13:39:20 -05:00
if err != nil {
2016-08-25 16:53:10 -07:00
formatErrorf ( "read error: %v" , err )
2015-10-23 16:01:09 -07:00
}
switch c {
case 'S' :
c = '$'
case '|' :
// nothing to do
default :
2016-08-25 16:53:10 -07:00
formatErrorf ( "unexpected escape sequence in export data" )
2015-10-23 16:01:09 -07:00
}
}
2016-03-11 13:39:20 -05:00
return c
2015-10-23 16:01:09 -07:00
}