]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] all: merge dev.regabi (7e0a81d) into dev.typeparams
authorMatthew Dempsky <mdempsky@google.com>
Fri, 22 Jan 2021 23:35:11 +0000 (15:35 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Sat, 23 Jan 2021 00:32:37 +0000 (16:32 -0800)
As with CL 285875, this required resolving some conflicts around
handling of //go:embed directives. Still further work is needed to
reject uses of //go:embed in files that don't import "embed", so this
is left as a TODO. (When this code was written for dev.typeparams, we
were still leaning towards not requiring the "embed" import.)

Also, the recent support for inlining closures (CL 283112) interacts
poorly with -G=3 mode. There are some known issues with this code
already (#43818), so for now this CL disables inlining of closures
when in -G=3 mode with a TODO to revisit this once closure inlining is
working fully.

Conflicts:

- src/cmd/compile/internal/noder/noder.go
- src/cmd/compile/internal/typecheck/dcl.go
- src/cmd/compile/internal/typecheck/func.go
- test/run.go

Merge List:

+ 2021-01-22 7e0a81d280 [dev.regabi] all: merge master (dab3e5a) into dev.regabi
+ 2021-01-22 dab3e5affe runtime: switch runtime to libc for openbsd/amd64
+ 2021-01-22 a1b53d85da cmd/go: add documentation for test and xtest fields output by go list
+ 2021-01-22 b268b60774 runtime: remove pthread_kill/pthread_self for openbsd
+ 2021-01-22 ec4051763d runtime: fix typo in mgcscavenge.go
+ 2021-01-22 7ece3a7b17 net/http: fix flaky TestDisableKeepAliveUpgrade
+ 2021-01-22 50cba0506f time: clarify Timer.Reset behavior on AfterFunc Timers
+ 2021-01-22 cf10e69f17 doc/go1.16: mention net/http.Transport.GetProxyConnectHeader
+ 2021-01-22 ec1b945265 doc/go1.16: mention path/filepath.WalkDir
+ 2021-01-22 11def3d40b doc/go1.16: mention syscall.AllThreadsSyscall
+ 2021-01-21 07b0235609 doc/go1.16: add notes about package-specific fs.FS changes
+ 2021-01-21 e2b4f1fea5 doc/go1.16: minor formatting fix
+ 2021-01-21 9f43a9e07b doc/go1.16: mention new debug/elf constants
+ 2021-01-21 3c2f11ba5b cmd/go: overwrite program name with full path
+ 2021-01-21 953d1feca9 all: introduce and use internal/execabs
+ 2021-01-21 b186e4d70d cmd/go: add test case for cgo CC setting
+ 2021-01-21 5a8a2265fb cmd/cgo: report exec errors a bit more clearly
+ 2021-01-21 46e2e2e9d9 cmd/go: pass resolved CC, GCCGO to cgo
+ 2021-01-21 3d40895e36 runtime: switch openbsd/arm64 to pthreads
+ 2021-01-21 d95ca91380 crypto/elliptic: fix P-224 field reduction
+ 2021-01-21 d7e71c01ad [dev.regabi] cmd/compile: replace ir.Name map with ir.NameSet for dwarf
+ 2021-01-21 5248f59a22 [dev.regabi] cmd/compile: replace ir.Name map with ir.NameSet for SSA
+ 2021-01-21 970d8b6cb2 [dev.regabi] cmd/compile: replace ir.Name map with ir.NameSet in inlining
+ 2021-01-21 68a4664475 [dev.regabi] cmd/compile: remove tempAssigns in walkCall1
+ 2021-01-21 fd9a391cdd [dev.regabi] cmd/compile: remove CallExpr.Rargs
+ 2021-01-21 19a6db6b63 [dev.regabi] cmd/compile: make sure mkcall* passed non-nil init
+ 2021-01-21 9f036844db [dev.regabi] cmd/compile: use ir.DoChildren directly in inlining
+ 2021-01-21 213c3905e9 [dev.regabi] cmd/compile: use node walked flag to prevent double walk for walkSelect
+ 2021-01-20 1760d736f6 [dev.regabi] cmd/compile: exporting, importing, and inlining functions with OCLOSURE
+ 2021-01-20 ecf4ebf100 cmd/internal/moddeps: check content of all modules in GOROOT
+ 2021-01-20 92cb157cf3 [dev.regabi] cmd/compile: late expansion of return values
+ 2021-01-20 d2d155d1ae runtime: don't adjust timer pp field in timerWaiting status
+ 2021-01-20 803d18fc6c cmd/go: set Incomplete field on go list output if no files match embed
+ 2021-01-20 6e243ce71d cmd/go: have go mod vendor copy embedded files in subdirs
+ 2021-01-20 be28e5abc5 cmd/go: fix mod_get_fallback test
+ 2021-01-20 928bda4f4a runtime: convert openbsd/amd64 locking to libc
+ 2021-01-19 824f2d635c cmd/go: allow go fmt to complete when embedded file is missing
+ 2021-01-19 0575e35e50 cmd/compile: require 'go 1.16' go.mod line for //go:embed
+ 2021-01-19 9423d50d53 [dev.regabi] cmd/compile: use '%q' for printing rune values less than 128
+ 2021-01-19 ccb2e90688 cmd/link: exit before Asmb2 if error
+ 2021-01-19 ca5774a5a5 embed: treat uninitialized FS as empty
+ 2021-01-19 d047c91a6c cmd/link,runtime: switch openbsd/amd64 to pthreads
+ 2021-01-19 61debffd97 runtime: factor out usesLibcall
+ 2021-01-19 9fed39d281 runtime: factor out mStackIsSystemAllocated
+ 2021-01-19 a2f825c542 [dev.regabi] cmd/compile: directly create go.map and go.track symbols
+ 2021-01-19 4a4212c0e5 [dev.regabi] cmd/compile: refactor Linksym creation
+ 2021-01-19 4f5c603c0f [dev.regabi] cmd/compile: cleanup callTargetLSym
+ 2021-01-18 dbab079835 runtime: free Windows event handles after last lock is dropped
+ 2021-01-18 5a8fbb0d2d os: do not close syscall.Stdin in TestReadStdin
+ 2021-01-18 422f38fb6c [dev.regabi] cmd/compile: move stack objects to liveness
+ 2021-01-18 6113db0bb4 [dev.regabi] cmd/compile: convert OPANIC argument to interface{} during typecheck
+ 2021-01-18 4c835f9169 [dev.regabi] cmd/compile: use LinksymOffsetExpr in TypePtr/ItabAddr
+ 2021-01-18 0ffa1ead6e [dev.regabi] cmd/compile: use *obj.LSym instead of *ir.Name for staticdata functions
+ 2021-01-17 7e0fa38aad [dev.regabi] cmd/compile: remove unneeded packages from ir.Pkgs
+ 2021-01-17 99a5db11ac [dev.regabi] cmd/compile: use LinksymOffsetExpr in walkConvInterface
+ 2021-01-17 87845d14f9 [dev.regabi] cmd/compile: add ir.TailCallStmt
+ 2021-01-17 e3027c6828 [dev.regabi] cmd/compile: fix linux-amd64-noopt builder
+ 2021-01-17 59ff93fe64 [dev.regabi] cmd/compile: rename NameOffsetExpr to LinksymOffsetExpr
+ 2021-01-17 82b9cae700 [dev.regabi] cmd/compile: change ir.NameOffsetExpr to use *obj.LSym instead of *Name
+ 2021-01-17 88956fc4b1 [dev.regabi] cmd/compile: stop analyze NameOffsetExpr.Name_ in escape analysis
+ 2021-01-17 7ce2a8383d [dev.regabi] cmd/compile: simplify stack temp initialization
+ 2021-01-17 ba0e8a92fa [dev.regabi] cmd/compile: refactor temp construction in walk
+ 2021-01-17 78e5aabcdb [dev.regabi] cmd/compile: replace Node.HasCall with walk.mayCall
+ 2021-01-16 6de9423445 [dev.regabi] cmd/compile: cleanup OAS2FUNC ordering
+ 2021-01-16 a956a0e909 [dev.regabi] cmd/compile, runtime: fix up comments/error messages from recent renames
+ 2021-01-16 ab3b67abfd [dev.regabi] cmd/compile: remove ONEWOBJ
+ 2021-01-16 c9b1445ac8 [dev.regabi] cmd/compile: remove TypeAssertExpr {Src,Dst}Type fields
+ 2021-01-15 682a1d2176 runtime: detect errors in DuplicateHandle
+ 2021-01-15 9f83418b83 cmd/link: remove GOROOT write in TestBuildForTvOS
+ 2021-01-15 ec9470162f cmd/compile: allow embed into any string or byte slice type
+ 2021-01-15 54198b04db cmd/compile: disallow embed of var inside func
+ 2021-01-15 b386c735e7 cmd/go: fix go generate docs
+ 2021-01-15 bb5075a525 syscall: remove RtlGenRandom and move it into internal/syscall
+ 2021-01-15 1deae0b597 os: invoke processKiller synchronously in testKillProcess
+ 2021-01-15 03a875137f [dev.regabi] cmd/compile: unexport reflectdata.WriteType
+ 2021-01-15 14537e6e54 [dev.regabi] cmd/compile: move stkobj symbol generation to SSA
+ 2021-01-15 ab523fc510 [dev.regabi] cmd/compile: don't promote Byval CaptureVars if Addrtaken
+ 2021-01-15 ff196c3e84 crypto/x509: update iOS bundled roots to version 55188.40.9
+ 2021-01-15 b7a698c73f [dev.regabi] test: disable test on windows because expected contains path separators.
+ 2021-01-15 4be7af23f9 [dev.regabi] cmd/compile: fix ICE during ir.Dump
+ 2021-01-14 e125ccd10e cmd/go: in 'go mod edit', validate versions given to -retract and -exclude
+ 2021-01-14 eb330020dc cmd/dist, cmd/go: pass -arch for C compilation on Darwin
+ 2021-01-14 84e8a06f62 cmd/cgo: remove unnecessary space in cgo export header
+ 2021-01-14 0c86b999c3 cmd/test2json: document passing -test.paniconexit0
+ 2021-01-14 9135795891 cmd/go/internal/load: report positions for embed errors
+ 2021-01-14 35b9c66601 [dev.regabi] cmd/compile,cmd/link: additional code review suggestions for CL 270863
+ 2021-01-14 d9b79e53bb cmd/compile: fix wrong complement for arm64 floating-point comparisons
+ 2021-01-14 c73232d08f cmd/go/internal/load: refactor setErrorPos to PackageError.setPos
+ 2021-01-14 6aa28d3e06 go/build: report positions for go:embed directives
+ 2021-01-14 9734fd482d [dev.regabi] cmd/compile: use node walked flag to prevent double walk for walkSwitch
+ 2021-01-14 f97983249a [dev.regabi] cmd/compile: move more PAUTOHEAP to SSA construction
+ 2021-01-14 4476300425 [dev.regabi] cmd/compile: use byte for CallExpr.Use
+ 2021-01-14 5a5ab24689 [dev.regabi] cmd/compile: do not rely on CallExpr.Rargs for detect already walked calls
+ 2021-01-14 983ac4b086 [dev.regabi] cmd/compile: fix ICE when initializing blank vars
+ 2021-01-13 7eb31d999c cmd/go: add hints to more missing sum error messages
+ 2021-01-13 d6d4673728 [dev.regabi] cmd/compile: fix GOEXPERIMENT=regabi builder
+ 2021-01-13 c41b999ad4 [dev.regabi] cmd/compile: refactor abiutils from "gc" into new "abi"
+ 2021-01-13 861707a8c8 [dev.regabi] cmd/compile: added limited //go:registerparams pragma for new ABI dev
+ 2021-01-13 c1370e918f [dev.regabi] cmd/compile: add code to support register ABI spills around morestack calls
+ 2021-01-13 2abd24f3b7 [dev.regabi] test: make run.go error messages slightly more informative
+ 2021-01-13 9a19481acb [dev.regabi] cmd/compile: make ordering for InvertFlags more stable
+ 2021-01-12 ba76567bc2 cmd/go/internal/modload: delete unused *mvsReqs.next method
+ 2021-01-12 665def2c11 encoding/asn1: document unmarshaling behavior for IMPLICIT string fields
+ 2021-01-11 81ea89adf3 cmd/go: fix non-script staleness checks interacting badly with GOFLAGS
+ 2021-01-11 759309029f doc: update editors.html for Go 1.16
+ 2021-01-11 c3b4c7093a cmd/internal/objfile: don't require runtime.symtab symbol for XCOFF
+ 2021-01-08 59bfc18e34 cmd/go: add hint to read 'go help vcs' to GOVCS errors
+ 2021-01-08 cd6f3a54e4 cmd/go: revise 'go help' documentation for modules
+ 2021-01-08 6192b98751 cmd/go: make hints in error messages more consistent
+ 2021-01-08 25886cf4bd cmd/go: preserve sums for indirect deps fetched by 'go mod download'
+ 2021-01-08 6250833911 runtime/metrics: mark histogram metrics as cumulative
+ 2021-01-08 8f6a9acbb3 runtime/metrics: remove unused StopTheWorld Description field
+ 2021-01-08 6598c65646 cmd/compile: fix exponential-time init-cycle reporting
+ 2021-01-08 fefad1dc85 test: fix timeout code for invoking compiler
+ 2021-01-08 6728118e0a cmd/go: pass signals forward during "go tool"
+ 2021-01-08 e65c543f3c go/build/constraint: add parser for build tag constraint expressions
+ 2021-01-08 0c5afc4fb7 testing/fstest,os: clarify racy behavior of TestFS
+ 2021-01-08 32afcc9436 runtime/metrics: change unit on *-by-size metrics to match bucket unit
+ 2021-01-08 c6513bca5a io/fs: minor corrections to Glob doc
+ 2021-01-08 304f769ffc cmd/compile: don't short-circuit copies whose source is volatile
+ 2021-01-08 ae97717133 runtime,runtime/metrics: use explicit histogram boundaries
+ 2021-01-08 a9ccd2d795 go/build: skip string literal while findEmbed
+ 2021-01-08 d92f8add32 archive/tar: fix typo in comment
+ 2021-01-08 cab1202183 cmd/link: accept extra blocks in TestFallocate
+ 2021-01-08 ee4d32249b io/fs: minor corrections to Glob release date
+ 2021-01-08 54bd1ccce2 cmd: update to latest golang.org/x/tools
+ 2021-01-07 9ec21a8f34 Revert "reflect: support multiple keys in struct tags"
+ 2021-01-07 091414b5b7 io/fs: correct WalkDirFunc documentation
+ 2021-01-07 9b55088d6b doc/go1.16: add release note for disallowing non-ASCII import paths
+ 2021-01-07 fa90aaca7d cmd/compile: fix late expand_calls leaf type for OpStructSelect/OpArraySelect
+ 2021-01-07 7cee66d4cb cmd/go: add documentation for Embed fields in go list output
+ 2021-01-07 e60cffa4ca html/template: attach functions to namespace
+ 2021-01-07 6da2d3b7d7 cmd/link: fix typo in asm.go
+ 2021-01-07 df81a15819 runtime: check mips64 VDSO clock_gettime return code
+ 2021-01-06 4787e906cf crypto/x509: rollback new CertificateRequest fields
+ 2021-01-06 c9658bee93 cmd/go: make module suggestion more friendly
+ 2021-01-06 4c668b25c6 runtime/metrics: fix panic message for Float64Histogram
+ 2021-01-06 d2131704a6 net/http/httputil: fix deadlock in DumpRequestOut
+ 2021-01-05 3e1e13ce6d cmd/go: set cfg.BuildMod to "readonly" by default with no module root
+ 2021-01-05 0b0d004983 cmd/go: pass embedcfg to gccgo if supported
+ 2021-01-05 1b85e7c057 cmd/go: don't scan gccgo standard library packages for imports
+ 2021-01-05 6b37b15d95 runtime: don't take allglock in tracebackothers
+ 2021-01-04 9eef49cfa6 math/rand: fix typo in comment
+ 2021-01-04 b01fb2af9e testing/fstest: fix typo in error message
+ 2021-01-01 3dd5867605 doc: 2021 is the Year of the Gopher
+ 2020-12-31 95ce805d14 io/fs: remove darwin/arm64 special condition
+ 2020-12-30 20d0991b86 lib/time, time/tzdata: update tzdata to 2020f
+ 2020-12-30 ed301733bb misc/cgo/testcarchive: remove special flags for Darwin/ARM
+ 2020-12-30 0ae2e032f2 misc/cgo/test: enable TestCrossPackageTests on darwin/arm64
+ 2020-12-29 780b4de16b misc/ios: fix wording for command line instructions
+ 2020-12-29 b4a71c95d2 doc/go1.16: reference misc/ios/README for how to build iOS programs
+ 2020-12-29 f83e0f6616 misc/ios: add to README how to build ios executables
+ 2020-12-28 4fd9455882 io/fs: fix typo in comment

Change-Id: If24bb93f1e1e7deb1d92ba223c85940ab93b2732

16 files changed:
1  2 
src/cmd/compile/internal/base/flag.go
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/noder/decl.go
src/cmd/compile/internal/noder/import.go
src/cmd/compile/internal/noder/noder.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/typecheck/dcl.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/subr.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/types2/stdlib_test.go
src/cmd/compile/internal/walk/walk.go
src/cmd/internal/obj/link.go
src/reflect/all_test.go
test/fixedbugs/issue43762.go
test/run.go

index 3602fb947df8e6005935ae4082ae2915944ef9e9,c38bbe627210dd11e3267031e8a824a376d7d1d0..d8ca9885cb4ff95b02bef6349920afa28b8a8f59
@@@ -54,7 -54,6 +54,7 @@@ type CmdFlags struct 
        C CountFlag    "help:\"disable printing of columns in error messages\""
        D string       "help:\"set relative `path` for local imports\""
        E CountFlag    "help:\"debug symbol export\""
 +      G CountFlag    "help:\"accept generic code\""
        I func(string) "help:\"add `directory` to import search path\""
        K CountFlag    "help:\"debug missing line numbers\""
        L CountFlag    "help:\"show full file names in error messages\""
@@@ -175,7 -174,7 +175,7 @@@ func ParseFlags() 
        if (*Flag.Shared || *Flag.Dynlink || *Flag.LinkShared) && !Ctxt.Arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X) {
                log.Fatalf("%s/%s does not support -shared", objabi.GOOS, objabi.GOARCH)
        }
-       parseSpectre(Flag.Spectre) // left as string for recordFlags
+       parseSpectre(Flag.Spectre) // left as string for RecordFlags
  
        Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
        Ctxt.Flag_optimize = Flag.N == 0
index 6f5f6499ced51154c4530ba77048ff3a9a61aa61,83f6740a48d1dc96589b8ae89016a0bec622f62c..f0be169f561deb84513c46fe0eec7b4aebf27fe1
@@@ -4,7 -4,7 +4,7 @@@
  //
  // The inlining facility makes 2 passes: first caninl determines which
  // functions are suitable for inlining, and for those that are it
- // saves a copy of the body. Then inlcalls walks each function body to
+ // saves a copy of the body. Then InlineCalls walks each function body to
  // expand calls to inlinable functions.
  //
  // The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
@@@ -27,7 -27,6 +27,6 @@@
  package inline
  
  import (
-       "errors"
        "fmt"
        "go/constant"
        "strings"
@@@ -74,12 -73,12 +73,12 @@@ func InlinePackage() 
        })
  }
  
