From 70a684cf44cc3398c44afcd69387d7938d90f063 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Wed, 28 Nov 2018 10:50:54 -0500 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Zhang --- src/go/internal/gccgoimporter/parser.go | 72 ++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go index 6fab1ef409a..e75f15c429f 100644 --- a/src/go/internal/gccgoimporter/parser.go +++ b/src/go/internal/gccgoimporter/parser.go @@ -15,6 +15,7 @@ import ( "strconv" "strings" "text/scanner" + "unicode/utf8" ) 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) { p.scanner.Init(src) 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.Filename = filename // for good error messages 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 . // FloatOrComplex = float ["i" | ("+"|"-") float "i"] . 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 { case scanner.String: str := p.parseString() @@ -443,7 +453,7 @@ func (p *parser) update(t types.Type, nlist []int) { // NamedType = TypeName [ "=" ] Type { Method } . // TypeName = ExportedName . -// Method = "func" "(" Param ")" Name ParamList ResultList ";" . +// Method = "func" "(" Param ")" Name ParamList ResultList [InlineBody] ";" . func (p *parser) parseNamedType(nlist []int) types.Type { pkg, name := p.parseExportedName() scope := pkg.Scope() @@ -508,6 +518,7 @@ func (p *parser) parseNamedType(nlist []int) types.Type { name := p.parseName() params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) + p.skipInlineBody() p.expectEOL() 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 { switch p.tok { 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 '(': params, _ := p.parseParamList(pkg) @@ -676,7 +691,7 @@ func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signa return t } -// Func = Name FunctionType . +// Func = Name FunctionType [InlineBody] . func (p *parser) parseFunc(pkg *types.Package) *types.Func { name := p.parseName() if strings.ContainsRune(name, '$') { @@ -685,7 +700,9 @@ func (p *parser) parseFunc(pkg *types.Package) *types.Func { p.discardDirectiveWhileParsingTypes(pkg) 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) ";" } "}" . @@ -823,8 +840,13 @@ func lookupBuiltinType(typ int) types.Type { // // 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('<') + 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") switch p.tok { @@ -863,6 +885,39 @@ func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) { return } +// InlineBody = "" .{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)* . func (p *parser) parseTypes(pkg *types.Package) { maxp1 := p.parseInt() @@ -882,6 +937,11 @@ func (p *parser) parseTypes(pkg *types.Package) { 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. // The next runes from the scanner should be the type data.