1
0
mirror of https://github.com/golang/go synced 2024-11-12 08:50:22 -07:00

go/internal/gccgoimporter: additional V3 export data changes

This patch merges in support for reading the most recent
incarnation of V3 export data (initial inline function bodies),
from the importer portions of https://golang.org/cl/150061 and
https://golang.org/cl/150067.

Updates #28961.

Change-Id: I34e837acbf48b8fd1a4896a1a977d2241adfb28d
Reviewed-on: https://go-review.googlesource.com/c/151557
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Than McIntosh 2018-11-28 10:50:54 -05:00
parent 2b58ca6e3d
commit 70a684cf44

View File

@ -15,6 +15,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"text/scanner" "text/scanner"
"unicode/utf8"
) )
type parser struct { type parser struct {
@ -41,7 +42,7 @@ func (p *parser) init(filename string, src io.Reader, imports map[string]*types.
func (p *parser) initScanner(filename string, src io.Reader) { func (p *parser) initScanner(filename string, src io.Reader) {
p.scanner.Init(src) p.scanner.Init(src)
p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) } p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings
p.scanner.Whitespace = 1<<'\t' | 1<<' ' p.scanner.Whitespace = 1<<'\t' | 1<<' '
p.scanner.Filename = filename // for good error messages p.scanner.Filename = filename // for good error messages
p.next() p.next()
@ -281,6 +282,15 @@ func (p *parser) parseConversion(pkg *types.Package) (val constant.Value, typ ty
// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) | Conversion . // ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) | Conversion .
// FloatOrComplex = float ["i" | ("+"|"-") float "i"] . // FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
func (p *parser) parseConstValue(pkg *types.Package) (val constant.Value, typ types.Type) { func (p *parser) parseConstValue(pkg *types.Package) (val constant.Value, typ types.Type) {
// v3 changed to $false, $true, $convert, to avoid confusion
// with variable names in inline function bodies.
if p.tok == '$' {
p.next()
if p.tok != scanner.Ident {
p.errorf("expected identifer after '$', got %s (%q)", scanner.TokenString(p.tok), p.lit)
}
}
switch p.tok { switch p.tok {
case scanner.String: case scanner.String:
str := p.parseString() str := p.parseString()
@ -443,7 +453,7 @@ func (p *parser) update(t types.Type, nlist []int) {
// NamedType = TypeName [ "=" ] Type { Method } . // NamedType = TypeName [ "=" ] Type { Method } .
// TypeName = ExportedName . // TypeName = ExportedName .
// Method = "func" "(" Param ")" Name ParamList ResultList ";" . // Method = "func" "(" Param ")" Name ParamList ResultList [InlineBody] ";" .
func (p *parser) parseNamedType(nlist []int) types.Type { func (p *parser) parseNamedType(nlist []int) types.Type {
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
scope := pkg.Scope() scope := pkg.Scope()
@ -508,6 +518,7 @@ func (p *parser) parseNamedType(nlist []int) types.Type {
name := p.parseName() name := p.parseName()
params, isVariadic := p.parseParamList(pkg) params, isVariadic := p.parseParamList(pkg)
results := p.parseResultList(pkg) results := p.parseResultList(pkg)
p.skipInlineBody()
p.expectEOL() p.expectEOL()
sig := types.NewSignature(receiver, params, results, isVariadic) sig := types.NewSignature(receiver, params, results, isVariadic)
@ -653,7 +664,11 @@ func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
func (p *parser) parseResultList(pkg *types.Package) *types.Tuple { func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
switch p.tok { switch p.tok {
case '<': case '<':
return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg))) p.next()
if p.tok == scanner.Ident && p.lit == "inl" {
return nil
}
return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseTypeAfterAngle(pkg)))
case '(': case '(':
params, _ := p.parseParamList(pkg) params, _ := p.parseParamList(pkg)
@ -676,7 +691,7 @@ func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signa
return t return t
} }
// Func = Name FunctionType . // Func = Name FunctionType [InlineBody] .
func (p *parser) parseFunc(pkg *types.Package) *types.Func { func (p *parser) parseFunc(pkg *types.Package) *types.Func {
name := p.parseName() name := p.parseName()
if strings.ContainsRune(name, '$') { if strings.ContainsRune(name, '$') {
@ -685,7 +700,9 @@ func (p *parser) parseFunc(pkg *types.Package) *types.Func {
p.discardDirectiveWhileParsingTypes(pkg) p.discardDirectiveWhileParsingTypes(pkg)
return nil return nil
} }
return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg, nil)) f := types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg, nil))
p.skipInlineBody()
return f
} }
// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" . // InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
@ -823,8 +840,13 @@ func lookupBuiltinType(typ int) types.Type {
// //
// parseType updates the type map to t for all type numbers n. // parseType updates the type map to t for all type numbers n.
// //
func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) { func (p *parser) parseType(pkg *types.Package, n ...int) types.Type {
p.expect('<') p.expect('<')
return p.parseTypeAfterAngle(pkg, n...)
}
// (*parser).Type after reading the "<".
func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...int) (t types.Type) {
p.expectKeyword("type") p.expectKeyword("type")
switch p.tok { switch p.tok {
@ -863,6 +885,39 @@ func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) {
return return
} }
// InlineBody = "<inl:NN>" .{NN}
// Reports whether a body was skipped.
func (p *parser) skipInlineBody() {
// We may or may not have seen the '<' already, depending on
// whether the function had a result type or not.
if p.tok == '<' {
p.next()
p.expectKeyword("inl")
} else if p.tok != scanner.Ident || p.lit != "inl" {
return
} else {
p.next()
}
p.expect(':')
want := p.parseInt()
p.expect('>')
defer func(w uint64) {
p.scanner.Whitespace = w
}(p.scanner.Whitespace)
p.scanner.Whitespace = 0
got := 0
for got < want {
r := p.scanner.Next()
if r == scanner.EOF {
p.error("unexpected EOF")
}
got += utf8.RuneLen(r)
}
}
// Types = "types" maxp1 exportedp1 (offset length)* . // Types = "types" maxp1 exportedp1 (offset length)* .
func (p *parser) parseTypes(pkg *types.Package) { func (p *parser) parseTypes(pkg *types.Package) {
maxp1 := p.parseInt() maxp1 := p.parseInt()
@ -882,6 +937,11 @@ func (p *parser) parseTypes(pkg *types.Package) {
total += len total += len
} }
defer func(w uint64) {
p.scanner.Whitespace = w
}(p.scanner.Whitespace)
p.scanner.Whitespace = 0
// We should now have p.tok pointing to the final newline. // We should now have p.tok pointing to the final newline.
// The next runes from the scanner should be the type data. // The next runes from the scanner should be the type data.