- // Caninl determines whether fn is inlineable.
+ // CanInline determines whether fn is inlineable.
  // If so, CanInline saves fn->nbody in fn->inl and substitutes it with a copy.
  // fn and ->nbody will already have been typechecked.
  func CanInline(fn *ir.Func) {
        if fn.Nname == nil {
-               base.Fatalf("caninl no nname %+v", fn)
+               base.Fatalf("CanInline no nname %+v", fn)
        }
  
        var reason string // reason, if any, that the function was not inlined
        }
  
        if fn.Typecheck() == 0 {
-               base.Fatalf("caninl on non-typechecked function %v", fn)
+               base.Fatalf("CanInline on non-typechecked function %v", fn)
        }
  
        n := fn.Nname
        visitor := hairyVisitor{
                budget:        inlineMaxBudget,
                extraCallCost: cc,
-               usedLocals:    make(map[*ir.Name]bool),
        }
        if visitor.tooHairy(fn) {
                reason = visitor.reason
        n.Func.Inl = &ir.Inline{
                Cost: inlineMaxBudget - visitor.budget,
                Dcl:  pruneUnusedAutos(n.Defn.(*ir.Func).Dcl, &visitor),
-               Body: ir.DeepCopyList(src.NoXPos, fn.Body),
+               Body: inlcopylist(fn.Body),
        }
  
        if base.Flag.LowerM > 1 {
@@@ -200,11 -198,11 +198,11 @@@ func Inline_Flood(n *ir.Name, exportsy
                return
        }
        if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
-               base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class)
+               base.Fatalf("Inline_Flood: unexpected %v, %v, %v", n, n.Op(), n.Class)
        }
        fn := n.Func
        if fn == nil {
-               base.Fatalf("inlFlood: missing Func on %v", n)
+               base.Fatalf("Inline_Flood: missing Func on %v", n)
        }
        if fn.Inl == nil {
                return
  
        typecheck.ImportedBody(fn)
  
-       // Recursively identify all referenced functions for
-       // reexport. We want to include even non-called functions,
-       // because after inlining they might be callable.
-       ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
+       var doFlood func(n ir.Node)
+       doFlood = func(n ir.Node) {
                switch n.Op() {
                case ir.OMETHEXPR, ir.ODOTMETH:
                        Inline_Flood(ir.MethodExprName(n), exportsym)
                        // Okay, because we don't yet inline indirect
                        // calls to method values.
                case ir.OCLOSURE:
-                       // If the closure is inlinable, we'll need to
-                       // flood it too. But today we don't support
-                       // inlining functions that contain closures.
-                       //
-                       // When we do, we'll probably want:
-                       //     inlFlood(n.Func.Closure.Func.Nname)
-                       base.Fatalf("unexpected closure in inlinable function")
+                       // VisitList doesn't visit closure bodies, so force a
+                       // recursive call to VisitList on the body of the closure.
+                       ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood)
                }
-       })
+       }
+       // Recursively identify all referenced functions for
+       // reexport. We want to include even non-called functions,
+       // because after inlining they might be callable.
+       ir.VisitList(ir.Nodes(fn.Inl.Body), doFlood)
  }
  
  // hairyVisitor visits a function body to determine its inlining
@@@ -256,18 -253,13 +253,13 @@@ type hairyVisitor struct 
        budget        int32
        reason        string
        extraCallCost int32
-       usedLocals    map[*ir.Name]bool
-       do            func(ir.Node) error
+       usedLocals    ir.NameSet
+       do            func(ir.Node) bool
  }
  
- var errBudget = errors.New("too expensive")
  func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
        v.do = v.doNode // cache closure
-       err := errChildren(fn, v.do)
-       if err != nil {
-               v.reason = err.Error()
+       if ir.DoChildren(fn, v.do) {
                return true
        }
        if v.budget < 0 {
        return false
  }
  
- func (v *hairyVisitor) doNode(n ir.Node) error {
+ func (v *hairyVisitor) doNode(n ir.Node) bool {
        if n == nil {
-               return nil
+               return false
        }
        switch n.Op() {
        // Call is okay if inlinable and we have the budget for the body.
        case ir.OCALLFUNC:
                        if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
                                fn := name.Sym().Name
                                if fn == "getcallerpc" || fn == "getcallersp" {
-                                       return errors.New("call to " + fn)
+                                       v.reason = "call to " + fn
+                                       return true
                                }
                                if fn == "throw" {
                                        v.budget -= inlineExtraThrowCost
                v.budget -= v.extraCallCost
  
        case ir.OPANIC:
+               n := n.(*ir.UnaryExpr)
+               if n.X.Op() == ir.OCONVIFACE && n.X.(*ir.ConvExpr).Implicit() {
+                       // Hack to keep reflect.flag.mustBe inlinable for TestIntendedInlining.
+                       // Before CL 284412, these conversions were introduced later in the
+                       // compiler, so they didn't count against inlining budget.
+                       v.budget++
+               }
                v.budget -= inlineExtraPanicCost
  
        case ir.ORECOVER:
                // recover matches the argument frame pointer to find
                // the right panic value, so it needs an argument frame.
-               return errors.New("call to recover")
+               v.reason = "call to recover"
+               return true
+       case ir.OCLOSURE:
++              // TODO(danscales,mdempsky): Get working with -G.
++              // Probably after #43818 is fixed.
++              if base.Flag.G > 0 {
++                      v.reason = "inlining closures not yet working with -G"
++                      return true
++              }
 +
-       case ir.OCLOSURE,
-               ir.ORANGE,
+               // TODO(danscales) - fix some bugs when budget is lowered below 30
+               // Maybe make budget proportional to number of closure variables, e.g.:
+               //v.budget -= int32(len(n.(*ir.ClosureExpr).Func.ClosureVars) * 3)
+               v.budget -= 30
+       case ir.ORANGE,
                ir.OSELECT,
                ir.OGO,
                ir.ODEFER,
                ir.ODCLTYPE, // can't print yet
-               ir.ORETJMP:
-               return errors.New("unhandled op " + n.Op().String())
+               ir.OTAILCALL:
+               v.reason = "unhandled op " + n.Op().String()
+               return true
  
        case ir.OAPPEND:
                v.budget -= inlineExtraAppendCost
  
        case ir.ODCLCONST, ir.OFALL:
                // These nodes don't produce code; omit from inlining budget.
-               return nil
+               return false
  
        case ir.OFOR, ir.OFORUNTIL:
                n := n.(*ir.ForStmt)
                if n.Label != nil {
-                       return errors.New("labeled control")
+                       v.reason = "labeled control"
+                       return true
                }
        case ir.OSWITCH:
                n := n.(*ir.SwitchStmt)
                if n.Label != nil {
-                       return errors.New("labeled control")
+                       v.reason = "labeled control"
+                       return true
                }
        // case ir.ORANGE, ir.OSELECT in "unhandled" above
  
                if ir.IsConst(n.Cond, constant.Bool) {
                        // This if and the condition cost nothing.
                        // TODO(rsc): It seems strange that we visit the dead branch.
-                       if err := errList(n.Init(), v.do); err != nil {
-                               return err
-                       }
-                       if err := errList(n.Body, v.do); err != nil {
-                               return err
-                       }
-                       if err := errList(n.Else, v.do); err != nil {
-                               return err
-                       }
-                       return nil
+                       return doList(n.Init(), v.do) ||
+                               doList(n.Body, v.do) ||
+                               doList(n.Else, v.do)
                }
  
        case ir.ONAME:
                n := n.(*ir.Name)
                if n.Class == ir.PAUTO {
-                       v.usedLocals[n] = true
+                       v.usedLocals.Add(n)
                }
  
        case ir.OBLOCK:
  
        // When debugging, don't stop early, to get full cost of inlining this function
        if v.budget < 0 && base.Flag.LowerM < 2 && !logopt.Enabled() {
-               return errBudget
+               v.reason = "too expensive"
+               return true
        }
  
-       return errChildren(n, v.do)
+       return ir.DoChildren(n, v.do)
  }
  
  func isBigFunc(fn *ir.Func) bool {
        })
  }
  
+ // inlcopylist (together with inlcopy) recursively copies a list of nodes, except
+ // that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
+ // the body and dcls of an inlineable function.
+ func inlcopylist(ll []ir.Node) []ir.Node {
+       s := make([]ir.Node, len(ll))
+       for i, n := range ll {
+               s[i] = inlcopy(n)
+       }
+       return s
+ }
+ // inlcopy is like DeepCopy(), but does extra work to copy closures.
+ func inlcopy(n ir.Node) ir.Node {
+       var edit func(ir.Node) ir.Node
+       edit = func(x ir.Node) ir.Node {
+               switch x.Op() {
+               case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.ONIL:
+                       return x
+               }
+               m := ir.Copy(x)
+               ir.EditChildren(m, edit)
+               if x.Op() == ir.OCLOSURE {
+                       x := x.(*ir.ClosureExpr)
+                       // Need to save/duplicate x.Func.Nname,
+                       // x.Func.Nname.Ntype, x.Func.Dcl, x.Func.ClosureVars, and
+                       // x.Func.Body for iexport and local inlining.
+                       oldfn := x.Func
+                       newfn := ir.NewFunc(oldfn.Pos())
+                       if oldfn.ClosureCalled() {
+                               newfn.SetClosureCalled(true)
+                       }
+                       m.(*ir.ClosureExpr).Func = newfn
+                       newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym())
+                       // XXX OK to share fn.Type() ??
+                       newfn.Nname.SetType(oldfn.Nname.Type())
+                       newfn.Nname.Ntype = inlcopy(oldfn.Nname.Ntype).(ir.Ntype)
+                       newfn.Body = inlcopylist(oldfn.Body)
+                       // Make shallow copy of the Dcl and ClosureVar slices
+                       newfn.Dcl = append([]*ir.Name(nil), oldfn.Dcl...)
+                       newfn.ClosureVars = append([]*ir.Name(nil), oldfn.ClosureVars...)
+               }
+               return m
+       }
+       return edit(n)
+ }
  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
  // calls made to inlineable functions. This is the external entry point.
  func InlineCalls(fn *ir.Func) {
@@@ -762,13 -810,6 +817,6 @@@ func mkinlcall(n *ir.CallExpr, fn *ir.F
                if ln.Class == ir.PPARAMOUT { // return values handled below.
                        continue
                }
-               if ir.IsParamStackCopy(ln) { // ignore the on-stack copy of a parameter that moved to the heap
-                       // TODO(mdempsky): Remove once I'm confident
-                       // this never actually happens. We currently
-                       // perform inlining before escape analysis, so
-                       // nothing should have moved to the heap yet.
-                       base.Fatalf("impossible: %v", ln)
-               }
                inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
                inlvars[ln] = inlf
                if base.Flag.GenDwarfInl > 0 {
                inlvars:      inlvars,
                bases:        make(map[*src.PosBase]*src.PosBase),
                newInlIndex:  newIndex,
+               fn:           fn,
        }
        subst.edit = subst.node
  
@@@ -1031,6 -1073,12 +1080,12 @@@ type inlsubst struct 
        newInlIndex int
  
        edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
+       // If non-nil, we are inside a closure inside the inlined function, and
+       // newclofn is the Func of the new inlined closure.
+       newclofn *ir.Func
+       fn *ir.Func // For debug -- the func that is being inlined
  }
  
  // list inlines a list of nodes.
@@@ -1042,6 -1090,157 +1097,157 @@@ func (subst *inlsubst) list(ll ir.Nodes
        return s
  }
  
+ // fields returns a list of the fields of a struct type representing receiver,
+ // params, or results, after duplicating the field nodes and substituting the
+ // Nname nodes inside the field nodes.
+ func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
+       oldfields := oldt.FieldSlice()
+       newfields := make([]*types.Field, len(oldfields))
+       for i := range oldfields {
+               newfields[i] = oldfields[i].Copy()
+               if oldfields[i].Nname != nil {
+                       newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
+               }
+       }
+       return newfields
+ }
+ // clovar creates a new ONAME node for a local variable or param of a closure
+ // inside a function being inlined.
+ func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
+       // TODO(danscales): want to get rid of this shallow copy, with code like the
+       // following, but it is hard to copy all the necessary flags in a maintainable way.
+       // m := ir.NewNameAt(n.Pos(), n.Sym())
+       // m.Class = n.Class
+       // m.SetType(n.Type())
+       // m.SetTypecheck(1)
+       //if n.IsClosureVar() {
+       //      m.SetIsClosureVar(true)
+       //}
+       m := &ir.Name{}
+       *m = *n
+       m.Curfn = subst.newclofn
+       if n.Defn != nil && n.Defn.Op() == ir.ONAME {
+               if !n.IsClosureVar() {
+                       base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
+               }
+               if n.Sym().Pkg != types.LocalPkg {
+                       // If the closure came from inlining a function from
+                       // another package, must change package of captured
+                       // variable to localpkg, so that the fields of the closure
+                       // struct are local package and can be accessed even if
+                       // name is not exported. If you disable this code, you can
+                       // reproduce the problem by running 'go test
+                       // go/internal/srcimporter'. TODO(mdempsky) - maybe change
+                       // how we create closure structs?
+                       m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
+               }
+               // Make sure any inlvar which is the Defn
+               // of an ONAME closure var is rewritten
+               // during inlining. Don't substitute
+               // if Defn node is outside inlined function.
+               if subst.inlvars[n.Defn.(*ir.Name)] != nil {
+                       m.Defn = subst.node(n.Defn)
+               }
+       }
+       if n.Outer != nil {
+               // Either the outer variable is defined in function being inlined,
+               // and we will replace it with the substituted variable, or it is
+               // defined outside the function being inlined, and we should just
+               // skip the outer variable (the closure variable of the function
+               // being inlined).
+               s := subst.node(n.Outer).(*ir.Name)
+               if s == n.Outer {
+                       s = n.Outer.Outer
+               }
+               m.Outer = s
+       }
+       return m
+ }
+ // closure does the necessary substitions for a ClosureExpr n and returns the new
+ // closure node.
+ func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
+       m := ir.Copy(n)
+       m.SetPos(subst.updatedPos(m.Pos()))
+       ir.EditChildren(m, subst.edit)
+       //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
+       // The following is similar to funcLit
+       oldfn := n.Func
+       newfn := ir.NewFunc(oldfn.Pos())
+       // These three lines are not strictly necessary, but just to be clear
+       // that new function needs to redo typechecking and inlinability.
+       newfn.SetTypecheck(0)
+       newfn.SetInlinabilityChecked(false)
+       newfn.Inl = nil
+       newfn.SetIsHiddenClosure(true)
+       newfn.Nname = ir.NewNameAt(n.Pos(), ir.BlankNode.Sym())
+       newfn.Nname.Func = newfn
+       newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype)
+       newfn.Nname.Defn = newfn
+       m.(*ir.ClosureExpr).Func = newfn
+       newfn.OClosure = m.(*ir.ClosureExpr)
+       if subst.newclofn != nil {
+               //fmt.Printf("Inlining a closure with a nested closure\n")
+       }
+       prevxfunc := subst.newclofn
+       // Mark that we are now substituting within a closure (within the
+       // inlined function), and create new nodes for all the local
+       // vars/params inside this closure.
+       subst.newclofn = newfn
+       newfn.Dcl = nil
+       newfn.ClosureVars = nil
+       for _, oldv := range oldfn.Dcl {
+               newv := subst.clovar(oldv)
+               subst.inlvars[oldv] = newv
+               newfn.Dcl = append(newfn.Dcl, newv)
+       }
+       for _, oldv := range oldfn.ClosureVars {
+               newv := subst.clovar(oldv)
+               subst.inlvars[oldv] = newv
+               newfn.ClosureVars = append(newfn.ClosureVars, newv)
+       }
+       // Need to replace ONAME nodes in
+       // newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
+       oldt := oldfn.Type()
+       newrecvs := subst.fields(oldt.Recvs())
+       var newrecv *types.Field
+       if len(newrecvs) > 0 {
+               newrecv = newrecvs[0]
+       }
+       newt := types.NewSignature(oldt.Pkg(), newrecv,
+               subst.fields(oldt.Params()), subst.fields(oldt.Results()))
+       newfn.Nname.SetType(newt)
+       newfn.Body = subst.list(oldfn.Body)
+       // Remove the nodes for the current closure from subst.inlvars
+       for _, oldv := range oldfn.Dcl {
+               delete(subst.inlvars, oldv)
+       }
+       for _, oldv := range oldfn.ClosureVars {
+               delete(subst.inlvars, oldv)
+       }
+       // Go back to previous closure func
+       subst.newclofn = prevxfunc
+       // Actually create the named function for the closure, now that
+       // the closure is inlined in a specific function.
+       m.SetTypecheck(0)
+       if oldfn.ClosureCalled() {
+               typecheck.Callee(m)
+       } else {
+               typecheck.Expr(m)
+       }
+       return m
+ }
  // node recursively copies a node from the saved pristine body of the
  // inlined function, substituting references to input/output
  // parameters with ones to the tmpnames, and substituting returns with
@@@ -1056,13 -1255,17 +1262,17 @@@ func (subst *inlsubst) node(n ir.Node) 
                n := n.(*ir.Name)
  
                // Handle captured variables when inlining closures.
-               if n.IsClosureVar() {
+               if n.IsClosureVar() && subst.newclofn == nil {
                        o := n.Outer
  
+                       // Deal with case where sequence of closures are inlined.
+                       // TODO(danscales) - write test case to see if we need to
+                       // go up multiple levels.
+                       if o.Curfn != ir.CurFunc {
+                               o = o.Outer
+                       }
                        // make sure the outer param matches the inlining location
-                       // NB: if we enabled inlining of functions containing OCLOSURE or refined
-                       // the reassigned check via some sort of copy propagation this would most
-                       // likely need to be changed to a loop to walk up to the correct Param
                        if o == nil || o.Curfn != ir.CurFunc {
                                base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
                        }
                }
  
        case ir.ORETURN:
+               if subst.newclofn != nil {
+                       // Don't do special substitutions if inside a closure
+                       break
+               }
                // Since we don't handle bodies with closures,
                // this return is guaranteed to belong to the current inlined function.
                n := n.(*ir.ReturnStmt)
                return m
  
        case ir.OLABEL:
+               if subst.newclofn != nil {
+                       // Don't do special substitutions if inside a closure
+                       break
+               }
                n := n.(*ir.LabelStmt)
                m := ir.Copy(n).(*ir.LabelStmt)
                m.SetPos(subst.updatedPos(m.Pos()))
                p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
                m.Label = typecheck.Lookup(p)
                return m
-       }
  
-       if n.Op() == ir.OCLOSURE {
-               base.Fatalf("cannot inline function containing closure: %+v", n)
+       case ir.OCLOSURE:
+               return subst.closure(n.(*ir.ClosureExpr))
        }
  
        m := ir.Copy(n)
@@@ -1171,7 -1382,7 +1389,7 @@@ func pruneUnusedAutos(ll []*ir.Name, vi
        s := make([]*ir.Name, 0, len(ll))
        for _, n := range ll {
                if n.Class == ir.PAUTO {
-                       if _, found := vis.usedLocals[n]; !found {
+                       if !vis.usedLocals.Has(n) {
                                continue
                        }
                }
@@@ -1191,21 -1402,13 +1409,13 @@@ func numNonClosures(list []*ir.Func) in
        return count
  }
  
- // TODO(mdempsky): Update inl.go to use ir.DoChildren directly.
- func errChildren(n ir.Node, do func(ir.Node) error) (err error) {
-       ir.DoChildren(n, func(x ir.Node) bool {
-               err = do(x)
-               return err != nil
-       })
-       return
- }
- func errList(list []ir.Node, do func(ir.Node) error) error {
+ func doList(list []ir.Node, do func(ir.Node) bool) bool {
        for _, x := range list {
                if x != nil {
-                       if err := do(x); err != nil {
-                               return err
+                       if do(x) {
+                               return true
                        }
                }
        }
-       return nil
+       return false
  }
index 4d20f410bc832f6c713c6569d3c189bd96b88c23,0000000000000000000000000000000000000000..c41b77c1008c138ab66ede48e0f171030addae7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,226 -1,0 +1,228 @@@
-               if err := varEmbed(g.makeXPos, names[0], decl, pragma); err != nil {
-                       base.ErrorfAt(g.pos(decl), "%s", err.Error())
-               }
 +// Copyright 2021 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.
 +
 +package noder
 +
 +import (
 +      "cmd/compile/internal/base"
 +      "cmd/compile/internal/ir"
 +      "cmd/compile/internal/syntax"
 +      "cmd/compile/internal/typecheck"
 +      "cmd/compile/internal/types"
 +      "cmd/compile/internal/types2"
 +)
 +
 +// TODO(mdempsky): Skip blank declarations? Probably only safe
 +// for declarations without pragmas.
 +
 +func (g *irgen) decls(decls []syntax.Decl) []ir.Node {
 +      var res ir.Nodes
 +      for _, decl := range decls {
 +              switch decl := decl.(type) {
 +              case *syntax.ConstDecl:
 +                      g.constDecl(&res, decl)
 +              case *syntax.FuncDecl:
 +                      g.funcDecl(&res, decl)
 +              case *syntax.TypeDecl:
 +                      if ir.CurFunc == nil {
 +                              continue // already handled in irgen.generate
 +                      }
 +                      g.typeDecl(&res, decl)
 +              case *syntax.VarDecl:
 +                      g.varDecl(&res, decl)
 +              default:
 +                      g.unhandled("declaration", decl)
 +              }
 +      }
 +      return res
 +}
 +
 +func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
 +      // TODO(mdempsky): Merge with gcimports so we don't have to import
 +      // packages twice.
 +
 +      g.pragmaFlags(decl.Pragma, 0)
 +
 +      ipkg := importfile(decl)
 +      if ipkg == ir.Pkgs.Unsafe {
 +              p.importedUnsafe = true
 +      }
++      if ipkg.Path == "embed" {
++              p.importedEmbed = true
++      }
 +}
 +
 +func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
 +      g.pragmaFlags(decl.Pragma, 0)
 +
 +      for _, name := range decl.NameList {
 +              name, obj := g.def(name)
 +              name.SetVal(obj.(*types2.Const).Val())
 +              out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name))
 +      }
 +}
 +
 +func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
 +      fn := ir.NewFunc(g.pos(decl))
 +      fn.Nname, _ = g.def(decl.Name)
 +      fn.Nname.Func = fn
 +      fn.Nname.Defn = fn
 +
 +      fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas)
 +      if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
 +              base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
 +      }
 +
 +      if decl.Name.Value == "init" && decl.Recv == nil {
 +              g.target.Inits = append(g.target.Inits, fn)
 +      }
 +
 +      g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
 +
 +      out.Append(fn)
 +}
 +
 +func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
 +      if decl.Alias {
 +              if !types.AllowsGoVersion(types.LocalPkg, 1, 9) {
 +                      base.ErrorfAt(g.pos(decl), "type aliases only supported as of -lang=go1.9")
 +              }
 +
 +              name, _ := g.def(decl.Name)
 +              g.pragmaFlags(decl.Pragma, 0)
 +
 +              // TODO(mdempsky): This matches how typecheckdef marks aliases for
 +              // export, but this won't generalize to exporting function-scoped
 +              // type aliases. We should maybe just use n.Alias() instead.
 +              if ir.CurFunc == nil {
 +                      name.Sym().Def = ir.TypeNode(name.Type())
 +              }
 +
 +              out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
 +              return
 +      }
 +
 +      // Prevent size calculations until we set the underlying type.
 +      types.DeferCheckSize()
 +
 +      name, obj := g.def(decl.Name)
 +      ntyp, otyp := name.Type(), obj.Type()
 +      if ir.CurFunc != nil {
 +              typecheck.TypeGen++
 +              ntyp.Vargen = typecheck.TypeGen
 +      }
 +
 +      pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
 +      name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
 +
 +      if pragmas&ir.NotInHeap != 0 {
 +              ntyp.SetNotInHeap(true)
 +      }
 +
 +      // We need to use g.typeExpr(decl.Type) here to ensure that for
 +      // chained, defined-type declarations like
 +      //
 +      //      type T U
 +      //
 +      //      //go:notinheap
 +      //      type U struct { â€¦ }
 +      //
 +      // that we mark both T and U as NotInHeap. If we instead used just
 +      // g.typ(otyp.Underlying()), then we'd instead set T's underlying
 +      // type directly to the struct type (which is not marked NotInHeap)
 +      // and fail to mark T as NotInHeap.
 +      //
 +      // Also, we rely here on Type.SetUnderlying allowing passing a
 +      // defined type and handling forward references like from T to U
 +      // above. Contrast with go/types's Named.SetUnderlying, which
 +      // disallows this.
 +      //
 +      // [mdempsky: Subtleties like these are why I always vehemently
 +      // object to new type pragmas.]
 +      ntyp.SetUnderlying(g.typeExpr(decl.Type))
 +      types.ResumeCheckSize()
 +
 +      if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
 +              methods := make([]*types.Field, otyp.NumMethods())
 +              for i := range methods {
 +                      m := otyp.Method(i)
 +                      meth := g.obj(m)
 +                      methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
 +                      methods[i].Nname = meth
 +              }
 +              ntyp.Methods().Set(methods)
 +      }
 +
 +      out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
 +}
 +
 +func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
 +      pos := g.pos(decl)
 +      names := make([]*ir.Name, len(decl.NameList))
 +      for i, name := range decl.NameList {
 +              names[i], _ = g.def(name)
 +      }
 +      values := g.exprList(decl.Values)
 +
 +      if decl.Pragma != nil {
 +              pragma := decl.Pragma.(*pragmas)
++              // TODO(mdempsky): Plumb noder.importedEmbed through to here.
++              varEmbed(g.makeXPos, names[0], decl, pragma, true)
 +              g.reportUnused(pragma)
 +      }
 +
 +      var as2 *ir.AssignListStmt
 +      if len(values) != 0 && len(names) != len(values) {
 +              as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
 +      }
 +
 +      for i, name := range names {
 +              if ir.CurFunc != nil {
 +                      out.Append(ir.NewDecl(pos, ir.ODCL, name))
 +              }
 +              if as2 != nil {
 +                      as2.Lhs[i] = name
 +                      name.Defn = as2
 +              } else {
 +                      as := ir.NewAssignStmt(pos, name, nil)
 +                      if len(values) != 0 {
 +                              as.Y = values[i]
 +                              name.Defn = as
 +                      } else if ir.CurFunc == nil {
 +                              name.Defn = as
 +                      }
 +                      out.Append(typecheck.Stmt(as))
 +              }
 +      }
 +      if as2 != nil {
 +              out.Append(typecheck.Stmt(as2))
 +      }
 +}
 +
 +// pragmaFlags returns any specified pragma flags included in allowed,
 +// and reports errors about any other, unexpected pragmas.
 +func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
 +      if pragma == nil {
 +              return 0
 +      }
 +      p := pragma.(*pragmas)
 +      present := p.Flag & allowed
 +      p.Flag &^= allowed
 +      g.reportUnused(p)
 +      return present
 +}
 +
 +// reportUnused reports errors about any unused pragmas.
 +func (g *irgen) reportUnused(pragma *pragmas) {
 +      for _, pos := range pragma.Pos {
 +              if pos.Flag&pragma.Flag != 0 {
 +                      base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
 +              }
 +      }
 +      if len(pragma.Embeds) > 0 {
 +              for _, e := range pragma.Embeds {
 +                      base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")
 +              }
 +      }
 +}
index ac7bc8bbf03b8a83c25392874af00a6acc39df8c,ca041a156c14557417af426a4077b62461be3011..aa02c01cff9acdf39e98aec2e510ad40aa2ef041
@@@ -5,25 -5,20 +5,25 @@@
  package noder
  
  import (
 +      "errors"
        "fmt"
 -      "go/constant"
 +      "io"
        "os"
 -      "path"
 +      pathpkg "path"
        "runtime"
        "sort"
 +      "strconv"
        "strings"
        "unicode"
        "unicode/utf8"
  
        "cmd/compile/internal/base"
 +      "cmd/compile/internal/importer"
        "cmd/compile/internal/ir"
 +      "cmd/compile/internal/syntax"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
 +      "cmd/compile/internal/types2"
        "cmd/internal/archive"
        "cmd/internal/bio"
        "cmd/internal/goobj"
        "cmd/internal/src"
  )
  
 +// Temporary import helper to get type2-based type-checking going.
 +type gcimports struct {
 +      packages map[string]*types2.Package
 +}
 +
 +func (m *gcimports) Import(path string) (*types2.Package, error) {
 +      return m.ImportFrom(path, "" /* no vendoring */, 0)
 +}
 +
 +func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) {
 +      if mode != 0 {
 +              panic("mode must be 0")
 +      }
 +
 +      path, err := resolveImportPath(path)
 +      if err != nil {
 +              return nil, err
 +      }
 +
 +      lookup := func(path string) (io.ReadCloser, error) { return openPackage(path) }
 +      return importer.Import(m.packages, path, srcDir, lookup)
 +}
 +
  func isDriveLetter(b byte) bool {
        return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
  }
@@@ -66,152 -38,160 +66,152 @@@ func islocalname(name string) bool 
                strings.HasPrefix(name, "../") || name == ".."
  }
  
 -func findpkg(name string) (file string, ok bool) {
 -      if islocalname(name) {
 +func openPackage(path string) (*os.File, error) {
 +      if islocalname(path) {
                if base.Flag.NoLocalImports {
 -                      return "", false
 +                      return nil, errors.New("local imports disallowed")
                }
  
                if base.Flag.Cfg.PackageFile != nil {
 -                      file, ok = base.Flag.Cfg.PackageFile[name]
 -                      return file, ok
 +                      return os.Open(base.Flag.Cfg.PackageFile[path])
                }
  
 -              // try .a before .6.  important for building libraries:
 -              // if there is an array.6 in the array.a library,
 -              // want to find all of array.a, not just array.6.
 -              file = fmt.Sprintf("%s.a", name)
 -              if _, err := os.Stat(file); err == nil {
 -                      return file, true
 +              // try .a before .o.  important for building libraries:
 +              // if there is an array.o in the array.a library,
 +              // want to find all of array.a, not just array.o.
 +              if file, err := os.Open(fmt.Sprintf("%s.a", path)); err == nil {
 +                      return file, nil
                }
 -              file = fmt.Sprintf("%s.o", name)
 -              if _, err := os.Stat(file); err == nil {
 -                      return file, true
 +              if file, err := os.Open(fmt.Sprintf("%s.o", path)); err == nil {
 +                      return file, nil
                }
 -              return "", false
 +              return nil, errors.New("file not found")
        }
  
        // local imports should be canonicalized already.
        // don't want to see "encoding/../encoding/base64"
        // as different from "encoding/base64".
 -      if q := path.Clean(name); q != name {
 -              base.Errorf("non-canonical import path %q (should be %q)", name, q)
 -              return "", false
 +      if q := pathpkg.Clean(path); q != path {
 +              return nil, fmt.Errorf("non-canonical import path %q (should be %q)", path, q)
        }
  
        if base.Flag.Cfg.PackageFile != nil {
 -              file, ok = base.Flag.Cfg.PackageFile[name]
 -              return file, ok
 +              return os.Open(base.Flag.Cfg.PackageFile[path])
        }
  
        for _, dir := range base.Flag.Cfg.ImportDirs {
 -              file = fmt.Sprintf("%s/%s.a", dir, name)
 -              if _, err := os.Stat(file); err == nil {
 -                      return file, true
 +              if file, err := os.Open(fmt.Sprintf("%s/%s.a", dir, path)); err == nil {
 +                      return file, nil
                }
 -              file = fmt.Sprintf("%s/%s.o", dir, name)
 -              if _, err := os.Stat(file); err == nil {
 -                      return file, true
 +              if file, err := os.Open(fmt.Sprintf("%s/%s.o", dir, path)); err == nil {
 +                      return file, nil
                }
        }
  
        if objabi.GOROOT != "" {
                suffix := ""
 -              suffixsep := ""
                if base.Flag.InstallSuffix != "" {
 -                      suffixsep = "_"
 -                      suffix = base.Flag.InstallSuffix
 +                      suffix = "_" + base.Flag.InstallSuffix
                } else if base.Flag.Race {
 -                      suffixsep = "_"
 -                      suffix = "race"
 +                      suffix = "_race"
                } else if base.Flag.MSan {
 -                      suffixsep = "_"
 -                      suffix = "msan"
 +                      suffix = "_msan"
                }
  
 -              file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
 -              if _, err := os.Stat(file); err == nil {
 -                      return file, true
 +              if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffix, path)); err == nil {
 +                      return file, nil
                }
 -              file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
 -              if _, err := os.Stat(file); err == nil {
 -                      return file, true
 +              if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffix, path)); err == nil {
 +                      return file, nil
                }
        }
 -
 -      return "", false
 +      return nil, errors.New("file not found")
  }
  
  // myheight tracks the local package's height based on packages
  // imported so far.
  var myheight int
  
 -func importfile(f constant.Value) *types.Pkg {
 -      if f.Kind() != constant.String {
 -              base.Errorf("import path must be a string")
 -              return nil
 -      }
 -
 -      path_ := constant.StringVal(f)
 -      if len(path_) == 0 {
 -              base.Errorf("import path is empty")
 -              return nil
 -      }
 -
 -      if isbadimport(path_, false) {
 -              return nil
 -      }
 -
 +// resolveImportPath resolves an import path as it appears in a Go
 +// source file to the package's full path.
 +func resolveImportPath(path string) (string, error) {
        // The package name main is no longer reserved,
        // but we reserve the import path "main" to identify
        // the main package, just as we reserve the import
        // path "math" to identify the standard math package.
 -      if path_ == "main" {
 -              base.Errorf("cannot import \"main\"")
 -              base.ErrorExit()
 -      }
 -
 -      if base.Ctxt.Pkgpath != "" && path_ == base.Ctxt.Pkgpath {
 -              base.Errorf("import %q while compiling that package (import cycle)", path_)
 -              base.ErrorExit()
 +      if path == "main" {
 +              return "", errors.New("cannot import \"main\"")
        }
  
 -      if mapped, ok := base.Flag.Cfg.ImportMap[path_]; ok {
 -              path_ = mapped
 +      if base.Ctxt.Pkgpath != "" && path == base.Ctxt.Pkgpath {
 +              return "", fmt.Errorf("import %q while compiling that package (import cycle)", path)
        }
  
 -      if path_ == "unsafe" {
 -              return ir.Pkgs.Unsafe
 +      if mapped, ok := base.Flag.Cfg.ImportMap[path]; ok {
 +              path = mapped
        }
  
 -      if islocalname(path_) {
 -              if path_[0] == '/' {
 -                      base.Errorf("import path cannot be absolute path")
 -                      return nil
 +      if islocalname(path) {
 +              if path[0] == '/' {
 +                      return "", errors.New("import path cannot be absolute path")
                }
  
 -              prefix := base.Ctxt.Pathname
 -              if base.Flag.D != "" {
 -                      prefix = base.Flag.D
 +              prefix := base.Flag.D
 +              if prefix == "" {
 +                      // Questionable, but when -D isn't specified, historically we
 +                      // resolve local import paths relative to the directory the
 +                      // compiler's current directory, not the respective source
 +                      // file's directory.
 +                      prefix = base.Ctxt.Pathname
                }
 -              path_ = path.Join(prefix, path_)
 +              path = pathpkg.Join(prefix, path)
  
 -              if isbadimport(path_, true) {
 -                      return nil
 +              if err := checkImportPath(path, true); err != nil {
 +                      return "", err
                }
        }
  
 -      file, found := findpkg(path_)
 -      if !found {
 -              base.Errorf("can't find import: %q", path_)
 -              base.ErrorExit()
 +      return path, nil
 +}
 +
 +// TODO(mdempsky): Return an error instead.
 +func importfile(decl *syntax.ImportDecl) *types.Pkg {
 +      path, err := strconv.Unquote(decl.Path.Value)
 +      if err != nil {
 +              base.Errorf("import path must be a string")
 +              return nil
        }
  
 -      importpkg := types.NewPkg(path_, "")
 -      if importpkg.Imported {
 -              return importpkg
 +      if err := checkImportPath(path, false); err != nil {
 +              base.Errorf("%s", err.Error())
 +              return nil
 +      }
 +
 +      path, err = resolveImportPath(path)
 +      if err != nil {
 +              base.Errorf("%s", err)
 +              return nil
        }
  
 -      importpkg.Imported = true
 +      importpkg := types.NewPkg(path, "")
 +      if importpkg.Direct {
 +              return importpkg // already fully loaded
 +      }
 +      importpkg.Direct = true
 +      typecheck.Target.Imports = append(typecheck.Target.Imports, importpkg)
  
 -      imp, err := bio.Open(file)
 +      if path == "unsafe" {
 +              return importpkg // initialized with universe
 +      }
 +
 +      f, err := openPackage(path)
        if err != nil {
 -              base.Errorf("can't open import: %q: %v", path_, err)
 +              base.Errorf("could not import %q: %v", path, err)
                base.ErrorExit()
        }
 +      imp := bio.NewReader(f)
        defer imp.Close()
 +      file := f.Name()
  
        // check object header
        p, err := imp.ReadString('\n')
        var fingerprint goobj.FingerprintType
        switch c {
        case '\n':
 -              base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path_)
 +              base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path)
                return nil
  
        case 'B':
                if base.Debug.Export != 0 {
 -                      fmt.Printf("importing %s (%s)\n", path_, file)
 +                      fmt.Printf("importing %s (%s)\n", path, file)
                }
                imp.ReadByte() // skip \n after $$B
  
                fingerprint = typecheck.ReadImports(importpkg, imp)
  
        default:
 -              base.Errorf("no import in %q", path_)
 +              base.Errorf("no import in %q", path)
                base.ErrorExit()
        }
  
        // assume files move (get installed) so don't record the full path
        if base.Flag.Cfg.PackageFile != nil {
                // If using a packageFile map, assume path_ can be recorded directly.
 -              base.Ctxt.AddImport(path_, fingerprint)
 +              base.Ctxt.AddImport(path, fingerprint)
        } else {
                // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
 -              base.Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint)
 +              base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint)
        }
  
        if importpkg.Height >= myheight {
@@@ -335,37 -315,47 +335,37 @@@ var reservedimports = []string
        "type",
  }
  
 -func isbadimport(path string, allowSpace bool) bool {
 +func checkImportPath(path string, allowSpace bool) error {
 +      if path == "" {
 +              return errors.New("import path is empty")
 +      }
 +
        if strings.Contains(path, "\x00") {
 -              base.Errorf("import path contains NUL")
 -              return true
 +              return errors.New("import path contains NUL")
        }
  
        for _, ri := range reservedimports {
                if path == ri {
 -                      base.Errorf("import path %q is reserved and cannot be used", path)
 -                      return true
 +                      return fmt.Errorf("import path %q is reserved and cannot be used", path)
                }
        }
  
        for _, r := range path {
 -              if r == utf8.RuneError {
 -                      base.Errorf("import path contains invalid UTF-8 sequence: %q", path)
 -                      return true
 -              }
 -
 -              if r < 0x20 || r == 0x7f {
 -                      base.Errorf("import path contains control character: %q", path)
 -                      return true
 -              }
 -
 -              if r == '\\' {
 -                      base.Errorf("import path contains backslash; use slash: %q", path)
 -                      return true
 -              }
 -
 -              if !allowSpace && unicode.IsSpace(r) {
 -                      base.Errorf("import path contains space character: %q", path)
 -                      return true
 -              }
 -
 -              if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
 -                      base.Errorf("import path contains invalid character '%c': %q", r, path)
 -                      return true
 +              switch {
 +              case r == utf8.RuneError:
 +                      return fmt.Errorf("import path contains invalid UTF-8 sequence: %q", path)
 +              case r < 0x20 || r == 0x7f:
 +                      return fmt.Errorf("import path contains control character: %q", path)
 +              case r == '\\':
 +                      return fmt.Errorf("import path contains backslash; use slash: %q", path)
 +              case !allowSpace && unicode.IsSpace(r):
 +                      return fmt.Errorf("import path contains space character: %q", path)
 +              case strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r):
 +                      return fmt.Errorf("import path contains invalid character '%c': %q", r, path)
                }
        }
  
 -      return false
 +      return nil
  }
  
  func pkgnotused(lineno src.XPos, path string, name string) {
@@@ -428,7 -418,7 +428,7 @@@ func clearImports() 
                if types.IsDotAlias(s) {
                        // throw away top-level name left over
                        // from previous import . "x"
-                       // We'll report errors after type checking in checkDotImports.
+                       // We'll report errors after type checking in CheckDotImports.
                        s.Def = nil
                        continue
                }
index e1ae2569e0c97a149853b06cb506c117d94ca487,5bb01895cc9ea9a929bc0d14c9b444bb416289c1..887205b9fb0b9bcf1259368ecb05408c166961d8
@@@ -5,7 -5,6 +5,6 @@@
  package noder
  
  import (
-       "errors"
        "fmt"
        "go/constant"
        "go/token"
@@@ -18,7 -17,6 +17,7 @@@
        "unicode/utf8"
  
        "cmd/compile/internal/base"
 +      "cmd/compile/internal/dwarfgen"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/typecheck"
  
  func LoadPackage(filenames []string) {
        base.Timer.Start("fe", "parse")
 -      lines := ParseFiles(filenames)
 -      base.Timer.Stop()
 -      base.Timer.AddEvent(int64(lines), "lines")
 -
 -      // Typecheck.
 -      Package()
  
 -      // With all user code typechecked, it's now safe to verify unused dot imports.
 -      CheckDotImports()
 -      base.ExitIfErrors()
 -}
 +      mode := syntax.CheckBranches
 +      if base.Flag.G != 0 {
 +              mode |= syntax.AllowGenerics
 +      }
  
 -// ParseFiles concurrently parses files into *syntax.File structures.
 -// Each declaration in every *syntax.File is converted to a syntax tree
 -// and its root represented by *Node is appended to Target.Decls.
 -// Returns the total count of parsed lines.
 -func ParseFiles(filenames []string) uint {
 -      noders := make([]*noder, 0, len(filenames))
        // Limit the number of simultaneously open files.
        sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
  
 -      for _, filename := range filenames {
 -              p := &noder{
 -                      basemap:     make(map[*syntax.PosBase]*src.PosBase),
 +      noders := make([]*noder, len(filenames))
 +      for i, filename := range filenames {
 +              p := noder{
                        err:         make(chan syntax.Error),
                        trackScopes: base.Flag.Dwarf,
                }
 -              noders = append(noders, p)
 +              noders[i] = &p
  
 -              go func(filename string) {
 +              filename := filename
 +              go func() {
                        sem <- struct{}{}
                        defer func() { <-sem }()
                        defer close(p.err)
 -                      base := syntax.NewFileBase(filename)
 +                      fbase := syntax.NewFileBase(filename)
  
                        f, err := os.Open(filename)
                        if err != nil {
@@@ -60,8 -69,8 +59,8 @@@
                        }
                        defer f.Close()
  
 -                      p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
 -              }(filename)
 +                      p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // errors are tracked via p.error
 +              }()
        }
  
        var lines uint
                for e := range p.err {
                        p.errorAt(e.Pos, "%s", e.Msg)
                }
 +              lines += p.file.EOF.Line()
 +      }
 +      base.Timer.AddEvent(int64(lines), "lines")
  
 +      if base.Flag.G != 0 {
 +              // Use types2 to type-check and possibly generate IR.
 +              check2(noders)
 +              return
 +      }
 +
 +      for _, p := range noders {
                p.node()
 -              lines += p.file.Lines
                p.file = nil // release memory
 +      }
  
 -              if base.SyntaxErrors() != 0 {
 -                      base.ErrorExit()
 -              }
 -              // Always run CheckDclstack here, even when debug_dclstack is not set, as a sanity measure.
 -              types.CheckDclstack()
 +      if base.SyntaxErrors() != 0 {
 +              base.ErrorExit()
        }
 +      types.CheckDclstack()
  
        for _, p := range noders {
                p.processPragmas()
        }
  
 +      // Typecheck.
        types.LocalPkg.Height = myheight
 -
 -      return lines
 -}
 -
 -func Package() {
        typecheck.DeclareUniverse()
 -
        typecheck.TypecheckAllowed = true
  
        // Process top-level declarations in phases.
        for i := 0; i < len(typecheck.Target.Decls); i++ {
                n := typecheck.Target.Decls[i]
                if n.Op() == ir.ODCLFUNC {
+                       if base.Flag.W > 1 {
+                               s := fmt.Sprintf("\nbefore typecheck %v", n)
+                               ir.Dump(s, n)
+                       }
                        typecheck.FuncBody(n.(*ir.Func))
+                       if base.Flag.W > 1 {
+                               s := fmt.Sprintf("\nafter typecheck %v", n)
+                               ir.Dump(s, n)
+                       }
                        fcount++
                }
        }
        }
  
        // Phase 5: With all user code type-checked, it's now safe to verify map keys.
 +      // With all user code typechecked, it's now safe to verify unused dot imports.
        typecheck.CheckMapKeys()
 -
 -}
 -
 -// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase.
 -func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
 -      // fast path: most likely PosBase hasn't changed
 -      if p.basecache.last == b0 {
 -              return p.basecache.base
 -      }
 -
 -      b1, ok := p.basemap[b0]
 -      if !ok {
 -              fn := b0.Filename()
 -              if b0.IsFileBase() {
 -                      b1 = src.NewFileBase(fn, absFilename(fn))
 -              } else {
 -                      // line directive base
 -                      p0 := b0.Pos()
 -                      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
 -      }
 -
 -      // update cache
 -      p.basecache.last = b0
 -      p.basecache.base = b1
 -
 -      return b1
 -}
 -
 -func (p *noder) makeXPos(pos syntax.Pos) (_ src.XPos) {
 -      return base.Ctxt.PosTable.XPos(src.MakePos(p.makeSrcPosBase(pos.Base()), pos.Line(), pos.Col()))
 +      CheckDotImports()
 +      base.ExitIfErrors()
  }
  
  func (p *noder) errorAt(pos syntax.Pos, format string, args ...interface{}) {
@@@ -173,33 -221,31 +180,33 @@@ func absFilename(name string) string 
  
  // noder transforms package syntax's AST into a Node tree.
  type noder struct {
 -      basemap   map[*syntax.PosBase]*src.PosBase
 -      basecache struct {
 -              last *syntax.PosBase
 -              base *src.PosBase
 -      }
 +      posMap
  
        file           *syntax.File
        linknames      []linkname
        pragcgobuf     [][]string
        err            chan syntax.Error
 -      scope          ir.ScopeID
        importedUnsafe bool
        importedEmbed  bool
 +      trackScopes    bool
 +
 +      funcState *funcState
 +}
  
 -      // scopeVars is a stack tracking the number of variables declared in the
 -      // current function at the moment each open scope was opened.
 -      trackScopes bool
 -      scopeVars   []int
 +// funcState tracks all per-function state to make handling nested
 +// functions easier.
 +type funcState struct {
 +      // scopeVars is a stack tracking the number of variables declared in
 +      // the current function at the moment each open scope was opened.
 +      scopeVars []int
 +      marker    dwarfgen.ScopeMarker
  
        lastCloseScopePos syntax.Pos
  }
  
  func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
 -      oldScope := p.scope
 -      p.scope = 0
 +      outerFuncState := p.funcState
 +      p.funcState = new(funcState)
        typecheck.StartFuncBody(fn)
  
        if block != nil {
        }
  
        typecheck.FinishFuncBody()
 -      p.scope = oldScope
 +      p.funcState.marker.WriteTo(fn)
 +      p.funcState = outerFuncState
  }
  
  func (p *noder) openScope(pos syntax.Pos) {
 +      fs := p.funcState
        types.Markdcl()
  
        if p.trackScopes {
 -              ir.CurFunc.Parents = append(ir.CurFunc.Parents, p.scope)
 -              p.scopeVars = append(p.scopeVars, len(ir.CurFunc.Dcl))
 -              p.scope = ir.ScopeID(len(ir.CurFunc.Parents))
 -
 -              p.markScope(pos)
 +              fs.scopeVars = append(fs.scopeVars, len(ir.CurFunc.Dcl))
 +              fs.marker.Push(p.makeXPos(pos))
        }
  }
  
  func (p *noder) closeScope(pos syntax.Pos) {
 -      p.lastCloseScopePos = pos
 +      fs := p.funcState
 +      fs.lastCloseScopePos = pos
        types.Popdcl()
  
        if p.trackScopes {
 -              scopeVars := p.scopeVars[len(p.scopeVars)-1]
 -              p.scopeVars = p.scopeVars[:len(p.scopeVars)-1]
 +              scopeVars := fs.scopeVars[len(fs.scopeVars)-1]
 +              fs.scopeVars = fs.scopeVars[:len(fs.scopeVars)-1]
                if scopeVars == len(ir.CurFunc.Dcl) {
                        // no variables were declared in this scope, so we can retract it.
 -
 -                      if int(p.scope) != len(ir.CurFunc.Parents) {
 -                              base.Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted")
 -                      }
 -
 -                      p.scope = ir.CurFunc.Parents[p.scope-1]
 -                      ir.CurFunc.Parents = ir.CurFunc.Parents[:len(ir.CurFunc.Parents)-1]
 -
 -                      nmarks := len(ir.CurFunc.Marks)
 -                      ir.CurFunc.Marks[nmarks-1].Scope = p.scope
 -                      prevScope := ir.ScopeID(0)
 -                      if nmarks >= 2 {
 -                              prevScope = ir.CurFunc.Marks[nmarks-2].Scope
 -                      }
 -                      if ir.CurFunc.Marks[nmarks-1].Scope == prevScope {
 -                              ir.CurFunc.Marks = ir.CurFunc.Marks[:nmarks-1]
 -                      }
 -                      return
 +                      fs.marker.Unpush()
 +              } else {
 +                      fs.marker.Pop(p.makeXPos(pos))
                }
 -
 -              p.scope = ir.CurFunc.Parents[p.scope-1]
 -
 -              p.markScope(pos)
 -      }
 -}
 -
 -func (p *noder) markScope(pos syntax.Pos) {
 -      xpos := p.makeXPos(pos)
 -      if i := len(ir.CurFunc.Marks); i > 0 && ir.CurFunc.Marks[i-1].Pos == xpos {
 -              ir.CurFunc.Marks[i-1].Scope = p.scope
 -      } else {
 -              ir.CurFunc.Marks = append(ir.CurFunc.Marks, ir.Mark{Pos: xpos, Scope: p.scope})
        }
  }
  
  // "if" statements, as their implicit blocks always end at the same
  // position as an explicit block.
  func (p *noder) closeAnotherScope() {
 -      p.closeScope(p.lastCloseScopePos)
 +      p.closeScope(p.funcState.lastCloseScopePos)
  }
  
  // linkname records a //go:linkname directive.
@@@ -261,6 -335,7 +268,6 @@@ type linkname struct 
  }
  
  func (p *noder) node() {
 -      types.Block = 1
        p.importedUnsafe = false
        p.importedEmbed = false
  
@@@ -329,7 -404,7 +336,7 @@@ func (p *noder) decls(decls []syntax.De
  }
  
  func (p *noder) importDecl(imp *syntax.ImportDecl) {
 -      if imp.Path.Bad {
 +      if imp.Path == nil || imp.Path.Bad {
                return // avoid follow-on errors if there was a syntax error
        }
  
                p.checkUnused(pragma)
        }
  
 -      ipkg := importfile(p.basicLit(imp.Path))
 +      ipkg := importfile(imp)
        if ipkg == nil {
                if base.Errors() == 0 {
                        base.Fatalf("phase error in import")
                p.importedEmbed = true
        }
  
 -      if !ipkg.Direct {
 -              typecheck.Target.Imports = append(typecheck.Target.Imports, ipkg)
 -      }
 -      ipkg.Direct = true
 -
        var my *types.Sym
        if imp.LocalPkgName != nil {
                my = p.name(imp.LocalPkgName)
@@@ -385,9 -465,20 +392,7 @@@ func (p *noder) varDecl(decl *syntax.Va
        exprs := p.exprList(decl.Values)
  
        if pragma, ok := decl.Pragma.(*pragmas); ok {
-               if err := varEmbed(p.makeXPos, names[0], decl, pragma); err != nil {
-                       p.errorAt(decl.Pos(), "%s", err.Error())
 -              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.errorAt(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
 -                              }
 -                      } else {
 -                              varEmbed(p, names, typ, exprs, pragma.Embeds)
 -                      }
 -                      pragma.Embeds = nil
--              }
++              varEmbed(p.makeXPos, names[0], decl, pragma, p.importedEmbed)
                p.checkUnused(pragma)
        }
  
@@@ -555,7 -646,7 +560,7 @@@ func (p *noder) funcDecl(fun *syntax.Fu
                }
        } else {
                f.Shortname = name
-               name = ir.BlankNode.Sym() // filled in by typecheckfunc
+               name = ir.BlankNode.Sym() // filled in by tcFunc
        }
  
        f.Nname = ir.NewNameAt(p.pos(fun.Name), name)
@@@ -1001,7 -1092,7 +1006,7 @@@ func (p *noder) stmtsFall(stmts []synta
                if s == nil {
                } else if s.Op() == ir.OBLOCK && len(s.(*ir.BlockStmt).List) > 0 {
                        // Inline non-empty block.
-                       // Empty blocks must be preserved for checkreturn.
+                       // Empty blocks must be preserved for CheckReturn.
                        nodes = append(nodes, s.(*ir.BlockStmt).List...)
                } else {
                        nodes = append(nodes, s)
@@@ -1035,15 -1126,9 +1040,15 @@@ func (p *noder) stmtFall(stmt syntax.St
        case *syntax.DeclStmt:
                return ir.NewBlockStmt(src.NoXPos, p.decls(stmt.DeclList))
        case *syntax.AssignStmt:
 +              if stmt.Rhs == nil {
 +                      pos := p.pos(stmt)
 +                      n := ir.NewAssignOpStmt(pos, p.binOp(stmt.Op), p.expr(stmt.Lhs), ir.NewBasicLit(pos, one))
 +                      n.IncDec = true
 +                      return n
 +              }
 +
                if stmt.Op != 0 && stmt.Op != syntax.Def {
                        n := ir.NewAssignOpStmt(p.pos(stmt), p.binOp(stmt.Op), p.expr(stmt.Lhs), p.expr(stmt.Rhs))
 -                      n.IncDec = stmt.Rhs == syntax.ImplicitOne
                        return n
                }
  
@@@ -1503,6 -1588,15 +1508,6 @@@ func (p *noder) wrapname(n syntax.Node
        return x
  }
  
 -func (p *noder) pos(n syntax.Node) src.XPos {
 -      // TODO(gri): orig.Pos() should always be known - fix package syntax
 -      xpos := base.Pos
 -      if pos := n.Pos(); pos.IsKnown() {
 -              xpos = p.makeXPos(pos)
 -      }
 -      return xpos
 -}
 -
  func (p *noder) setlineno(n syntax.Node) {
        if n != nil {
                base.Pos = p.pos(n)
@@@ -1774,7 -1868,7 +1779,7 @@@ func (p *noder) funcLit(expr *syntax.Fu
        fn := ir.NewFunc(p.pos(expr))
        fn.SetIsHiddenClosure(ir.CurFunc != nil)
  
-       fn.Nname = ir.NewNameAt(p.pos(expr), ir.BlankNode.Sym()) // filled in by typecheckclosure
+       fn.Nname = ir.NewNameAt(p.pos(expr), ir.BlankNode.Sym()) // filled in by tcClosure
        fn.Nname.Func = fn
        fn.Nname.Ntype = xtype
        fn.Nname.Defn = fn
@@@ -1829,36 -1923,48 +1834,41 @@@ func oldname(s *types.Sym) ir.Node 
        return n
  }
  
- func varEmbed(makeXPos func(syntax.Pos) src.XPos, name *ir.Name, decl *syntax.VarDecl, pragma *pragmas) error {
 -func varEmbed(p *noder, names []*ir.Name, typ ir.Ntype, exprs []ir.Node, embeds []pragmaEmbed) {
 -      haveEmbed := false
 -      for _, decl := range p.file.DeclList {
 -              imp, ok := decl.(*syntax.ImportDecl)
 -              if !ok {
 -                      // imports always come first
 -                      break
 -              }
 -              path, _ := strconv.Unquote(imp.Path.Value)
 -              if path == "embed" {
 -                      haveEmbed = true
 -                      break
 -              }
++func varEmbed(makeXPos func(syntax.Pos) src.XPos, name *ir.Name, decl *syntax.VarDecl, pragma *pragmas, haveEmbed bool) {
 +      if pragma.Embeds == nil {
-               return nil
++              return
        }
  
 -      pos := embeds[0].Pos
 +      pragmaEmbeds := pragma.Embeds
 +      pragma.Embeds = nil
++      pos := makeXPos(pragmaEmbeds[0].Pos)
 +
-       if base.Flag.Cfg.Embed.Patterns == nil {
-               return errors.New("invalid go:embed: build system did not supply embed configuration")
+       if !haveEmbed {
 -              p.errorAt(pos, "invalid go:embed: missing import \"embed\"")
++              base.ErrorfAt(pos, "go:embed only allowed in Go files that import \"embed\"")
+               return
        }
 -      if len(names) > 1 {
 -              p.errorAt(pos, "go:embed cannot apply to multiple vars")
 +      if len(decl.NameList) > 1 {
-               return errors.New("go:embed cannot apply to multiple vars")
++              base.ErrorfAt(pos, "go:embed cannot apply to multiple vars")
+               return
        }
 -      if len(exprs) > 0 {
 -              p.errorAt(pos, "go:embed cannot apply to var with initializer")
 +      if decl.Values != nil {
-               return errors.New("go:embed cannot apply to var with initializer")
++              base.ErrorfAt(pos, "go:embed cannot apply to var with initializer")
+               return
        }
 -      if typ == nil {
 -              // Should not happen, since len(exprs) == 0 now.
 -              p.errorAt(pos, "go:embed cannot apply to var without type")
 +      if decl.Type == nil {
 +              // Should not happen, since Values == nil now.
-               return errors.New("go:embed cannot apply to var without type")
++              base.ErrorfAt(pos, "go:embed cannot apply to var without type")
+               return
        }
        if typecheck.DeclContext != ir.PEXTERN {
-               return errors.New("go:embed cannot apply to var inside func")
 -              p.errorAt(pos, "go:embed cannot apply to var inside func")
++              base.ErrorfAt(pos, "go:embed cannot apply to var inside func")
+               return
        }
  
 -      v := names[0]
 -      typecheck.Target.Embeds = append(typecheck.Target.Embeds, v)
 -      v.Embed = new([]ir.Embed)
 -      for _, e := range embeds {
 -              *v.Embed = append(*v.Embed, ir.Embed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns})
 +      var embeds []ir.Embed
 +      for _, e := range pragmaEmbeds {
 +              embeds = append(embeds, ir.Embed{Pos: makeXPos(e.Pos), Patterns: e.Patterns})
        }
-       return nil
 +      typecheck.Target.Embeds = append(typecheck.Target.Embeds, name)
 +      name.Embed = &embeds
  }
index 30857fff6da72d8564d8023e55cb7f8fea66a9b9,1ec92e3dd073e7ebd6ae4e2c9aca2d9710e9eefc..3ff14c87f4fc7b0603435b511771cc9cf1dcfbdc
@@@ -32,7 -32,7 +32,7 @@@ type itabEntry struct 
  
        // symbols of each method in
        // the itab, sorted by byte offset;
-       // filled in by peekitabs
+       // filled in by CompileITabs
        entries []*obj.LSym
  }
  
@@@ -401,7 -401,7 +401,7 @@@ func dimportpath(p *types.Pkg) 
        }
  
        // If we are compiling the runtime package, there are two runtime packages around
-       // -- localpkg and Runtimepkg. We don't want to produce import path symbols for
+       // -- localpkg and Pkgs.Runtime. We don't want to produce import path symbols for
        // both of them, so just produce one for localpkg.
        if base.Ctxt.Pkgpath == "runtime" && p == ir.Pkgs.Runtime {
                return
@@@ -562,7 -562,7 +562,7 @@@ func dextratype(lsym *obj.LSym, ot int
        }
  
        for _, a := range m {
-               WriteType(a.type_)
+               writeType(a.type_)
        }
  
        ot = dgopkgpathOff(lsym, ot, typePkg(t))
@@@ -613,7 -613,7 +613,7 @@@ func dextratypeData(lsym *obj.LSym, ot 
                nsym := dname(a.name.Name, "", pkg, exported)
  
                ot = objw.SymPtrOff(lsym, ot, nsym)
-               ot = dmethodptrOff(lsym, ot, WriteType(a.mtype))
+               ot = dmethodptrOff(lsym, ot, writeType(a.mtype))
                ot = dmethodptrOff(lsym, ot, a.isym)
                ot = dmethodptrOff(lsym, ot, a.tsym)
        }
@@@ -690,7 -690,7 +690,7 @@@ func dcommontype(lsym *obj.LSym, t *typ
                if t.Sym() != nil || methods(tptr) != nil {
                        sptrWeak = false
                }
-               sptr = WriteType(tptr)
+               sptr = writeType(tptr)
        }
  
        gcsym, useGCProg, ptrdata := dgcsym(t)
  // TrackSym returns the symbol for tracking use of field/method f, assumed
  // to be a member of struct/interface type t.
  func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
-       return ir.Pkgs.Track.Lookup(t.ShortString() + "." + f.Sym.Name).Linksym()
 -      return base.PkgLinksym("go.track", t.ShortString() + "." + f.Sym.Name, obj.ABI0)
++      return base.PkgLinksym("go.track", t.ShortString()+"."+f.Sym.Name, obj.ABI0)
  }
  
  func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
  
  func TypeSym(t *types.Type) *types.Sym {
        if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
-               base.Fatalf("typenamesym %v", t)
+               base.Fatalf("TypeSym %v", t)
        }
        if t.Kind() == types.TFUNC && t.Recv() != nil {
                base.Fatalf("misuse of method type: %v", t)
@@@ -836,39 -836,22 +836,22 @@@ func TypeLinksym(t *types.Type) *obj.LS
  }
  
  func TypePtr(t *types.Type) *ir.AddrExpr {
-       s := TypeSym(t)
-       if s.Def == nil {
-               n := ir.NewNameAt(src.NoXPos, s)
-               n.SetType(types.Types[types.TUINT8])
-               n.Class = ir.PEXTERN
-               n.SetTypecheck(1)
-               s.Def = n
-       }
-       n := typecheck.NodAddr(ir.AsNode(s.Def))
-       n.SetType(types.NewPtr(s.Def.Type()))
-       n.SetTypecheck(1)
-       return n
+       n := ir.NewLinksymExpr(base.Pos, TypeLinksym(t), types.Types[types.TUINT8])
+       return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr)
  }
  
  func ITabAddr(t, itype *types.Type) *ir.AddrExpr {
        if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
-               base.Fatalf("itabname(%v, %v)", t, itype)
-       }
-       s := ir.Pkgs.Itab.Lookup(t.ShortString() + "," + itype.ShortString())
-       if s.Def == nil {
-               n := typecheck.NewName(s)
-               n.SetType(types.Types[types.TUINT8])
-               n.Class = ir.PEXTERN
-               n.SetTypecheck(1)
-               s.Def = n
-               itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: n.Linksym()})
-       }
-       n := typecheck.NodAddr(ir.AsNode(s.Def))
-       n.SetType(types.NewPtr(s.Def.Type()))
-       n.SetTypecheck(1)
-       return n
+               base.Fatalf("ITabAddr(%v, %v)", t, itype)
+       }
+       s, existed := ir.Pkgs.Itab.LookupOK(t.ShortString() + "," + itype.ShortString())
+       if !existed {
+               itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
+       }
+       lsym := s.Linksym()
+       n := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])
+       return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr)
  }
  
  // needkeyupdate reports whether map updates with t as a key
@@@ -933,10 -916,10 +916,10 @@@ func formalType(t *types.Type) *types.T
        return t
  }
  
- func WriteType(t *types.Type) *obj.LSym {
+ func writeType(t *types.Type) *obj.LSym {
        t = formalType(t)
        if t.IsUntyped() {
-               base.Fatalf("dtypesym %v", t)
+               base.Fatalf("writeType %v", t)
        }
  
        s := types.TypeSym(t)
  
        case types.TARRAY:
                // ../../../../runtime/type.go:/arrayType
-               s1 := WriteType(t.Elem())
+               s1 := writeType(t.Elem())
                t2 := types.NewSlice(t.Elem())
-               s2 := WriteType(t2)
+               s2 := writeType(t2)
                ot = dcommontype(lsym, t)
                ot = objw.SymPtr(lsym, ot, s1, 0)
                ot = objw.SymPtr(lsym, ot, s2, 0)
  
        case types.TSLICE:
                // ../../../../runtime/type.go:/sliceType
-               s1 := WriteType(t.Elem())
+               s1 := writeType(t.Elem())
                ot = dcommontype(lsym, t)
                ot = objw.SymPtr(lsym, ot, s1, 0)
                ot = dextratype(lsym, ot, t, 0)
  
        case types.TCHAN:
                // ../../../../runtime/type.go:/chanType
-               s1 := WriteType(t.Elem())
+               s1 := writeType(t.Elem())
                ot = dcommontype(lsym, t)
                ot = objw.SymPtr(lsym, ot, s1, 0)
                ot = objw.Uintptr(lsym, ot, uint64(t.ChanDir()))
  
        case types.TFUNC:
                for _, t1 := range t.Recvs().Fields().Slice() {
-                       WriteType(t1.Type)
+                       writeType(t1.Type)
                }
                isddd := false
                for _, t1 := range t.Params().Fields().Slice() {
                        isddd = t1.IsDDD()
-                       WriteType(t1.Type)
+                       writeType(t1.Type)
                }
                for _, t1 := range t.Results().Fields().Slice() {
-                       WriteType(t1.Type)
+                       writeType(t1.Type)
                }
  
                ot = dcommontype(lsym, t)
  
                // Array of rtype pointers follows funcType.
                for _, t1 := range t.Recvs().Fields().Slice() {
-                       ot = objw.SymPtr(lsym, ot, WriteType(t1.Type), 0)
+                       ot = objw.SymPtr(lsym, ot, writeType(t1.Type), 0)
                }
                for _, t1 := range t.Params().Fields().Slice() {
-                       ot = objw.SymPtr(lsym, ot, WriteType(t1.Type), 0)
+                       ot = objw.SymPtr(lsym, ot, writeType(t1.Type), 0)
                }
                for _, t1 := range t.Results().Fields().Slice() {
-                       ot = objw.SymPtr(lsym, ot, WriteType(t1.Type), 0)
+                       ot = objw.SymPtr(lsym, ot, writeType(t1.Type), 0)
                }
  
        case types.TINTER:
                m := imethods(t)
                n := len(m)
                for _, a := range m {
-                       WriteType(a.type_)
+                       writeType(a.type_)
                }
  
                // ../../../../runtime/type.go:/interfaceType
                        nsym := dname(a.name.Name, "", pkg, exported)
  
                        ot = objw.SymPtrOff(lsym, ot, nsym)
-                       ot = objw.SymPtrOff(lsym, ot, WriteType(a.type_))
+                       ot = objw.SymPtrOff(lsym, ot, writeType(a.type_))
                }
  
        // ../../../../runtime/type.go:/mapType
        case types.TMAP:
-               s1 := WriteType(t.Key())
-               s2 := WriteType(t.Elem())
-               s3 := WriteType(MapBucketType(t))
+               s1 := writeType(t.Key())
+               s2 := writeType(t.Elem())
+               s3 := writeType(MapBucketType(t))
                hasher := genhash(t.Key())
  
                ot = dcommontype(lsym, t)
                }
  
                // ../../../../runtime/type.go:/ptrType
-               s1 := WriteType(t.Elem())
+               s1 := writeType(t.Elem())
  
                ot = dcommontype(lsym, t)
                ot = objw.SymPtr(lsym, ot, s1, 0)
        case types.TSTRUCT:
                fields := t.Fields().Slice()
                for _, t1 := range fields {
-                       WriteType(t1.Type)
+                       writeType(t1.Type)
                }
  
                // All non-exported struct field names within a struct
                for _, f := range fields {
                        // ../../../../runtime/type.go:/structField
                        ot = dnameField(lsym, ot, spkg, f)
-                       ot = objw.SymPtr(lsym, ot, WriteType(f.Type), 0)
+                       ot = objw.SymPtr(lsym, ot, writeType(f.Type), 0)
                        offsetAnon := uint64(f.Offset) << 1
                        if offsetAnon>>1 != uint64(f.Offset) {
                                base.Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
@@@ -1275,7 -1258,7 +1258,7 @@@ func genfun(t, it *types.Type) []*obj.L
  }
  
  // ITabSym uses the information gathered in
- // peekitabs to de-virtualize interface methods.
+ // CompileITabs to de-virtualize interface methods.
  // Since this is called by the SSA backend, it shouldn't
  // generate additional Nodes, Syms, etc.
  func ITabSym(it *obj.LSym, offset int64) *obj.LSym {
@@@ -1312,7 -1295,7 +1295,7 @@@ func NeedRuntimeType(t *types.Type) 
  }
  
  func WriteRuntimeTypes() {
-       // Process signatset. Use a loop, as dtypesym adds
+       // Process signatset. Use a loop, as writeType adds
        // entries to signatset while it is being processed.
        signats := make([]typeAndStr, len(signatslice))
        for len(signatslice) > 0 {
                sort.Sort(typesByString(signats))
                for _, ts := range signats {
                        t := ts.t
-                       WriteType(t)
+                       writeType(t)
                        if t.Sym() != nil {
-                               WriteType(types.NewPtr(t))
+                               writeType(types.NewPtr(t))
                        }
                }
        }
@@@ -1345,8 -1328,8 +1328,8 @@@ func WriteTabs() 
                //   _      [4]byte
                //   fun    [1]uintptr // variable sized
                // }
-               o := objw.SymPtr(i.lsym, 0, WriteType(i.itype), 0)
-               o = objw.SymPtr(i.lsym, o, WriteType(i.t), 0)
+               o := objw.SymPtr(i.lsym, 0, writeType(i.itype), 0)
+               o = objw.SymPtr(i.lsym, o, writeType(i.t), 0)
                o = objw.Uint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash
                o += 4                                          // skip unused field
                for _, fn := range genfun(i.t, i.itype) {
                        if p.Class != ir.PFUNC {
                                t = types.NewPtr(t)
                        }
-                       tsym := WriteType(t)
+                       tsym := writeType(t)
                        ot = objw.SymPtrOff(s, ot, nsym)
                        ot = objw.SymPtrOff(s, ot, tsym)
                        // Plugin exports symbols as interfaces. Mark their types
@@@ -1407,16 -1390,16 +1390,16 @@@ func WriteBasicTypes() 
        // but using runtime means fewer copies in object files.
        if base.Ctxt.Pkgpath == "runtime" {
                for i := types.Kind(1); i <= types.TBOOL; i++ {
-                       WriteType(types.NewPtr(types.Types[i]))
+                       writeType(types.NewPtr(types.Types[i]))
                }
-               WriteType(types.NewPtr(types.Types[types.TSTRING]))
-               WriteType(types.NewPtr(types.Types[types.TUNSAFEPTR]))
+               writeType(types.NewPtr(types.Types[types.TSTRING]))
+               writeType(types.NewPtr(types.Types[types.TUNSAFEPTR]))
  
                // emit type structs for error and func(error) string.
                // The latter is the type of an auto-generated wrapper.
-               WriteType(types.NewPtr(types.ErrorType))
+               writeType(types.NewPtr(types.ErrorType))
  
-               WriteType(types.NewSignature(types.NoPkg, nil, []*types.Field{
+               writeType(types.NewSignature(types.NoPkg, nil, []*types.Field{
                        types.NewField(base.Pos, nil, types.ErrorType),
                }, []*types.Field{
                        types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
                dimportpath(ir.Pkgs.Runtime)
  
                if base.Flag.Race {
-                       dimportpath(ir.Pkgs.Race)
+                       dimportpath(types.NewPkg("runtime/race", ""))
                }
                if base.Flag.MSan {
-                       dimportpath(ir.Pkgs.Msan)
+                       dimportpath(types.NewPkg("runtime/msan", ""))
                }
                dimportpath(types.NewPkg("main", ""))
        }
  }
@@@ -1617,13 -1601,13 +1601,13 @@@ func (p *gcProg) emit(t *types.Type, of
        }
        switch t.Kind() {
        default:
-               base.Fatalf("GCProg.emit: unexpected type %v", t)
+               base.Fatalf("gcProg.emit: unexpected type %v", t)
  
        case types.TSTRING:
                p.w.Ptr(offset / int64(types.PtrSize))
  
        case types.TINTER:
-               // Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1.
+               // Note: the first word isn't a pointer. See comment in typebits.Set
                p.w.Ptr(offset/int64(types.PtrSize) + 1)
  
        case types.TSLICE:
        case types.TARRAY:
                if t.NumElem() == 0 {
                        // should have been handled by haspointers check above
-                       base.Fatalf("GCProg.emit: empty array")
+                       base.Fatalf("gcProg.emit: empty array")
                }
  
                // Flatten array-of-array-of-array to just a big array by multiplying counts.
@@@ -1670,18 -1654,9 +1654,9 @@@ func ZeroAddr(size int64) ir.Node 
        if ZeroSize < size {
                ZeroSize = size
        }
-       s := ir.Pkgs.Map.Lookup("zero")
-       if s.Def == nil {
-               x := typecheck.NewName(s)
-               x.SetType(types.Types[types.TUINT8])
-               x.Class = ir.PEXTERN
-               x.SetTypecheck(1)
-               s.Def = x
-       }
-       z := typecheck.NodAddr(ir.AsNode(s.Def))
-       z.SetType(types.NewPtr(types.Types[types.TUINT8]))
-       z.SetTypecheck(1)
-       return z
+       lsym := base.PkgLinksym("go.map", "zero", obj.ABI0)
+       x := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])
+       return typecheck.Expr(typecheck.NodAddr(x))
  }
  
  func CollectPTabs() {
@@@ -1794,7 -1769,7 +1769,7 @@@ func methodWrapper(rcvr *types.Type, me
                }
                as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
                fn.Body.Append(as)
-               fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.ORETJMP, ir.MethodSym(methodrcvr, method.Sym)))
+               fn.Body.Append(ir.NewTailCallStmt(base.Pos, method.Nname.(*ir.Name)))
        } else {
                fn.SetWrapper(true) // ignore frame for panic+recover matching
                call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
index bd54919c935d37be3fc11acbce2038b894ae1992,c324238bf1ef0f74258f80d90d00835d3634ddd4..eab0bb09b29500b6dd2198daa912b46f56845450
@@@ -41,7 -41,7 +41,7 @@@ func Declare(n *ir.Name, ctxt ir.Class
  
        s := n.Sym()
  
-       // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+       // kludgy: TypecheckAllowed means we're past parsing. Eg reflectdata.methodWrapper may declare out of package names later.
        if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg {
                base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
        }
@@@ -304,14 -304,11 +304,14 @@@ func checkembeddedtype(t *types.Type) 
        }
  }
  
 -func fakeRecvField() *types.Field {
 +// TODO(mdempsky): Move to package types.
 +func FakeRecv() *types.Field {
        return types.NewField(src.NoXPos, nil, types.FakeRecvType())
  }
  
- var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
 +var fakeRecvField = FakeRecv
 +
+ var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
  
  type funcStackEnt struct {
        curfn      *ir.Func
@@@ -401,14 -398,14 +401,14 @@@ func Temp(t *types.Type) *ir.Name 
  // make a new Node off the books
  func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
        if curfn == nil {
-               base.Fatalf("no curfn for tempAt")
+               base.Fatalf("no curfn for TempAt")
        }
        if curfn.Op() == ir.OCLOSURE {
-               ir.Dump("tempAt", curfn)
-               base.Fatalf("adding tempAt to wrong closure function")
+               ir.Dump("TempAt", curfn)
+               base.Fatalf("adding TempAt to wrong closure function")
        }
        if t == nil {
-               base.Fatalf("tempAt called with nil type")
+               base.Fatalf("TempAt called with nil type")
        }
        if t.Kind() == types.TFUNC && t.Recv() != nil {
                base.Fatalf("misuse of method type: %v", t)
index 766eb8bae9155f94898aaa5fba08e43e82ab53e4,f624773c8f0fea62ab7aacdfa5d7f3e7aeb282f9..7ab5f68ce301b40a4f3325ff5d7e8a015cadd902
@@@ -100,7 -100,7 +100,7 @@@ func PartialCallType(n *ir.SelectorExpr
        return t
  }
  
- // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
+ // Lazy typechecking of imported bodies. For local functions, CanInline will set ->typecheck
  // because they're a copy of an already checked body.
  func ImportedBody(fn *ir.Func) {
        lno := ir.SetPos(fn.Nname)
  
        ImportBody(fn)
  
-       // typecheckinl is only for imported functions;
+       // Stmts(fn.Inl.Body) below is only for imported functions;
        // their bodies may refer to unsafe as long as the package
        // was marked safe during import (which was checked then).
-       // the ->inl of a local function has been typechecked before caninl copied it.
+       // the ->inl of a local function has been typechecked before CanInline copied it.
        pkg := fnpkg(fn.Nname)
  
        if pkg == types.LocalPkg || pkg == nil {
-               return // typecheckinl on local function
+               return // ImportedBody on local function
        }
  
        if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
        Stmts(fn.Inl.Body)
        ir.CurFunc = savefn
  
-       // During expandInline (which imports fn.Func.Inl.Body),
-       // declarations are added to fn.Func.Dcl by funcHdr(). Move them
+       // During ImportBody (which imports fn.Func.Inl.Body),
+       // declarations are added to fn.Func.Dcl by funcBody(). Move them
        // to fn.Func.Inl.Dcl for consistency with how local functions
-       // behave. (Append because typecheckinl may be called multiple
-       // times.)
+       // behave. (Append because ImportedBody may be called multiple
+       // times on same fn.)
        fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...)
        fn.Dcl = nil
  
@@@ -174,7 -174,7 +174,7 @@@ func fnpkg(fn *ir.Name) *types.Pkg 
  
  // closurename generates a new unique name for a closure within
  // outerfunc.
 -func closurename(outerfunc *ir.Func) *types.Sym {
 +func ClosureName(outerfunc *ir.Func) *types.Sym {
        outer := "glob."
        prefix := "func"
        gen := &globClosgen
@@@ -296,15 -296,22 +296,22 @@@ func tcClosure(clo *ir.ClosureExpr, to
        fn.SetClosureCalled(top&ctxCallee != 0)
  
        // Do not typecheck fn twice, otherwise, we will end up pushing
-       // fn to Target.Decls multiple times, causing initLSym called twice.
+       // fn to Target.Decls multiple times, causing InitLSym called twice.
        // See #30709
        if fn.Typecheck() == 1 {
                clo.SetType(fn.Type())
                return
        }
  
-       fn.Nname.SetSym(ClosureName(ir.CurFunc))
-       ir.MarkFunc(fn.Nname)
+       // Don't give a name and add to xtop if we are typechecking an inlined
+       // body in ImportedBody(), since we only want to create the named function
+       // when the closure is actually inlined (and then we force a typecheck
+       // explicitly in (*inlsubst).node()).
+       inTypeCheckInl := ir.CurFunc != nil && ir.CurFunc.Body == nil
+       if !inTypeCheckInl {
 -              fn.Nname.SetSym(closurename(ir.CurFunc))
++              fn.Nname.SetSym(ClosureName(ir.CurFunc))
+               ir.MarkFunc(fn.Nname)
+       }
        Func(fn)
        clo.SetType(fn.Type())
  
        }
        fn.ClosureVars = fn.ClosureVars[:out]
  
-       Target.Decls = append(Target.Decls, fn)
+       if base.Flag.W > 1 {
+               s := fmt.Sprintf("New closure func: %s", ir.FuncName(fn))
+               ir.Dump(s, fn)
+       }
+       if !inTypeCheckInl {
+               // Add function to xtop once only when we give it a name
+               Target.Decls = append(Target.Decls, fn)
+       }
  }
  
  // type check function definition
  // To be called by typecheck, not directly.
- // (Call typecheckFunc instead.)
+ // (Call typecheck.Func instead.)
  func tcFunc(n *ir.Func) {
        if base.EnableTrace && base.Flag.LowerT {
-               defer tracePrint("typecheckfunc", n)(nil)
+               defer tracePrint("tcFunc", n)(nil)
        }
  
        n.Nname = AssignExpr(n.Nname).(*ir.Name)
@@@ -896,7 -910,7 +910,7 @@@ func tcNew(n *ir.UnaryExpr) ir.Node 
  // tcPanic typechecks an OPANIC node.
  func tcPanic(n *ir.UnaryExpr) ir.Node {
        n.X = Expr(n.X)
-       n.X = DefaultLit(n.X, types.Types[types.TINTER])
+       n.X = AssignConv(n.X, types.Types[types.TINTER], "argument to panic")
        if n.X.Type() == nil {
                n.SetType(nil)
                return n
index a640d105d154453ec8492c62747d524b4f26a1f0,b6a0870672f40e4f4e9fd8b713b1e1728c3a65d7..b88a9f22839e7cb3034e39cdfe127420bd8046b0
@@@ -81,7 -81,7 +81,7 @@@ func markAddrOf(n ir.Node) ir.Node 
                // main typecheck has completed.
                // The argument to OADDR needs to be typechecked because &x[i] takes
                // the address of x if x is an array, but not if x is a slice.
-               // Note: outervalue doesn't work correctly until n is typechecked.
+               // Note: OuterValue doesn't work correctly until n is typechecked.
                n = typecheck(n, ctxExpr)
                if x := ir.OuterValue(n); x.Op() == ir.ONAME {
                        x.Name().SetAddrtaken(true)
@@@ -127,9 -127,10 +127,9 @@@ func NodNil() ir.Node 
        return n
  }
  
 -// in T.field
 -// find missing fields that
 -// will give shortest unique addressing.
 -// modify the tree with missing type names.
 +// AddImplicitDots finds missing fields in obj.field that
 +// will give the shortest unique addressing and
 +// modifies the tree with missing field names.
  func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr {
        n.X = typecheck(n.X, ctxType|ctxExpr)
        if n.X.Diag() {
@@@ -367,10 -368,10 +367,10 @@@ func assignop(src, dst *types.Type) (ir
                var missing, have *types.Field
                var ptr int
                if implements(src, dst, &missing, &have, &ptr) {
-                       // Call itabname so that (src, dst)
+                       // Call NeedITab/ITabAddr so that (src, dst)
                        // gets added to itabs early, which allows
                        // us to de-virtualize calls through this
-                       // type/interface pair later. See peekitabs in reflect.go
+                       // type/interface pair later. See CompileITabs in reflect.go
                        if types.IsDirectIface(src) && !dst.IsEmptyInterface() {
                                NeedITab(src, dst)
                        }
                }
        }
  
-       // 6. rule about untyped constants - already converted by defaultlit.
+       // 6. rule about untyped constants - already converted by DefaultLit.
  
        // 7. Any typed value can be assigned to the blank identifier.
        if dst.Kind() == types.TBLANK {
@@@ -834,7 -835,7 +834,7 @@@ func lookdot0(s *types.Sym, t *types.Ty
  var slist []symlink
  
  // Code to help generate trampoline functions for methods on embedded
- // types. These are approx the same as the corresponding adddot
+ // types. These are approx the same as the corresponding AddImplicitDots
  // routines except that they expect to be called with unique tasks and
  // they return the actual methods.
  
index d5100021a29570824beb2a345199f5fa53a1d309,7881ea308dacb5ae8c08b9a359b54fb203915864..cb434578dd37e6b758aa7d9e100a3968b3333319
@@@ -456,7 -456,7 +456,7 @@@ func typecheck(n ir.Node, top int) (re
  }
  
  // indexlit implements typechecking of untyped values as
- // array/slice indexes. It is almost equivalent to defaultlit
+ // array/slice indexes. It is almost equivalent to DefaultLit
  // but also accepts untyped numeric values representable as
  // value of type int (see also checkmake for comparison).
  // The result of indexlit MUST be assigned back to n, e.g.
@@@ -521,7 -521,7 +521,7 @@@ func typecheck1(n ir.Node, top int) ir.
                }
                return n
  
-       case ir.ONAMEOFFSET:
+       case ir.OLINKSYMOFFSET:
                // type already set
                return n
  
                n := n.(*ir.ReturnStmt)
                return tcReturn(n)
  
-       case ir.ORETJMP:
-               n := n.(*ir.BranchStmt)
+       case ir.OTAILCALL:
+               n := n.(*ir.TailCallStmt)
                return n
  
        case ir.OSELECT:
@@@ -938,7 -938,7 +938,7 @@@ func typecheckargs(n ir.InitNode) 
        // If we're outside of function context, then this call will
        // be executed during the generated init function. However,
        // init.go hasn't yet created it. Instead, associate the
-       // temporary variables with initTodo for now, and init.go
+       // temporary variables with  InitTodoFunc for now, and init.go
        // will reassociate them later when it's appropriate.
        static := ir.CurFunc == nil
        if static {
@@@ -1674,10 -1674,10 +1674,10 @@@ func CheckMapKeys() 
        mapqueue = nil
  }
  
 -// typegen tracks the number of function-scoped defined types that
 +// TypeGen tracks the number of function-scoped defined types that
  // have been declared. It's used to generate unique linker symbols for
  // their runtime type descriptors.
 -var typegen int32
 +var TypeGen int32
  
  func typecheckdeftype(n *ir.Name) {
        if base.EnableTrace && base.Flag.LowerT {
  
        t := types.NewNamed(n)
        if n.Curfn != nil {
 -              typegen++
 -              t.Vargen = typegen
 +              TypeGen++
 +              t.Vargen = TypeGen
        }
  
        if n.Pragma()&ir.NotInHeap != 0 {
@@@ -1890,7 -1890,7 +1890,7 @@@ func checkmake(t *types.Type, arg strin
                return false
        }
  
-       // Do range checks for constants before defaultlit
+       // Do range checks for constants before DefaultLit
        // to avoid redundant "constant NNN overflows int" errors.
        if n.Op() == ir.OLITERAL {
                v := toint(n.Val())
                }
        }
  
-       // defaultlit is necessary for non-constants too: n might be 1.1<<k.
+       // DefaultLit is necessary for non-constants too: n might be 1.1<<k.
        // TODO(gri) The length argument requirements for (array/slice) make
        // are the same as for index expressions. Factor the code better;
        // for instance, indexlit might be called here and incorporate some
@@@ -2023,7 -2023,7 +2023,7 @@@ func isTermNode(n ir.Node) bool 
                n := n.(*ir.BlockStmt)
                return isTermNodes(n.List)
  
-       case ir.OGOTO, ir.ORETURN, ir.ORETJMP, ir.OPANIC, ir.OFALL:
+       case ir.OGOTO, ir.ORETURN, ir.OTAILCALL, ir.OPANIC, ir.OFALL:
                return true
  
        case ir.OFOR, ir.OFORUNTIL:
index ae573a4ec8129c547411899cfece95c05fa8e0e5,0000000000000000000000000000000000000000..ffd423be277aa6702978dc8d964b1fd937136b8c
mode 100644,000000..100644
--- /dev/null
@@@ -1,323 -1,0 +1,325 @@@
 +// UNREVIEWED
 +// Copyright 2013 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.
 +
 +// This file tests types.Check by using it to
 +// typecheck the standard library and tests.
 +
 +package types2_test
 +
 +import (
 +      "bytes"
 +      "cmd/compile/internal/syntax"
 +      "fmt"
 +      "go/build"
 +      "internal/testenv"
 +      "io/ioutil"
 +      "os"
 +      "path/filepath"
 +      "runtime"
 +      "strings"
 +      "testing"
 +      "time"
 +
 +      . "cmd/compile/internal/types2"
 +)
 +
 +var stdLibImporter = defaultImporter()
 +
 +func TestStdlib(t *testing.T) {
 +      testenv.MustHaveGoBuild(t)
 +
 +      pkgCount := 0
 +      duration := walkPkgDirs(filepath.Join(runtime.GOROOT(), "src"), func(dir string, filenames []string) {
 +              typecheck(t, dir, filenames)
 +              pkgCount++
 +      }, t.Error)
 +
 +      if testing.Verbose() {
 +              fmt.Println(pkgCount, "packages typechecked in", duration)
 +      }
 +}
 +
 +// firstComment returns the contents of the first non-empty comment in
 +// the given file, "skip", or the empty string. No matter the present
 +// comments, if any of them contains a build tag, the result is always
 +// "skip". Only comments within the first 4K of the file are considered.
 +// TODO(gri) should only read until we see "package" token.
 +func firstComment(filename string) (first string) {
 +      f, err := os.Open(filename)
 +      if err != nil {
 +              return ""
 +      }
 +      defer f.Close()
 +
 +      // read at most 4KB
 +      var buf [4 << 10]byte
 +      n, _ := f.Read(buf[:])
 +      src := bytes.NewBuffer(buf[:n])
 +
 +      // TODO(gri) we need a better way to terminate CommentsDo
 +      defer func() {
 +              if p := recover(); p != nil {
 +                      if s, ok := p.(string); ok {
 +                              first = s
 +                      }
 +              }
 +      }()
 +
 +      syntax.CommentsDo(src, func(_, _ uint, text string) {
 +              if text[0] != '/' {
 +                      return // not a comment
 +              }
 +
 +              // extract comment text
 +              if text[1] == '*' {
 +                      text = text[:len(text)-2]
 +              }
 +              text = strings.TrimSpace(text[2:])
 +
 +              if strings.HasPrefix(text, "+build ") {
 +                      panic("skip")
 +              }
 +              if first == "" {
 +                      first = text // text may be "" but that's ok
 +              }
 +              // continue as we may still see build tags
 +      })
 +
 +      return
 +}
 +
 +func testTestDir(t *testing.T, path string, ignore ...string) {
 +      files, err := ioutil.ReadDir(path)
 +      if err != nil {
 +              t.Fatal(err)
 +      }
 +
 +      excluded := make(map[string]bool)
 +      for _, filename := range ignore {
 +              excluded[filename] = true
 +      }
 +
 +      for _, f := range files {
 +              // filter directory contents
 +              if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
 +                      continue
 +              }
 +
 +              // get per-file instructions
 +              expectErrors := false
 +              filename := filepath.Join(path, f.Name())
 +              if comment := firstComment(filename); comment != "" {
 +                      fields := strings.Fields(comment)
 +                      switch fields[0] {
 +                      case "skip", "compiledir":
 +                              continue // ignore this file
 +                      case "errorcheck":
 +                              expectErrors = true
 +                              for _, arg := range fields[1:] {
 +                                      if arg == "-0" || arg == "-+" || arg == "-std" {
 +                                              // Marked explicitly as not expected errors (-0),
 +                                              // or marked as compiling runtime/stdlib, which is only done
 +                                              // to trigger runtime/stdlib-only error output.
 +                                              // In both cases, the code should typecheck.
 +                                              expectErrors = false
 +                                              break
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              // parse and type-check file
 +              if testing.Verbose() {
 +                      fmt.Println("\t", filename)
 +              }
 +              file, err := syntax.ParseFile(filename, nil, nil, 0)
 +              if err == nil {
 +                      conf := Config{Importer: stdLibImporter}
 +                      _, err = conf.Check(filename, []*syntax.File{file}, nil)
 +              }
 +
 +              if expectErrors {
 +                      if err == nil {
 +                              t.Errorf("expected errors but found none in %s", filename)
 +                      }
 +              } else {
 +                      if err != nil {
 +                              t.Error(err)
 +                      }
 +              }
 +      }
 +}
 +
 +func TestStdTest(t *testing.T) {
 +      testenv.MustHaveGoBuild(t)
 +
 +      if testing.Short() && testenv.Builder() == "" {
 +              t.Skip("skipping in short mode")
 +      }
 +
 +      testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
 +              "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
 +              "directive.go",   // tests compiler rejection of bad directive placement - ignore
++              "embedfunc.go",   // tests //go:embed
++              "embedvers.go",   // tests //go:embed
 +              "linkname2.go",   // types2 doesn't check validity of //go:xxx directives
 +      )
 +}
 +
 +func TestStdFixed(t *testing.T) {
 +      testenv.MustHaveGoBuild(t)
 +
 +      if testing.Short() && testenv.Builder() == "" {
 +              t.Skip("skipping in short mode")
 +      }
 +
 +      testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
 +              "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
 +              "issue6889.go",   // gc-specific test
 +              "issue7746.go",   // large constants - consumes too much memory
 +              "issue11362.go",  // canonical import path check
 +              "issue16369.go",  // go/types handles this correctly - not an issue
 +              "issue18459.go",  // go/types doesn't check validity of //go:xxx directives
 +              "issue18882.go",  // go/types doesn't check validity of //go:xxx directives
 +              "issue20232.go",  // go/types handles larger constants than gc
 +              "issue20529.go",  // go/types does not have constraints on stack size
 +              "issue22200.go",  // go/types does not have constraints on stack size
 +              "issue22200b.go", // go/types does not have constraints on stack size
 +              "issue25507.go",  // go/types does not have constraints on stack size
 +              "issue20780.go",  // go/types does not have constraints on stack size
 +              "issue31747.go",  // go/types does not have constraints on language level (-lang=go1.12) (see #31793)
 +              "issue34329.go",  // go/types does not have constraints on language level (-lang=go1.13) (see #31793)
 +              "issue42058a.go", // go/types does not have constraints on channel element size
 +              "issue42058b.go", // go/types does not have constraints on channel element size
 +              "bug251.go",      // issue #34333 which was exposed with fix for #34151
 +      )
 +}
 +
 +func TestStdKen(t *testing.T) {
 +      testenv.MustHaveGoBuild(t)
 +
 +      testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
 +}
 +
 +// Package paths of excluded packages.
 +var excluded = map[string]bool{
 +      "builtin": true,
 +}
 +
 +// typecheck typechecks the given package files.
 +func typecheck(t *testing.T, path string, filenames []string) {
 +      // parse package files
 +      var files []*syntax.File
 +      for _, filename := range filenames {
 +              errh := func(err error) { t.Error(err) }
 +              file, err := syntax.ParseFile(filename, errh, nil, 0)
 +              if err != nil {
 +                      return
 +              }
 +
 +              if testing.Verbose() {
 +                      if len(files) == 0 {
 +                              fmt.Println("package", file.PkgName.Value)
 +                      }
 +                      fmt.Println("\t", filename)
 +              }
 +
 +              files = append(files, file)
 +      }
 +
 +      // typecheck package files
 +      conf := Config{
 +              Error:    func(err error) { t.Error(err) },
 +              Importer: stdLibImporter,
 +      }
 +      info := Info{Uses: make(map[*syntax.Name]Object)}
 +      conf.Check(path, files, &info)
 +
 +      // Perform checks of API invariants.
 +
 +      // All Objects have a package, except predeclared ones.
 +      errorError := Universe.Lookup("error").Type().Interface().ExplicitMethod(0) // (error).Error
 +      for id, obj := range info.Uses {
 +              predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
 +              if predeclared == (obj.Pkg() != nil) {
 +                      posn := id.Pos()
 +                      if predeclared {
 +                              t.Errorf("%s: predeclared object with package: %s", posn, obj)
 +                      } else {
 +                              t.Errorf("%s: user-defined object without package: %s", posn, obj)
 +                      }
 +              }
 +      }
 +}
 +
 +// pkgFilenames returns the list of package filenames for the given directory.
 +func pkgFilenames(dir string) ([]string, error) {
 +      ctxt := build.Default
 +      ctxt.CgoEnabled = false
 +      pkg, err := ctxt.ImportDir(dir, 0)
 +      if err != nil {
 +              if _, nogo := err.(*build.NoGoError); nogo {
 +                      return nil, nil // no *.go files, not an error
 +              }
 +              return nil, err
 +      }
 +      if excluded[pkg.ImportPath] {
 +              return nil, nil
 +      }
 +      var filenames []string
 +      for _, name := range pkg.GoFiles {
 +              filenames = append(filenames, filepath.Join(pkg.Dir, name))
 +      }
 +      for _, name := range pkg.TestGoFiles {
 +              filenames = append(filenames, filepath.Join(pkg.Dir, name))
 +      }
 +      return filenames, nil
 +}
 +
 +func walkPkgDirs(dir string, pkgh func(dir string, filenames []string), errh func(args ...interface{})) time.Duration {
 +      w := walker{time.Now(), 10 * time.Millisecond, pkgh, errh}
 +      w.walk(dir)
 +      return time.Since(w.start)
 +}
 +
 +type walker struct {
 +      start time.Time
 +      dmax  time.Duration
 +      pkgh  func(dir string, filenames []string)
 +      errh  func(args ...interface{})
 +}
 +
 +func (w *walker) walk(dir string) {
 +      // limit run time for short tests
 +      if testing.Short() && time.Since(w.start) >= w.dmax {
 +              return
 +      }
 +
 +      fis, err := ioutil.ReadDir(dir)
 +      if err != nil {
 +              w.errh(err)
 +              return
 +      }
 +
 +      // apply pkgh to the files in directory dir
 +      // but ignore files directly under $GOROOT/src (might be temporary test files).
 +      if dir != filepath.Join(runtime.GOROOT(), "src") {
 +              files, err := pkgFilenames(dir)
 +              if err != nil {
 +                      w.errh(err)
 +                      return
 +              }
 +              if files != nil {
 +                      w.pkgh(dir, files)
 +              }
 +      }
 +
 +      // traverse subdirectories, but don't walk into testdata
 +      for _, fi := range fis {
 +              if fi.IsDir() && fi.Name() != "testdata" {
 +                      w.walk(filepath.Join(dir, fi.Name()))
 +              }
 +      }
 +}
index 4271772fb7bdd1eabedbb433f436e9baf505fb10,4273a62fe564ee25f0ab06d80a1d9dd17562a6a2..b47d96dc4c933db6022f9bffc20334b69313edba
@@@ -7,7 -7,6 +7,6 @@@ package wal
  import (
        "errors"
        "fmt"
-       "strings"
  
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
@@@ -47,40 -46,11 +46,16 @@@ func Walk(fn *ir.Func) 
                ir.DumpList(s, ir.CurFunc.Body)
        }
  
-       zeroResults()
-       heapmoves()
-       if base.Flag.W != 0 && len(ir.CurFunc.Enter) > 0 {
-               s := fmt.Sprintf("enter %v", ir.CurFunc.Sym())
-               ir.DumpList(s, ir.CurFunc.Enter)
-       }
        if base.Flag.Cfg.Instrumenting {
                instrument(fn)
        }
 +
 +      // Eagerly compute sizes of all variables for SSA.
 +      for _, n := range fn.Dcl {
 +              types.CalcSize(n.Type())
 +      }
  }
  
- func paramoutheap(fn *ir.Func) bool {
-       for _, ln := range fn.Dcl {
-               switch ln.Class {
-               case ir.PPARAMOUT:
-                       if ir.IsParamStackCopy(ln) || ln.Addrtaken() {
-                               return true
-                       }
-               case ir.PAUTO:
-                       // stop early - parameters are over
-                       return false
-               }
-       }
-       return false
- }
  // walkRecv walks an ORECV node.
  func walkRecv(n *ir.UnaryExpr) ir.Node {
        if n.Typecheck() == 0 {
@@@ -97,8 -67,6 +72,6 @@@ func convas(n *ir.AssignStmt, init *ir.
        if n.Op() != ir.OAS {
                base.Fatalf("convas: not OAS %v", n.Op())
        }
-       defer updateHasCall(n)
        n.SetTypecheck(1)
  
        if n.X == nil || n.Y == nil {
  
  var stop = errors.New("stop")
  
- // paramstoheap returns code to allocate memory for heap-escaped parameters
- // and to copy non-result parameters' values from the stack.
- func paramstoheap(params *types.Type) []ir.Node {
-       var nn []ir.Node
-       for _, t := range params.Fields().Slice() {
-               v := ir.AsNode(t.Nname)
-               if v != nil && v.Sym() != nil && strings.HasPrefix(v.Sym().Name, "~r") { // unnamed result
-                       v = nil
-               }
-               if v == nil {
-                       continue
-               }
-               if stackcopy := v.Name().Stackcopy; stackcopy != nil {
-                       nn = append(nn, walkStmt(ir.NewDecl(base.Pos, ir.ODCL, v.(*ir.Name))))
-                       if stackcopy.Class == ir.PPARAM {
-                               nn = append(nn, walkStmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, v, stackcopy))))
-                       }
-               }
-       }
-       return nn
- }
- // zeroResults zeros the return values at the start of the function.
- // We need to do this very early in the function.  Defer might stop a
- // panic and show the return values as they exist at the time of
- // panic.  For precise stacks, the garbage collector assumes results
- // are always live, so we need to zero them before any allocations,
- // even allocations to move params/results to the heap.
- // The generated code is added to Curfn's Enter list.
- func zeroResults() {
-       for _, f := range ir.CurFunc.Type().Results().Fields().Slice() {
-               v := ir.AsNode(f.Nname)
-               if v != nil && v.Name().Heapaddr != nil {
-                       // The local which points to the return value is the
-                       // thing that needs zeroing. This is already handled
-                       // by a Needzero annotation in plive.go:livenessepilogue.
-                       continue
-               }
-               if ir.IsParamHeapCopy(v) {
-                       // TODO(josharian/khr): Investigate whether we can switch to "continue" here,
-                       // and document more in either case.
-                       // In the review of CL 114797, Keith wrote (roughly):
-                       // I don't think the zeroing below matters.
-                       // The stack return value will never be marked as live anywhere in the function.
-                       // It is not written to until deferreturn returns.
-                       v = v.Name().Stackcopy
-               }
-               // Zero the stack location containing f.
-               ir.CurFunc.Enter.Append(ir.NewAssignStmt(ir.CurFunc.Pos(), v, nil))
-       }
- }
- // returnsfromheap returns code to copy values for heap-escaped parameters
- // back to the stack.
- func returnsfromheap(params *types.Type) []ir.Node {
-       var nn []ir.Node
-       for _, t := range params.Fields().Slice() {
-               v := ir.AsNode(t.Nname)
-               if v == nil {
-                       continue
-               }
-               if stackcopy := v.Name().Stackcopy; stackcopy != nil && stackcopy.Class == ir.PPARAMOUT {
-                       nn = append(nn, walkStmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, stackcopy, v))))
-               }
-       }
-       return nn
- }
- // heapmoves generates code to handle migrating heap-escaped parameters
- // between the stack and the heap. The generated code is added to Curfn's
- // Enter and Exit lists.
- func heapmoves() {
-       lno := base.Pos
-       base.Pos = ir.CurFunc.Pos()
-       nn := paramstoheap(ir.CurFunc.Type().Recvs())
-       nn = append(nn, paramstoheap(ir.CurFunc.Type().Params())...)
-       nn = append(nn, paramstoheap(ir.CurFunc.Type().Results())...)
-       ir.CurFunc.Enter.Append(nn...)
-       base.Pos = ir.CurFunc.Endlineno
-       ir.CurFunc.Exit.Append(returnsfromheap(ir.CurFunc.Type().Results())...)
-       base.Pos = lno
- }
  func vmkcall(fn ir.Node, t *types.Type, init *ir.Nodes, va []ir.Node) *ir.CallExpr {
+       if init == nil {
+               base.Fatalf("mkcall with nil init: %v", fn)
+       }
        if fn.Type() == nil || fn.Type().Kind() != types.TFUNC {
                base.Fatalf("mkcall %v %v", fn, fn.Type())
        }
@@@ -233,10 -118,24 +123,24 @@@ func mkcall(name string, t *types.Type
        return vmkcall(typecheck.LookupRuntime(name), t, init, args)
  }
  
+ func mkcallstmt(name string, args ...ir.Node) ir.Node {
+       return mkcallstmt1(typecheck.LookupRuntime(name), args...)
+ }
  func mkcall1(fn ir.Node, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
        return vmkcall(fn, t, init, args)
  }
  
+ func mkcallstmt1(fn ir.Node, args ...ir.Node) ir.Node {
+       var init ir.Nodes
+       n := vmkcall(fn, nil, &init, args)
+       if len(init) == 0 {
+               return n
+       }
+       init.Append(n)
+       return ir.NewBlockStmt(n.Pos(), init)
+ }
  func chanfn(name string, n int, t *types.Type) ir.Node {
        if !t.IsChan() {
                base.Fatalf("chanfn %v", t)
@@@ -324,7 -223,7 +228,7 @@@ func mapfast(t *types.Type) int 
  func walkAppendArgs(n *ir.CallExpr, init *ir.Nodes) {
        walkExprListSafe(n.Args, init)
  
-       // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+       // walkExprListSafe will leave OINDEX (s[n]) alone if both s
        // and n are name or literal, but those may index the slice we're
        // modifying here. Fix explicitly.
        ls := n.Args
@@@ -356,8 -255,8 +260,8 @@@ func appendWalkStmt(init *ir.Nodes, stm
        op := stmt.Op()
        n := typecheck.Stmt(stmt)
        if op == ir.OAS || op == ir.OAS2 {
-               // If the assignment has side effects, walkexpr will append them
-               // directly to init for us, while walkstmt will wrap it in an OBLOCK.
+               // If the assignment has side effects, walkExpr will append them
+               // directly to init for us, while walkStmt will wrap it in an OBLOCK.
                // We need to append them directly.
                // TODO(rsc): Clean this up.
                n = walkExpr(n, init)
  const maxOpenDefers = 8
  
  // backingArrayPtrLen extracts the pointer and length from a slice or string.
- // This constructs two nodes referring to n, so n must be a cheapexpr.
+ // This constructs two nodes referring to n, so n must be a cheapExpr.
  func backingArrayPtrLen(n ir.Node) (ptr, length ir.Node) {
        var init ir.Nodes
        c := cheapExpr(n, &init)
        return ptr, length
  }
  
- // updateHasCall checks whether expression n contains any function
- // calls and sets the n.HasCall flag if so.
- func updateHasCall(n ir.Node) {
-       if n == nil {
-               return
-       }
-       n.SetHasCall(calcHasCall(n))
- }
- func calcHasCall(n ir.Node) bool {
-       if len(n.Init()) != 0 {
-               // TODO(mdempsky): This seems overly conservative.
+ // mayCall reports whether evaluating expression n may require
+ // function calls, which could clobber function call arguments/results
+ // currently on the stack.
+ func mayCall(n ir.Node) bool {
+       // When instrumenting, any expression might require function calls.
+       if base.Flag.Cfg.Instrumenting {
                return true
        }
  
-       switch n.Op() {
-       default:
-               base.Fatalf("calcHasCall %+v", n)
-               panic("unreachable")
+       isSoftFloat := func(typ *types.Type) bool {
+               return types.IsFloat[typ.Kind()] || types.IsComplex[typ.Kind()]
+       }
  
-       case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OTYPE, ir.ONAMEOFFSET:
-               if n.HasCall() {
-                       base.Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
-               }
-               return false
-       case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
-               return true
-       case ir.OANDAND, ir.OOROR:
-               // hard with instrumented code
-               n := n.(*ir.LogicalExpr)
-               if base.Flag.Cfg.Instrumenting {
-                       return true
+       return ir.Any(n, func(n ir.Node) bool {
+               // walk should have already moved any Init blocks off of
+               // expressions.
+               if len(n.Init()) != 0 {
+                       base.FatalfAt(n.Pos(), "mayCall %+v", n)
                }
-               return n.X.HasCall() || n.Y.HasCall()
-       case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR,
-               ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD:
-               // These ops might panic, make sure they are done
-               // before we start marshaling args for a call. See issue 16760.
-               return true
  
-       // When using soft-float, these ops might be rewritten to function calls
-       // so we ensure they are evaluated first.
-       case ir.OADD, ir.OSUB, ir.OMUL:
-               n := n.(*ir.BinaryExpr)
-               if ssagen.Arch.SoftFloat && (types.IsFloat[n.Type().Kind()] || types.IsComplex[n.Type().Kind()]) {
-                       return true
-               }
-               return n.X.HasCall() || n.Y.HasCall()
-       case ir.ONEG:
-               n := n.(*ir.UnaryExpr)
-               if ssagen.Arch.SoftFloat && (types.IsFloat[n.Type().Kind()] || types.IsComplex[n.Type().Kind()]) {
-                       return true
-               }
-               return n.X.HasCall()
-       case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
-               n := n.(*ir.BinaryExpr)
-               if ssagen.Arch.SoftFloat && (types.IsFloat[n.X.Type().Kind()] || types.IsComplex[n.X.Type().Kind()]) {
+               switch n.Op() {
+               default:
+                       base.FatalfAt(n.Pos(), "mayCall %+v", n)
+               case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
                        return true
-               }
-               return n.X.HasCall() || n.Y.HasCall()
-       case ir.OCONV:
-               n := n.(*ir.ConvExpr)
-               if ssagen.Arch.SoftFloat && ((types.IsFloat[n.Type().Kind()] || types.IsComplex[n.Type().Kind()]) || (types.IsFloat[n.X.Type().Kind()] || types.IsComplex[n.X.Type().Kind()])) {
+               case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR,
+                       ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD:
+                       // These ops might panic, make sure they are done
+                       // before we start marshaling args for a call. See issue 16760.
                        return true
+               case ir.OANDAND, ir.OOROR:
+                       n := n.(*ir.LogicalExpr)
+                       // The RHS expression may have init statements that
+                       // should only execute conditionally, and so cannot be
+                       // pulled out to the top-level init list. We could try
+                       // to be more precise here.
+                       return len(n.Y.Init()) != 0
+               // When using soft-float, these ops might be rewritten to function calls
+               // so we ensure they are evaluated first.
+               case ir.OADD, ir.OSUB, ir.OMUL, ir.ONEG:
+                       return ssagen.Arch.SoftFloat && isSoftFloat(n.Type())
+               case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
+                       n := n.(*ir.BinaryExpr)
+                       return ssagen.Arch.SoftFloat && isSoftFloat(n.X.Type())
+               case ir.OCONV:
+                       n := n.(*ir.ConvExpr)
+                       return ssagen.Arch.SoftFloat && (isSoftFloat(n.Type()) || isSoftFloat(n.X.Type()))
+               case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OLINKSYMOFFSET, ir.OMETHEXPR,
+                       ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOMPLEX, ir.OEFACE,
+                       ir.OADDR, ir.OBITNOT, ir.ONOT, ir.OPLUS,
+                       ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
+                       ir.OCONVNOP, ir.ODOT,
+                       ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
+                       ir.OBYTES2STRTMP, ir.OGETG, ir.OSLICEHEADER:
+                       // ok: operations that don't require function calls.
+                       // Expand as needed.
                }
-               return n.X.HasCall()
-       case ir.OAND, ir.OANDNOT, ir.OLSH, ir.OOR, ir.ORSH, ir.OXOR, ir.OCOPY, ir.OCOMPLEX, ir.OEFACE:
-               n := n.(*ir.BinaryExpr)
-               return n.X.HasCall() || n.Y.HasCall()
-       case ir.OAS:
-               n := n.(*ir.AssignStmt)
-               return n.X.HasCall() || n.Y != nil && n.Y.HasCall()
-       case ir.OADDR:
-               n := n.(*ir.AddrExpr)
-               return n.X.HasCall()
-       case ir.OPAREN:
-               n := n.(*ir.ParenExpr)
-               return n.X.HasCall()
-       case ir.OBITNOT, ir.ONOT, ir.OPLUS, ir.ORECV,
-               ir.OALIGNOF, ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.ONEW,
-               ir.OOFFSETOF, ir.OPANIC, ir.OREAL, ir.OSIZEOF,
-               ir.OCHECKNIL, ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.ONEWOBJ, ir.OSPTR, ir.OVARDEF, ir.OVARKILL, ir.OVARLIVE:
-               n := n.(*ir.UnaryExpr)
-               return n.X.HasCall()
-       case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER:
-               n := n.(*ir.SelectorExpr)
-               return n.X.HasCall()
-       case ir.OGETG, ir.OMETHEXPR:
-               return false
  
-       // TODO(rsc): These look wrong in various ways but are what calcHasCall has always done.
-       case ir.OADDSTR:
-               // TODO(rsc): This used to check left and right, which are not part of OADDSTR.
-               return false
-       case ir.OBLOCK:
-               // TODO(rsc): Surely the block's statements matter.
                return false
-       case ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.OBYTES2STRTMP, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2BYTESTMP, ir.OSTR2RUNES, ir.ORUNESTR:
-               // TODO(rsc): Some conversions are themselves calls, no?
-               n := n.(*ir.ConvExpr)
-               return n.X.HasCall()
-       case ir.ODOTTYPE2:
-               // TODO(rsc): Shouldn't this be up with ODOTTYPE above?
-               n := n.(*ir.TypeAssertExpr)
-               return n.X.HasCall()
-       case ir.OSLICEHEADER:
-               // TODO(rsc): What about len and cap?
-               n := n.(*ir.SliceHeaderExpr)
-               return n.Ptr.HasCall()
-       case ir.OAS2DOTTYPE, ir.OAS2FUNC:
-               // TODO(rsc): Surely we need to check List and Rlist.
-               return false
-       }
+       })
  }
  
  // itabType loads the _type field from a runtime.itab struct.
@@@ -539,7 -386,7 +391,7 @@@ func runtimeField(name string, offset i
  
  // ifaceData loads the data field from an interface.
  // The concrete type must be known to have type t.
- // It follows the pointer if !isdirectiface(t).
+ // It follows the pointer if !IsDirectIface(t).
  func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node {
        if t.IsInterface() {
                base.Fatalf("ifaceData interface: %v", t)
index 977c5c3303321ae17fce0ec0c90b6162bc4b9e0e,7ba8c6d317d1d67527b828704e0defd2a1ab34ba..35cb53cbf6cc83dcdccdc2a7df79e61d300929b0
@@@ -766,6 -766,17 +766,17 @@@ type Auto struct 
        Gotype  *LSym
  }
  
+ // RegArg provides spill/fill information for a register-resident argument
+ // to a function.  These need spilling/filling in the safepoint/stackgrowth case.
+ // At the time of fill/spill, the offset must be adjusted by the architecture-dependent
+ // adjustment to hardware SP that occurs in a call instruction.  E.g., for AMD64,
+ // at Offset+8 because the return address was pushed.
+ type RegArg struct {
+       Addr           Addr
+       Reg            int16
+       Spill, Unspill As
+ }
  // Link holds the context for writing object code from a compiler
  // to be linker input or for reading that input into the linker.
  type Link struct {
        DebugInfo          func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
        GenAbstractFunc    func(fn *LSym)
        Errors             int
+       RegArgs            []RegArg
  
 -      InParallel      bool // parallel backend phase in effect
 -      UseBASEntries   bool // use Base Address Selection Entries in location lists and PC ranges
 -      IsAsm           bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
 +      InParallel    bool // parallel backend phase in effect
 +      UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
 +      IsAsm         bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
  
        // state for writing objects
        Text []*LSym
@@@ -844,6 -856,32 +856,32 @@@ func (ctxt *Link) Logf(format string, a
        ctxt.Bso.Flush()
  }
  
+ func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
+       // Spill register args.
+       for _, ra := range ctxt.RegArgs {
+               spill := Appendp(last, pa)
+               spill.As = ra.Spill
+               spill.From.Type = TYPE_REG
+               spill.From.Reg = ra.Reg
+               spill.To = ra.Addr
+               last = spill
+       }
+       return last
+ }
+ func (ctxt *Link) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog {
+       // Unspill any spilled register args
+       for _, ra := range ctxt.RegArgs {
+               unspill := Appendp(last, pa)
+               unspill.As = ra.Unspill
+               unspill.From = ra.Addr
+               unspill.To.Type = TYPE_REG
+               unspill.To.Reg = ra.Reg
+               last = unspill
+       }
+       return last
+ }
  // The smallest possible offset from the hardware stack pointer to a local
  // variable on the stack. Architectures that use a link register save its value
  // on the stack in the function prologue and so always have a pointer between
diff --combined src/reflect/all_test.go
index d5269152eb0d4d30441c3b0d80752c5a7853fe22,1225d6177d4b4709ff9c4982887adfab9dc2fb33..ea7163f66aa48c4712faf0ddfed3dd4872f00b9d
@@@ -2997,44 -2997,44 +2997,44 @@@ func TestUnexportedMethods(t *testing.T
        }
  }
  
 -type InnerInt struct {
 -      X int
 -}
 -
 -type OuterInt struct {
 -      Y int
 -      InnerInt
 -}
 -
 -func (i *InnerInt) M() int {
 -      return i.X
 -}
 -
 -func TestEmbeddedMethods(t *testing.T) {
 -      typ := TypeOf((*OuterInt)(nil))
 -      if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*OuterInt).M).Pointer() {
 -              t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
 -              for i := 0; i < typ.NumMethod(); i++ {
 -                      m := typ.Method(i)
 -                      t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
 -              }
 -      }
 -
 -      i := &InnerInt{3}
 -      if v := ValueOf(i).Method(0).Call(nil)[0].Int(); v != 3 {
 -              t.Errorf("i.M() = %d, want 3", v)
 -      }
 -
 -      o := &OuterInt{1, InnerInt{2}}
 -      if v := ValueOf(o).Method(0).Call(nil)[0].Int(); v != 2 {
 -              t.Errorf("i.M() = %d, want 2", v)
 -      }
 -
 -      f := (*OuterInt).M
 -      if v := f(o); v != 2 {
 -              t.Errorf("f(o) = %d, want 2", v)
 -      }
 -}
 +// type InnerInt struct {
 +//    X int
 +// }
 +
 +// type OuterInt struct {
 +//    Y int
 +//    InnerInt
 +// }
 +
 +// func (i *InnerInt) M() int {
 +//    return i.X
 +// }
 +
 +// func TestEmbeddedMethods(t *testing.T) {
 +//    typ := TypeOf((*OuterInt)(nil))
 +//    if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*OuterInt).M).Pointer() {
 +//            t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
 +//            for i := 0; i < typ.NumMethod(); i++ {
 +//                    m := typ.Method(i)
 +//                    t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
 +//            }
 +//    }
 +
 +//    i := &InnerInt{3}
 +//    if v := ValueOf(i).Method(0).Call(nil)[0].Int(); v != 3 {
 +//            t.Errorf("i.M() = %d, want 3", v)
 +//    }
 +
 +//    o := &OuterInt{1, InnerInt{2}}
 +//    if v := ValueOf(o).Method(0).Call(nil)[0].Int(); v != 2 {
 +//            t.Errorf("i.M() = %d, want 2", v)
 +//    }
 +
 +//    f := (*OuterInt).M
 +//    if v := f(o); v != 2 {
 +//            t.Errorf("f(o) = %d, want 2", v)
 +//    }
 +// }
  
  type FuncDDD func(...interface{}) error
  
@@@ -7168,176 -7168,6 +7168,6 @@@ func TestMapIterDelete1(t *testing.T) 
        }
  }
  
- func TestStructTagLookup(t *testing.T) {
-       var tests = []struct {
-               tag           StructTag
-               key           string
-               expectedValue string
-               expectedOK    bool
-       }{
-               {
-                       tag:           `json:"json_value_1"`,
-                       key:           "json",
-                       expectedValue: "json_value_1",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json:"json_value_2" xml:"xml_value_2"`,
-                       key:           "json",
-                       expectedValue: "json_value_2",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json:"json_value_3" xml:"xml_value_3"`,
-                       key:           "xml",
-                       expectedValue: "xml_value_3",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `bson json:"shared_value_4"`,
-                       key:           "json",
-                       expectedValue: "shared_value_4",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `bson json:"shared_value_5"`,
-                       key:           "bson",
-                       expectedValue: "shared_value_5",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json bson xml form:"field_1,omitempty" other:"value_1"`,
-                       key:           "xml",
-                       expectedValue: "field_1,omitempty",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json bson xml form:"field_2,omitempty" other:"value_2"`,
-                       key:           "form",
-                       expectedValue: "field_2,omitempty",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json bson xml form:"field_3,omitempty" other:"value_3"`,
-                       key:           "other",
-                       expectedValue: "value_3",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json    bson    xml    form:"field_4" other:"value_4"`,
-                       key:           "json",
-                       expectedValue: "field_4",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json    bson    xml    form:"field_5" other:"value_5"`,
-                       key:           "non_existing",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `json "json_6"`,
-                       key:           "json",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `json:"json_7" bson "bson_7"`,
-                       key:           "json",
-                       expectedValue: "json_7",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `json:"json_8" xml "xml_8"`,
-                       key:           "xml",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `json    bson    xml    form "form_9" other:"value_9"`,
-                       key:           "bson",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `json bson xml form "form_10" other:"value_10"`,
-                       key:           "other",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `json bson xml form:"form_11" other "value_11"`,
-                       key:           "json",
-                       expectedValue: "form_11",
-                       expectedOK:    true,
-               },
-               {
-                       tag:           `tag1`,
-                       key:           "tag1",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `tag2 :"hello_2"`,
-                       key:           "tag2",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           `tag3: "hello_3"`,
-                       key:           "tag3",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           "json\x7fbson: \"hello_4\"",
-                       key:           "json",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           "json\x7fbson: \"hello_5\"",
-                       key:           "bson",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           "json bson:\x7f\"hello_6\"",
-                       key:           "json",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           "json bson:\x7f\"hello_7\"",
-                       key:           "bson",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           "json\x09bson:\"hello_8\"",
-                       key:           "json",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-               {
-                       tag:           "a\x7fb json:\"val\"",
-                       key:           "json",
-                       expectedValue: "",
-                       expectedOK:    false,
-               },
-       }
-       for _, test := range tests {
-               v, ok := test.tag.Lookup(test.key)
-               if v != test.expectedValue {
-                       t.Errorf("struct tag lookup failed, got %s, want %s", v, test.expectedValue)
-               }
-               if ok != test.expectedOK {
-                       t.Errorf("struct tag lookup failed, got %t, want %t", ok, test.expectedOK)
-               }
-       }
- }
  // iterateToString returns the set of elements
  // returned by an iterator in readable form.
  func iterateToString(it *MapIter) string {
index 0000000000000000000000000000000000000000,4544b6e4963d87c77b7f82eae80db0151eaf42be..9f7682ad6ac50b013a0e513b25bf55e9395a9c9b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,11 +1,11 @@@
 -var _ = true == '\\' // ERROR "invalid operation: true == '\\\\'"
 -var _ = true == '\'' // ERROR "invalid operation: true == '\\''"
 -var _ = true == '\n' // ERROR "invalid operation: true == '\\n'"
+ // errorcheck
+ // Copyright 2021 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.
+ package p
++var _ = true == '\\' // ERROR "invalid operation: true == '\\\\'|cannot convert true"
++var _ = true == '\'' // ERROR "invalid operation: true == '\\''|cannot convert true"
++var _ = true == '\n' // ERROR "invalid operation: true == '\\n'|cannot convert true"
diff --combined test/run.go
index f2f17c4f2078236dccb2b523c7108a45ed260176,116f983a97a151562fc67392aea41e7c4e292356..a460c4d8b6ffe859735dbd3f2e5834fc30661465
@@@ -59,7 -59,7 +59,7 @@@ var 
  
        // dirs are the directories to look for *.go files in.
        // TODO(bradfitz): just use all directories?
-       dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "typeparam"}
 -      dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi"}
++      dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "abi", "typeparam"}
  
        // ratec controls the max number of tests running at a time.
        ratec chan bool
@@@ -467,6 -467,8 +467,8 @@@ func goGcflagsIsEmpty() bool 
        return "" == os.Getenv("GO_GCFLAGS")
  }
  
+ var errTimeout = errors.New("command exceeded time limit")
  // run runs a test.
  func (t *test) run() {
        start := time.Now()
        // Execution recipe stops at first blank line.
        pos := strings.Index(t.src, "\n\n")
        if pos == -1 {
-               t.err = errors.New("double newline not found")
+               t.err = fmt.Errorf("double newline ending execution recipe not found in %s", t.goFileName())
                return
        }
        action := t.src[:pos]
                                case err = <-done:
                                        // ok
                                case <-tick.C:
+                                       cmd.Process.Signal(os.Interrupt)
+                                       time.Sleep(1 * time.Second)
                                        cmd.Process.Kill()
-                                       err = <-done
-                                       // err = errors.New("Test timeout")
+                                       <-done
+                                       err = errTimeout
                                }
                                tick.Stop()
                        }
                } else {
                        err = cmd.Run()
                }
-               if err != nil {
+               if err != nil && err != errTimeout {
                        err = fmt.Errorf("%s\n%s", err, buf.Bytes())
                }
                return buf.Bytes(), err
                                t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
                                return
                        }
+                       if err == errTimeout {
+                               t.err = fmt.Errorf("compilation timed out")
+                               return
+                       }
                } else {
                        if err != nil {
                                t.err = err
                        t.updateErrors(string(out), long)
                }
                t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
 -              return
 +              if t.err != nil {
 +                      return // don't hide error if run below succeeds
 +              }
 +
 +              // The following is temporary scaffolding to get types2 typechecker
 +              // up and running against the existing test cases. The explicitly
 +              // listed files don't pass yet, usually because the error messages
 +              // are slightly different (this list is not complete). Any errorcheck
 +              // tests that require output from analysis phases past intial type-
 +              // checking are also excluded since these phases are not running yet.
 +              // We can get rid of this code once types2 is fully plugged in.
 +
 +              // For now we're done when we can't handle the file or some of the flags.
 +              // The first goal is to eliminate the excluded list; the second goal is to
 +              // eliminate the flag list.
 +
 +              // Excluded files.
 +              if excluded[t.goFileName()] {
 +                      if *verbose {
 +                              fmt.Printf("excl\t%s\n", t.goFileName())
 +                      }
 +                      return // cannot handle file yet
 +              }
 +
 +              // Excluded flags.
 +              for _, flag := range flags {
 +                      for _, pattern := range []string{
 +                              "-+",
 +                              "-0",
 +                              "-e=0",
 +                              "-m",
 +                              "-live",
 +                              "-std",
 +                              "wb",
 +                              "append",
 +                              "slice",
 +                              "typeassert",
 +                              "ssa/check_bce/debug",
 +                              "ssa/intrinsics/debug",
 +                              "ssa/opt/debug",
 +                              "ssa/prove/debug",
 +                              "ssa/likelyadjust/debug",
 +                              "ssa/insert_resched_checks/off",
 +                              "ssa/phiopt/debug",
 +                              "defer",
 +                              "nil",
 +                      } {
 +                              if strings.Contains(flag, pattern) {
 +                                      if *verbose {
 +                                              fmt.Printf("excl\t%s\t%s\n", t.goFileName(), flags)
 +                                      }
 +                                      return // cannot handle flag
 +                              }
 +                      }
 +              }
 +
 +              // Run errorcheck again with -G option (new typechecker).
 +              cmdline = []string{goTool(), "tool", "compile", "-G", "-C", "-e", "-o", "a.o"}
 +              // No need to add -dynlink even if linkshared if we're just checking for errors...
 +              cmdline = append(cmdline, flags...)
 +              cmdline = append(cmdline, long)
 +              out, err = runcmd(cmdline...)
 +              if wantError {
 +                      if err == nil {
 +                              t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
 +                              return
 +                      }
 +              } else {
 +                      if err != nil {
 +                              t.err = err
 +                              return
 +                      }
 +              }
 +              if *updateErrors {
 +                      t.updateErrors(string(out), long)
 +              }
 +              t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
  
        case "compile":
                // Compile Go file.
                                        t.err = err
                                        return
                                }
-                               if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
-                                       t.err = fmt.Errorf("incorrect output\n%s", out)
-                               }
+                               t.checkExpectedOutput(out)
                        }
                }
  
                        t.err = err
                        return
                }
-               if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
-                       t.err = fmt.Errorf("incorrect output\n%s", out)
-               }
+               t.checkExpectedOutput(out)
  
        case "build":
                // Build Go file.
                                t.err = err
                                break
                        }
-                       if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
-                               t.err = fmt.Errorf("incorrect output\n%s", out)
-                       }
+                       t.checkExpectedOutput(out)
                }
  
        case "buildrun":
                        return
                }
  
-               if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
-                       t.err = fmt.Errorf("incorrect output\n%s", out)
-               }
+               t.checkExpectedOutput(out)
  
        case "run":
                // Run Go file if no special go command flags are provided;
                        t.err = err
                        return
                }
-               if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
-                       t.err = fmt.Errorf("incorrect output\n%s", out)
-               }
+               t.checkExpectedOutput(out)
  
        case "runoutput":
                // Run Go file and write its output into temporary Go file.
                        t.err = err
                        return
                }
-               if string(out) != t.expectedOutput() {
-                       t.err = fmt.Errorf("incorrect output\n%s", out)
-               }
+               t.checkExpectedOutput(out)
  
        case "errorcheckoutput":
                // Run Go file and write its output into temporary Go file.
@@@ -1251,12 -1171,24 +1247,24 @@@ func (t *test) makeTempDir() 
        }
  }
  
- func (t *test) expectedOutput() string {
+ // checkExpectedOutput compares the output from compiling and/or running with the contents
+ // of the corresponding reference output file, if any (replace ".go" with ".out").
+ // If they don't match, fail with an informative message.
+ func (t *test) checkExpectedOutput(gotBytes []byte) {
+       got := string(gotBytes)
        filename := filepath.Join(t.dir, t.gofile)
        filename = filename[:len(filename)-len(".go")]
        filename += ".out"
-       b, _ := ioutil.ReadFile(filename)
-       return string(b)
+       b, err := ioutil.ReadFile(filename)
+       // File is allowed to be missing (err != nil) in which case output should be empty.
+       got = strings.Replace(got, "\r\n", "\n", -1)
+       if got != string(b) {
+               if err == nil {
+                       t.err = fmt.Errorf("output does not match expected in %s. Instead saw\n%s", filename, got)
+               } else {
+                       t.err = fmt.Errorf("output should be empty when (optional) expected-output file %s is not present. Instead saw\n%s", filename, got)
+               }
+       }
  }
  
  func splitOutput(out string, wantAuto bool) []string {
@@@ -1922,74 -1854,3 +1930,76 @@@ func overlayDir(dstRoot, srcRoot string
                return err
        })
  }
 +
 +// List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option).
 +// Temporary scaffolding until we pass all the tests at which point this map can be removed.
 +var excluded = map[string]bool{
 +      "complit1.go":     true, // types2 reports extra errors
 +      "const2.go":       true, // types2 not run after syntax errors
 +      "ddd1.go":         true, // issue #42987
 +      "directive.go":    true, // misplaced compiler directive checks
++      "embedfunc.go":    true, // error reported by irgen (only runs with -G=3)
++      "embedvers.go":    true, // error reported by backend (only runs with -G=3)
 +      "float_lit3.go":   true, // types2 reports extra errors
 +      "import1.go":      true, // types2 reports extra errors
 +      "import5.go":      true, // issue #42988
 +      "import6.go":      true, // issue #43109
 +      "initializerr.go": true, // types2 reports extra errors
 +      "linkname2.go":    true, // error reported by noder (not running for types2 errorcheck test)
 +      "shift1.go":       true, // issue #42989
 +      "typecheck.go":    true, // invalid function is not causing errors when called
 +
 +      "fixedbugs/bug176.go":    true, // types2 reports all errors (pref: types2)
 +      "fixedbugs/bug193.go":    true, // types2 bug: shift error not reported (fixed in go/types)
 +      "fixedbugs/bug195.go":    true, // types2 reports slightly different (but correct) bugs
 +      "fixedbugs/bug228.go":    true, // types2 not run after syntax errors
 +      "fixedbugs/bug231.go":    true, // types2 bug? (same error reported twice)
 +      "fixedbugs/bug255.go":    true, // types2 reports extra errors
 +      "fixedbugs/bug351.go":    true, // types2 reports extra errors
 +      "fixedbugs/bug374.go":    true, // types2 reports extra errors
 +      "fixedbugs/bug385_32.go": true, // types2 doesn't produce "stack frame too large" error (32-bit specific)
 +      "fixedbugs/bug385_64.go": true, // types2 doesn't produce "stack frame too large" error
 +      "fixedbugs/bug388.go":    true, // types2 not run due to syntax errors
 +      "fixedbugs/bug412.go":    true, // types2 produces a follow-on error
 +
 +      "fixedbugs/issue11590.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue11610.go":  true, // types2 not run after syntax errors
 +      "fixedbugs/issue11614.go":  true, // types2 reports an extra error
 +      "fixedbugs/issue13415.go":  true, // declared but not used conflict
 +      "fixedbugs/issue14520.go":  true, // missing import path error by types2
 +      "fixedbugs/issue14540.go":  true, // error reported by noder (not running for types2 errorcheck test)
 +      "fixedbugs/issue16428.go":  true, // types2 reports two instead of one error
 +      "fixedbugs/issue17038.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue17645.go":  true, // multiple errors on same line
 +      "fixedbugs/issue18393.go":  true, // types2 not run after syntax errors
 +      "fixedbugs/issue19012.go":  true, // multiple errors on same line
 +      "fixedbugs/issue20233.go":  true, // types2 reports two instead of one error (pref: compiler)
 +      "fixedbugs/issue20245.go":  true, // types2 reports two instead of one error (pref: compiler)
 +      "fixedbugs/issue20529.go":  true, // types2 doesn't produce "stack frame too large" error
 +      "fixedbugs/issue20780.go":  true, // types2 doesn't produce "stack frame too large" error
 +      "fixedbugs/issue21979.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue22200.go":  true, // types2 doesn't produce "stack frame too large" error
 +      "fixedbugs/issue22200b.go": true, // types2 doesn't produce "stack frame too large" error
 +      "fixedbugs/issue23732.go":  true, // types2 reports different (but ok) line numbers
 +      "fixedbugs/issue25507.go":  true, // types2 doesn't produce "stack frame too large" error
 +      "fixedbugs/issue25958.go":  true, // types2 doesn't report a follow-on error (pref: types2)
 +      "fixedbugs/issue28079b.go": true, // types2 reports follow-on errors
 +      "fixedbugs/issue28268.go":  true, // types2 reports follow-on errors
 +      "fixedbugs/issue31747.go":  true, // types2 is missing support for -lang flag
 +      "fixedbugs/issue33460.go":  true, // types2 reports alternative positions in separate error
 +      "fixedbugs/issue34329.go":  true, // types2 is missing support for -lang flag
 +      "fixedbugs/issue41575.go":  true, // types2 reports alternative positions in separate error
 +      "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large"
 +      "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large"
 +      "fixedbugs/issue4232.go":   true, // types2 reports (correct) extra errors
 +      "fixedbugs/issue4452.go":   true, // types2 reports (correct) extra errors
 +      "fixedbugs/issue5609.go":   true, // types2 needs a better error message
 +      "fixedbugs/issue6889.go":   true, // types2 can handle this without constant overflow
 +      "fixedbugs/issue7525.go":   true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525b.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525c.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525d.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7525e.go":  true, // types2 reports init cycle error on different line - ok otherwise
 +      "fixedbugs/issue7742.go":   true, // types2 type-checking doesn't terminate
 +      "fixedbugs/issue7746.go":   true, // types2 type-checking doesn't terminate
 +}