diff options
author | Matthew Dempsky <mdempsky@google.com> | 2021-06-14 12:26:41 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2021-06-14 13:24:47 -0700 |
commit | ea438bda85ed473ecee215b098eba1f19113bc24 (patch) | |
tree | 78ea8b11917bcdf1e7c78c09c0395c684d55c054 /src/cmd | |
parent | 8eeaf961c50973b0aa2065d2c31dfa5d9949bf93 (diff) | |
parent | fdab5be159c508c4c1cf5be84119fd2b38403cdf (diff) | |
download | go-ea438bda85ed473ecee215b098eba1f19113bc24.tar.gz go-ea438bda85ed473ecee215b098eba1f19113bc24.zip |
[dev.typeparams] all: merge master (fdab5be) into dev.typeparams
Two non-conflict changes included because they're needed for all.bash:
1. Bump internal/goversion.Version to 18. This will happen eventually
anyway (dev.typeparams will not be merged back to Go 1.17), and is
needed for cmd/api to allow new API additions.
2. Add fixedbugs/issue46725.go (new test added on master) to the list
of known failures for -G=3. This test exercises a bug that was fixed
in typecheck, but -G=3 mode has duplicated that code and will need to
be fixed as well. That's outside of the scope of a merge.
Conflicts:
- src/runtime/traceback.go
Nearby lines were removed on both master and dev.typeparams.
Merge List:
+ 2021-06-14 fdab5be159 doc/go1.17: further revise OpenBSD release notes
+ 2021-06-14 326ea438bb cmd/compile: rewrite a, b = f() to use temporaries when type not identical
+ 2021-06-14 3249b645c9 cmd/compile: factor out rewrite multi-valued f()
+ 2021-06-13 14305bf0b9 misc/cgo: generate Windows import libraries for clang
+ 2021-06-13 24cff0f044 cmd/go, misc/cgo: skip test if no .edata
+ 2021-06-13 67b1b6a2e3 cmd/compile: allow ir.OSLICE2ARRPTR in mayCall
+ 2021-06-12 1ed0d129e9 runtime: testprogcgo: don't call exported Go functions directly from Go
+ 2021-06-12 9d46ee5ac4 reflect: handle stack-to-register translation in callMethod
+ 2021-06-11 e552a6d312 cmd/go: remove hint when no module is suggested
+ 2021-06-11 16b5d766d8 syscall: do not load native libraries on non-native powershell on arm
+ 2021-06-11 77aa209b38 runtime: loop on EINTR in macOS sigNoteSleep
+ 2021-06-11 e2dc6dd5c9 doc/go1.17: clean up formatting of gofmt section
+ 2021-06-11 2f1128461d cmd/go: match Windows paths in TestScript/mod_invalid_version
+ 2021-06-11 2721da2608 doc/go1.17: fix formatting near httptest
+ 2021-06-10 770f1de8c5 net/http: remove test-only private key from production binaries
+ 2021-06-10 8d11b1d117 cmd/go: report the imports of CompiledGoFiles in ImportMap
+ 2021-06-10 dc00dc6c6b crypto/tls: let HTTP/1.1 clients connect to servers with NextProtos "h2"
+ 2021-06-09 27f83723e9 api: promote next to go1.17
+ 2021-06-09 182157c81a doc/go1.17: remove lingering TODO
+ 2021-06-09 a5bc060b42 doc/go1.17: document strconv changes for Go 1.17
+ 2021-06-09 1402b27d46 strconv: document parsing of leading +/-
+ 2021-06-09 df35ade067 doc/go1.17: document //go:build lines
+ 2021-06-09 e4e7807d24 net/http: add AllowQuerySemicolons
+ 2021-06-09 ec3026d032 doc/go1.17: remove TODO for ports section
+ 2021-06-09 e6dda19888 net/url: reject query values with semicolons
+ 2021-06-09 139e935d3c math/big: comment division
+ 2021-06-09 aa5540cd82 cmd/compile: make map.zero symbol content-addressable
+ 2021-06-09 07ca28d529 cmd/link: fix bug in -strictdups checking of BSS symbols
+ 2021-06-08 bcecae2af6 doc/go1.17: mention new possibility of type conversion panicking
+ 2021-06-08 63dcab2e91 doc/go1.17: mention new vet checks sigchanyzer and stdmethods.
+ 2021-06-08 6551763a60 doc/go1.17: mention block profile bias fix
+ 2021-06-08 cb80937bf6 Revert "doc/go1.17: mention block profile bias fix"
+ 2021-06-08 d3e3d03666 net: reject leading zeros in IP address parsers
+ 2021-06-08 da4a640141 doc/go1.17: revise OpenBSD release notes
+ 2021-06-08 689f4c7415 doc/go1.17: mention block profile bias fix
+ 2021-06-08 9afe071c60 doc/go1.17: remove TODO for Tools section
+ 2021-06-08 f753d7223e doc/go1.17: resolve TODO for cmd/cover
+ 2021-06-08 9498b0155d cmd/go: in Go 1.17+ modules, add indirect go.mod dependencies separately from direct ones
+ 2021-06-08 949f00cebe doc/go1.17: add release notes for crypto packages
+ 2021-06-08 0fb3e2c184 doc/go1.17: add a release note for the '-compat' flag to 'go mod tidy'
+ 2021-06-08 2169deb352 cmd/compile: use t.AllMethods when sorting typesByString
+ 2021-06-08 c20bcb6488 runtime: remove out-of-date comments about frame skipping
+ 2021-06-07 39c39ae52f doc: document Go 1.17 language changes
+ 2021-06-07 dc8b558951 cmd/dist: pass -Wno-lto-type-mismatch in swig_callback_lto
+ 2021-06-07 909dd5e010 strconv: ParseFloat: always return ErrSyntax for bad syntax
Change-Id: Iffdf379d0275bbd12d50149ce38634773ced481d
Diffstat (limited to 'src/cmd')
29 files changed, 521 insertions, 187 deletions
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index a52696fbb6..8a2ff75583 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -149,6 +149,7 @@ func dumpdata() { if reflectdata.ZeroSize > 0 { zero := base.PkgLinksym("go.map", "zero", obj.ABI0) objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA) + zero.Set(obj.AttrContentAddressable, true) } staticdata.WriteFuncSyms() diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index bdc3527011..f16034ea70 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1472,8 +1472,8 @@ func (a typesByString) Less(i, j int) bool { // will be equal for the above checks, but different in DWARF output. // Sort by source position to ensure deterministic order. // See issues 27013 and 30202. - if a[i].t.Kind() == types.TINTER && a[i].t.Methods().Len() > 0 { - return a[i].t.Methods().Index(0).Pos.Before(a[j].t.Methods().Index(0).Pos) + if a[i].t.Kind() == types.TINTER && a[i].t.AllMethods().Len() > 0 { + return a[i].t.AllMethods().Index(0).Pos.Before(a[j].t.AllMethods().Index(0).Pos) } return false } diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 175216f279..922a01bfbe 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -204,8 +204,20 @@ assignOK: r.Use = ir.CallUseList rtyp := r.Type() + mismatched := false + failed := false for i := range lhs { - assignType(i, rtyp.Field(i).Type) + result := rtyp.Field(i).Type + assignType(i, result) + + if lhs[i].Type() == nil || result == nil { + failed = true + } else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) { + mismatched = true + } + } + if mismatched && !failed { + rewriteMultiValueCall(stmt, r) } return } diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index a6b21f948a..8454b8d5b3 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -941,16 +941,18 @@ func typecheckargs(n ir.InitNode) { return } - // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). - // Save n as n.Orig for fmt.go. if ir.Orig(n) == n { n.(ir.OrigNode).SetOrig(ir.SepCopy(n)) } - as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil) - as.Rhs.Append(list...) + // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). + rewriteMultiValueCall(n, list[0]) +} +// rewriteMultiValueCall rewrites multi-valued f() to use temporaries, +// so the backend wouldn't need to worry about tuple-valued expressions. +func rewriteMultiValueCall(n ir.InitNode, call ir.Node) { // 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 @@ -960,25 +962,40 @@ func typecheckargs(n ir.InitNode) { if static { ir.CurFunc = InitTodoFunc } - list = nil - for _, f := range t.FieldSlice() { - t := Temp(f.Type) - as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t)) - as.Lhs.Append(t) - list = append(list, t) + + as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, []ir.Node{call}) + results := call.Type().FieldSlice() + list := make([]ir.Node, len(results)) + for i, result := range results { + tmp := Temp(result.Type) + as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, tmp)) + as.Lhs.Append(tmp) + list[i] = tmp } if static { ir.CurFunc = nil } + n.PtrInit().Append(Stmt(as)) + switch n := n.(type) { + default: + base.Fatalf("rewriteMultiValueCall %+v", n.Op()) case *ir.CallExpr: n.Args = list case *ir.ReturnStmt: n.Results = list + case *ir.AssignListStmt: + if n.Op() != ir.OAS2FUNC { + base.Fatalf("rewriteMultiValueCall: invalid op %v", n.Op()) + } + as.SetOp(ir.OAS2FUNC) + n.SetOp(ir.OAS2) + n.Rhs = make([]ir.Node, len(list)) + for i, tmp := range list { + n.Rhs[i] = AssignConv(tmp, n.Lhs[i].Type(), "assignment") + } } - - n.PtrInit().Append(Stmt(as)) } func checksliceindex(l ir.Node, r ir.Node, tp *types.Type) bool { diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index fe2c62cd4f..26da6e3145 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -313,7 +313,7 @@ func mayCall(n ir.Node) bool { return true case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR, - ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD: + ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD, ir.OSLICE2ARRPTR: // These ops might panic, make sure they are done // before we start marshaling args for a call. See issue 16760. return true diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index bc49c6d804..1ed2c0f631 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -737,9 +737,9 @@ func (t *tester) registerTests() { fn: func(dt *distTest) error { cmd := t.addCmd(dt, "misc/swig/callback", t.goTest()) cmd.Env = append(os.Environ(), - "CGO_CFLAGS=-flto", - "CGO_CXXFLAGS=-flto", - "CGO_LDFLAGS=-flto", + "CGO_CFLAGS=-flto -Wno-lto-type-mismatch", + "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch", + "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch", ) return nil }, diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 1aa0320d07..cd03968eed 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -7,7 +7,7 @@ require ( github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect - golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd + golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9 diff --git a/src/cmd/go.sum b/src/cmd/go.sum index eeb625fcf8..d728acaec9 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -13,8 +13,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd h1:CuRnpyMrCCBulv0d/y0CswR4K0vGydgE3DZ2wYPIOo8= -golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY= +golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index a059a6dd90..c0c86ab9f5 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -72,7 +72,6 @@ func tooSlow(t *testing.T) { // (temp) directory. var testGOROOT string -var testCC string var testGOCACHE string var testGo string @@ -179,13 +178,6 @@ func TestMain(m *testing.M) { os.Exit(2) } - out, err = exec.Command(gotool, "env", "CC").CombinedOutput() - if err != nil { - fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out) - os.Exit(2) - } - testCC = strings.TrimSpace(string(out)) - cmd := exec.Command(testGo, "env", "CGO_ENABLED") cmd.Stderr = new(strings.Builder) if out, err := cmd.Output(); err != nil { @@ -2185,7 +2177,7 @@ func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) { // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 section := f.Section(".edata") if section == nil { - t.Fatalf(".edata section is not present") + t.Skip(".edata section is not present") } // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go type IMAGE_EXPORT_DIRECTORY struct { diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 53aaf311ec..7cb9ec6d94 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -724,8 +724,18 @@ func runList(ctx context.Context, cmd *base.Command, args []string) { // Record non-identity import mappings in p.ImportMap. for _, p := range pkgs { - for i, srcPath := range p.Internal.RawImports { - path := p.Imports[i] + nRaw := len(p.Internal.RawImports) + for i, path := range p.Imports { + var srcPath string + if i < nRaw { + srcPath = p.Internal.RawImports[i] + } else { + // This path is not within the raw imports, so it must be an import + // found only within CompiledGoFiles. Those paths are found in + // CompiledImports. + srcPath = p.Internal.CompiledImports[i-nRaw] + } + if path != srcPath { if p.ImportMap == nil { p.ImportMap = make(map[string]string) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 738904865e..a83cc9a812 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -194,8 +194,8 @@ type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package Imports []*Package // this package's direct imports - CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library) - RawImports []string // this package's original imports as they appear in the text of the program + CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports + RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports ForceLibrary bool // this package is a library (even if named "main") CmdlineFiles bool // package built from files listed on command line CmdlinePkg bool // package listed on command line diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index f76befcfe3..60bd26fb22 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -178,11 +178,13 @@ func (e *ImportMissingSumError) Error() string { // Importing package is unknown, or the missing package was named on the // command line. Recommend 'go mod download' for the modules that could // provide the package, since that shouldn't change go.mod. - args := make([]string, len(e.mods)) - for i, mod := range e.mods { - args[i] = mod.Path + if len(e.mods) > 0 { + args := make([]string, len(e.mods)) + for i, mod := range e.mods { + args[i] = mod.Path + } + hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " ")) } - hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " ")) } else { // Importing package is known (common case). Recommend 'go get' on the // current version of the importing package. diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index ea404b9f78..eb9cfe629b 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -999,10 +999,14 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements) Indirect: !rs.direct[m.Path], }) } - modFile.SetRequire(list) if goVersion != "" { modFile.AddGoStmt(goVersion) } + if semver.Compare("v"+modFileGoVersion(), separateIndirectVersionV) < 0 { + modFile.SetRequire(list) + } else { + modFile.SetRequireSeparateIndirect(list) + } modFile.Cleanup() dirty := index.modFileIsDirty(modFile) diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index a9c3a91d35..1145ac4ba5 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -35,6 +35,11 @@ const ( // module's go.mod file is expected to list explicit requirements on every // module that provides any package transitively imported by that module. lazyLoadingVersionV = "v1.17" + + // separateIndirectVersionV is the Go version (plus leading "v") at which + // "// indirect" dependencies are added in a block separate from the direct + // ones. See https://golang.org/issue/45965. + separateIndirectVersionV = "v1.17" ) const ( diff --git a/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt new file mode 100644 index 0000000000..3d68ef3055 --- /dev/null +++ b/src/cmd/go/testdata/script/list_cgo_compiled_importmap.txt @@ -0,0 +1,38 @@ +# Regression test for https://golang.org/issue/46462. +# +# The "runtime/cgo" import found in synthesized .go files (reported in +# the CompiledGoFiles field) should have a corresponding entry in the +# ImportMap field when a runtime/cgo variant (such as a test variant) +# will be used. + +[short] skip # -compiled can be slow (because it compiles things) +[!cgo] skip + +env CGO_ENABLED=1 +env GOFLAGS=-tags=netcgo # Force net to use cgo even on Windows. + + +# "runtime/cgo [runtime.test]" appears in the the test dependencies of "runtime", +# because "runtime/cgo" itself depends on "runtime" + +go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .Imports}}{{end}}' runtime + + # Control case: the explicitly-imported package "sync" is a test variant, + # because "sync" depends on "runtime". +stdout '"sync \[runtime\.test\]"' +! stdout '"sync"' + + # Experiment: the implicitly-imported package "runtime/cgo" is also a test variant, + # because "runtime/cgo" also depends on "runtime". +stdout '"runtime/cgo \[runtime\.test\]"' +! stdout '"runtime/cgo"' + + +# Because the import of "runtime/cgo" in the cgo-generated file actually refers +# to "runtime/cgo [runtime.test]", the latter should be listed in the ImportMap. +# BUG(#46462): Today, it is not. + +go list -deps -test -compiled -f '{{if eq .ImportPath "net [runtime.test]"}}{{printf "%q" .ImportMap}}{{end}}' runtime + +stdout '"sync":"sync \[runtime\.test\]"' # control +stdout '"runtime/cgo":"runtime/cgo \[runtime\.test\]"' # experiment diff --git a/src/cmd/go/testdata/script/mod_go_version_missing.txt b/src/cmd/go/testdata/script/mod_go_version_missing.txt index aca36a0450..d704816729 100644 --- a/src/cmd/go/testdata/script/mod_go_version_missing.txt +++ b/src/cmd/go/testdata/script/mod_go_version_missing.txt @@ -73,10 +73,9 @@ module example.com/m go $goversion -require ( - example.com/dep v0.1.0 - example.com/testdep v0.1.0 // indirect -) +require example.com/dep v0.1.0 + +require example.com/testdep v0.1.0 // indirect replace ( example.com/dep v0.1.0 => ./dep diff --git a/src/cmd/go/testdata/script/mod_install_hint.txt b/src/cmd/go/testdata/script/mod_install_hint.txt new file mode 100644 index 0000000000..ab02840eb8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_hint.txt @@ -0,0 +1,5 @@ +# Module is replaced but not required. No hint appears as no module is suggested.
+go mod init m
+go mod edit -replace=github.com/notrequired@v0.5.0=github.com/doesnotexist@v0.5.0
+! go install github.com/notrequired
+! stderr 'to add it:'
\ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt index 34d9c47674..6846a792a5 100644 --- a/src/cmd/go/testdata/script/mod_invalid_version.txt +++ b/src/cmd/go/testdata/script/mod_invalid_version.txt @@ -19,7 +19,7 @@ cp go.mod.orig go.mod go mod edit -require golang.org/x/text@14c0d48ead0c cd outside ! go list -m golang.org/x/text -stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\..\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3' +stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3' cd .. go list -m golang.org/x/text stdout 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' @@ -47,10 +47,10 @@ cp go.mod.orig go.mod go mod edit -require golang.org/x/text@v2.1.1-0.20170915032832-14c0d48ead0c cd outside ! go list -m golang.org/x/text -stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' cd .. ! go list -m golang.org/x/text -stderr $WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +stderr $WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' # A pseudo-version with fewer than 12 digits of SHA-1 prefix is invalid. cp go.mod.orig go.mod diff --git a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt index 3dc1515df2..97718c4513 100644 --- a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt +++ b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt @@ -139,9 +139,10 @@ go 1.17 require ( a v0.1.0 b v0.1.0 - c v0.1.0 // indirect ) +require c v0.1.0 // indirect + replace ( a v0.1.0 => ./a1 b v0.1.0 => ./b1 diff --git a/src/cmd/go/testdata/script/mod_lazy_new_import.txt b/src/cmd/go/testdata/script/mod_lazy_new_import.txt index 86b14b64b6..4272a52de1 100644 --- a/src/cmd/go/testdata/script/mod_lazy_new_import.txt +++ b/src/cmd/go/testdata/script/mod_lazy_new_import.txt @@ -78,10 +78,9 @@ module example.com/lazy go 1.17 -require ( - example.com/a v0.1.0 - example.com/b v0.1.0 // indirect -) +require example.com/a v0.1.0 + +require example.com/b v0.1.0 // indirect replace ( example.com/a v0.1.0 => ./a @@ -94,8 +93,9 @@ module example.com/lazy go 1.17 +require example.com/a v0.1.0 + require ( - example.com/a v0.1.0 example.com/b v0.1.0 // indirect example.com/c v0.1.0 // indirect ) diff --git a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt index 722712d1f2..68a5b6dca2 100644 --- a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt +++ b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt @@ -148,10 +148,9 @@ module example.com/lazy go 1.17 -require ( - example.com/a v0.1.0 - example.com/b v0.1.0 // indirect -) +require example.com/a v0.1.0 + +require example.com/b v0.1.0 // indirect replace ( example.com/a v0.1.0 => ./a diff --git a/src/cmd/go/testdata/script/mod_retention.txt b/src/cmd/go/testdata/script/mod_retention.txt index 0e639db551..7a371b1806 100644 --- a/src/cmd/go/testdata/script/mod_retention.txt +++ b/src/cmd/go/testdata/script/mod_retention.txt @@ -140,8 +140,9 @@ module m go $goversion require ( - golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect rsc.io/quote v1.5.2 rsc.io/sampler v1.3.0 // indirect rsc.io/testonly v1.0.0 // indirect ) + +require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect diff --git a/src/cmd/go/testdata/script/mod_tidy_convergence.txt b/src/cmd/go/testdata/script/mod_tidy_convergence.txt index 22c8fc66c5..09c46f764b 100644 --- a/src/cmd/go/testdata/script/mod_tidy_convergence.txt +++ b/src/cmd/go/testdata/script/mod_tidy_convergence.txt @@ -90,7 +90,6 @@ cmp go.mod go.mod.postget cp go.mod.orig go.mod go mod edit -go=1.17 go.mod go mod edit -go=1.17 go.mod.tidye -go mod edit -go=1.17 go.mod.postget go mod tidy -e cmp go.mod go.mod.tidye @@ -99,7 +98,7 @@ stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provid go get -d example.net/x@v0.1.0 example.net/y@v0.1.0 go mod tidy -cmp go.mod go.mod.postget +cmp go.mod go.mod.postget-117 -- go.mod -- @@ -144,6 +143,21 @@ require ( example.net/x v0.1.0 example.net/y v0.1.0 // indirect ) +-- go.mod.postget-117 -- +module example.net/m + +go 1.17 + +replace ( + example.net/x v0.1.0 => ./x1 + example.net/x v0.2.0-pre => ./x2-pre + example.net/y v0.1.0 => ./y1 + example.net/y v0.2.0 => ./y2 +) + +require example.net/x v0.1.0 + +require example.net/y v0.1.0 // indirect -- m.go -- package m diff --git a/src/cmd/go/testdata/script/mod_tidy_version.txt b/src/cmd/go/testdata/script/mod_tidy_version.txt index eaa6ee7b0d..3bc97bcb1e 100644 --- a/src/cmd/go/testdata/script/mod_tidy_version.txt +++ b/src/cmd/go/testdata/script/mod_tidy_version.txt @@ -92,8 +92,9 @@ cmpenv go.mod go.mod.latest -- go.mod -- module example.com/m +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/c v0.1.0 // indirect example.net/d v0.1.0 // indirect ) @@ -118,8 +119,9 @@ module example.com/m go 1.15 +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/c v0.1.0 // indirect example.net/d v0.1.0 // indirect ) @@ -139,8 +141,9 @@ module example.com/m go 1.15 +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/c v0.1.0 // indirect example.net/d v0.2.0 // indirect ) @@ -160,10 +163,9 @@ module example.com/m go 1.16 -require ( - example.net/a v0.1.0 - example.net/c v0.1.0 // indirect -) +require example.net/a v0.1.0 + +require example.net/c v0.1.0 // indirect replace ( example.net/a v0.1.0 => ./a @@ -180,8 +182,9 @@ module example.com/m go 1.17 +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/b v0.1.0 // indirect example.net/c v0.1.0 // indirect ) @@ -201,8 +204,9 @@ module example.com/m go $goversion +require example.net/a v0.1.0 + require ( - example.net/a v0.1.0 example.net/b v0.1.0 // indirect example.net/c v0.1.0 // indirect ) diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 1b71a66c6f..efca824d98 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -699,12 +699,18 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) { p := r.Data(li) rdup, ldup := l.toLocal(dup) pdup := rdup.Data(ldup) - if bytes.Equal(p, pdup) { - return - } reason := "same length but different contents" if len(p) != len(pdup) { reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup)) + } else if bytes.Equal(p, pdup) { + // For BSS symbols, we need to check size as well, see issue 46653. + szdup := l.SymSize(dup) + sz := int64(r.Sym(li).Siz()) + if szdup == sz { + return + } + reason = fmt.Sprintf("different sizes: new size %d != old size %d", + sz, szdup) } fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 4a580991ef..fed9c7bc3f 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -470,10 +470,30 @@ TEXT ·f(SB), NOSPLIT|DUPOK, $0-0 JMP 0(PC) ` +const testStrictDupAsmSrc3 = ` +#include "textflag.h" +GLOBL ·rcon(SB), RODATA|DUPOK, $64 +` + +const testStrictDupAsmSrc4 = ` +#include "textflag.h" +GLOBL ·rcon(SB), RODATA|DUPOK, $32 +` + func TestStrictDup(t *testing.T) { // Check that -strictdups flag works. testenv.MustHaveGoBuild(t) + asmfiles := []struct { + fname string + payload string + }{ + {"a", testStrictDupAsmSrc1}, + {"b", testStrictDupAsmSrc2}, + {"c", testStrictDupAsmSrc3}, + {"d", testStrictDupAsmSrc4}, + } + t.Parallel() tmpdir := t.TempDir() @@ -483,15 +503,12 @@ func TestStrictDup(t *testing.T) { if err != nil { t.Fatal(err) } - src = filepath.Join(tmpdir, "a.s") - err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666) - if err != nil { - t.Fatal(err) - } - src = filepath.Join(tmpdir, "b.s") - err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666) - if err != nil { - t.Fatal(err) + for _, af := range asmfiles { + src = filepath.Join(tmpdir, af.fname+".s") + err = ioutil.WriteFile(src, []byte(af.payload), 0666) + if err != nil { + t.Fatal(err) + } } src = filepath.Join(tmpdir, "go.mod") err = ioutil.WriteFile(src, []byte("module teststrictdup\n"), 0666) @@ -503,7 +520,7 @@ func TestStrictDup(t *testing.T) { cmd.Dir = tmpdir out, err := cmd.CombinedOutput() if err != nil { - t.Errorf("linking with -strictdups=1 failed: %v", err) + t.Errorf("linking with -strictdups=1 failed: %v\n%s", err, string(out)) } if !bytes.Contains(out, []byte("mismatched payload")) { t.Errorf("unexpected output:\n%s", out) @@ -515,7 +532,11 @@ func TestStrictDup(t *testing.T) { if err == nil { t.Errorf("linking with -strictdups=2 did not fail") } - if !bytes.Contains(out, []byte("mismatched payload")) { + // NB: on amd64 we get the 'new length' error, on arm64 the 'different + // contents' error. + if !(bytes.Contains(out, []byte("mismatched payload: new length")) || + bytes.Contains(out, []byte("mismatched payload: same length but different contents"))) || + !bytes.Contains(out, []byte("mismatched payload: different sizes")) { t.Errorf("unexpected output:\n%s", out) } } diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/read.go b/src/cmd/vendor/golang.org/x/mod/modfile/read.go index 2a961ca81c..956f30cbb3 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go @@ -194,12 +194,15 @@ func (x *FileSyntax) updateLine(line *Line, tokens ...string) { line.Token = tokens } -func (x *FileSyntax) removeLine(line *Line) { +// markRemoved modifies line so that it (and its end-of-line comment, if any) +// will be dropped by (*FileSyntax).Cleanup. +func (line *Line) markRemoved() { line.Token = nil + line.Comments.Suffix = nil } // Cleanup cleans up the file syntax x after any edit operations. -// To avoid quadratic behavior, removeLine marks the line as dead +// To avoid quadratic behavior, (*Line).markRemoved marks the line as dead // by setting line.Token = nil but does not remove it from the slice // in which it appears. After edits have all been indicated, // calling Cleanup cleans out the dead lines. diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go index 7299e15500..78f83fa714 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/rule.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/rule.go @@ -58,13 +58,6 @@ type Go struct { Syntax *Line } -// A Require is a single require statement. -type Require struct { - Mod module.Version - Indirect bool // has "// indirect" comment - Syntax *Line -} - // An Exclude is a single exclude statement. type Exclude struct { Mod module.Version @@ -93,6 +86,93 @@ type VersionInterval struct { Low, High string } +// A Require is a single require statement. +type Require struct { + Mod module.Version + Indirect bool // has "// indirect" comment + Syntax *Line +} + +func (r *Require) markRemoved() { + r.Syntax.markRemoved() + *r = Require{} +} + +func (r *Require) setVersion(v string) { + r.Mod.Version = v + + if line := r.Syntax; len(line.Token) > 0 { + if line.InBlock { + // If the line is preceded by an empty line, remove it; see + // https://golang.org/issue/33779. + if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 { + line.Comments.Before = line.Comments.Before[:0] + } + if len(line.Token) >= 2 { // example.com v1.2.3 + line.Token[1] = v + } + } else { + if len(line.Token) >= 3 { // require example.com v1.2.3 + line.Token[2] = v + } + } + } +} + +// setIndirect sets line to have (or not have) a "// indirect" comment. +func (r *Require) setIndirect(indirect bool) { + r.Indirect = indirect + line := r.Syntax + if isIndirect(line) == indirect { + return + } + if indirect { + // Adding comment. + if len(line.Suffix) == 0 { + // New comment. + line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} + return + } + + com := &line.Suffix[0] + text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash))) + if text == "" { + // Empty comment. + com.Token = "// indirect" + return + } + + // Insert at beginning of existing comment. + com.Token = "// indirect; " + text + return + } + + // Removing comment. + f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) + if f == "indirect" { + // Remove whole comment. + line.Suffix = nil + return + } + + // Remove comment prefix. + com := &line.Suffix[0] + i := strings.Index(com.Token, "indirect;") + com.Token = "//" + com.Token[i+len("indirect;"):] +} + +// isIndirect reports whether line has a "// indirect" comment, +// meaning it is in go.mod only for its effect on indirect dependencies, +// so that it can be dropped entirely once the effective version of the +// indirect dependency reaches the given minimum version. +func isIndirect(line *Line) bool { + if len(line.Suffix) == 0 { + return false + } + f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) + return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;") +} + func (f *File) AddModuleStmt(path string) error { if f.Syntax == nil { f.Syntax = new(FileSyntax) @@ -476,58 +556,6 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) { } } -// isIndirect reports whether line has a "// indirect" comment, -// meaning it is in go.mod only for its effect on indirect dependencies, -// so that it can be dropped entirely once the effective version of the -// indirect dependency reaches the given minimum version. -func isIndirect(line *Line) bool { - if len(line.Suffix) == 0 { - return false - } - f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) - return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;") -} - -// setIndirect sets line to have (or not have) a "// indirect" comment. -func setIndirect(line *Line, indirect bool) { - if isIndirect(line) == indirect { - return - } - if indirect { - // Adding comment. - if len(line.Suffix) == 0 { - // New comment. - line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} - return - } - - com := &line.Suffix[0] - text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash))) - if text == "" { - // Empty comment. - com.Token = "// indirect" - return - } - - // Insert at beginning of existing comment. - com.Token = "// indirect; " + text - return - } - - // Removing comment. - f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) - if f == "indirect" { - // Remove whole comment. - line.Suffix = nil - return - } - - // Remove comment prefix. - com := &line.Suffix[0] - i := strings.Index(com.Token, "indirect;") - com.Token = "//" + com.Token[i+len("indirect;"):] -} - // IsDirectoryPath reports whether the given path should be interpreted // as a directory path. Just like on the go command line, relative paths // and rooted paths are directory paths; the rest are module paths. @@ -835,6 +863,12 @@ func (f *File) AddGoStmt(version string) error { return nil } +// AddRequire sets the first require line for path to version vers, +// preserving any existing comments for that line and removing all +// other lines for path. +// +// If no line currently exists for path, AddRequire adds a new line +// at the end of the last require block. func (f *File) AddRequire(path, vers string) error { need := true for _, r := range f.Require { @@ -844,7 +878,7 @@ func (f *File) AddRequire(path, vers string) error { f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers) need = false } else { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Require{} } } @@ -856,69 +890,235 @@ func (f *File) AddRequire(path, vers string) error { return nil } +// AddNewRequire adds a new require line for path at version vers at the end of +// the last require block, regardless of any existing require lines for path. func (f *File) AddNewRequire(path, vers string, indirect bool) { line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers) - setIndirect(line, indirect) - f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line}) + r := &Require{ + Mod: module.Version{Path: path, Version: vers}, + Syntax: line, + } + r.setIndirect(indirect) + f.Require = append(f.Require, r) } +// SetRequire updates the requirements of f to contain exactly req, preserving +// the existing block structure and line comment contents (except for 'indirect' +// markings) for the first requirement on each named module path. +// +// The Syntax field is ignored for the requirements in req. +// +// Any requirements not already present in the file are added to the block +// containing the last require line. +// +// The requirements in req must specify at most one distinct version for each +// module path. +// +// If any existing requirements may be removed, the caller should call Cleanup +// after all edits are complete. func (f *File) SetRequire(req []*Require) { - need := make(map[string]string) - indirect := make(map[string]bool) + type elem struct { + version string + indirect bool + } + need := make(map[string]elem) for _, r := range req { - need[r.Mod.Path] = r.Mod.Version - indirect[r.Mod.Path] = r.Indirect + if prev, dup := need[r.Mod.Path]; dup && prev.version != r.Mod.Version { + panic(fmt.Errorf("SetRequire called with conflicting versions for path %s (%s and %s)", r.Mod.Path, prev.version, r.Mod.Version)) + } + need[r.Mod.Path] = elem{r.Mod.Version, r.Indirect} } + // Update or delete the existing Require entries to preserve + // only the first for each module path in req. for _, r := range f.Require { - if v, ok := need[r.Mod.Path]; ok { - r.Mod.Version = v - r.Indirect = indirect[r.Mod.Path] + e, ok := need[r.Mod.Path] + if ok { + r.setVersion(e.version) + r.setIndirect(e.indirect) } else { - *r = Require{} + r.markRemoved() + } + delete(need, r.Mod.Path) + } + + // Add new entries in the last block of the file for any paths that weren't + // already present. + // + // This step is nondeterministic, but the final result will be deterministic + // because we will sort the block. + for path, e := range need { + f.AddNewRequire(path, e.version, e.indirect) + } + + f.SortBlocks() +} + +// SetRequireSeparateIndirect updates the requirements of f to contain the given +// requirements. Comment contents (except for 'indirect' markings) are retained +// from the first existing requirement for each module path, and block structure +// is maintained as long as the indirect markings match. +// +// Any requirements on paths not already present in the file are added. Direct +// requirements are added to the last block containing *any* other direct +// requirement. Indirect requirements are added to the last block containing +// *only* other indirect requirements. If no suitable block exists, a new one is +// added, with the last block containing a direct dependency (if any) +// immediately before the first block containing only indirect dependencies. +// +// The Syntax field is ignored for requirements in the given blocks. +func (f *File) SetRequireSeparateIndirect(req []*Require) { + type modKey struct { + path string + indirect bool + } + need := make(map[modKey]string) + for _, r := range req { + need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version + } + + comments := make(map[string]Comments) + for _, r := range f.Require { + v, ok := need[modKey{r.Mod.Path, r.Indirect}] + if !ok { + if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok { + if _, dup := comments[r.Mod.Path]; !dup { + comments[r.Mod.Path] = r.Syntax.Comments + } + } + r.markRemoved() + continue } + r.setVersion(v) + delete(need, modKey{r.Mod.Path, r.Indirect}) } - var newStmts []Expr + var ( + lastDirectOrMixedBlock Expr + firstIndirectOnlyBlock Expr + lastIndirectOnlyBlock Expr + ) for _, stmt := range f.Syntax.Stmt { switch stmt := stmt.(type) { + case *Line: + if len(stmt.Token) == 0 || stmt.Token[0] != "require" { + continue + } + if isIndirect(stmt) { + lastIndirectOnlyBlock = stmt + } else { + lastDirectOrMixedBlock = stmt + } case *LineBlock: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - var newLines []*Line + if len(stmt.Token) == 0 || stmt.Token[0] != "require" { + continue + } + indirectOnly := true + for _, line := range stmt.Line { + if len(line.Token) == 0 { + continue + } + if !isIndirect(line) { + indirectOnly = false + break + } + } + if indirectOnly { + lastIndirectOnlyBlock = stmt + if firstIndirectOnlyBlock == nil { + firstIndirectOnlyBlock = stmt + } + } else { + lastDirectOrMixedBlock = stmt + } + } + } + + isOrContainsStmt := func(stmt Expr, target Expr) bool { + if stmt == target { + return true + } + if stmt, ok := stmt.(*LineBlock); ok { + if target, ok := target.(*Line); ok { for _, line := range stmt.Line { - if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" { - if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 { - line.Comments.Before = line.Comments.Before[:0] - } - line.Token[1] = need[p] - delete(need, p) - setIndirect(line, indirect[p]) - newLines = append(newLines, line) + if line == target { + return true } } - if len(newLines) == 0 { - continue // drop stmt - } - stmt.Line = newLines } + } + return false + } - case *Line: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" { - stmt.Token[2] = need[p] - delete(need, p) - setIndirect(stmt, indirect[p]) + addRequire := func(path, vers string, indirect bool, comments Comments) { + var line *Line + if indirect { + if lastIndirectOnlyBlock != nil { + line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers) + } else { + // Add a new require block after the last direct-only or mixed "require" + // block (if any). + // + // (f.Syntax.addLine would add the line to an existing "require" block if + // present, but here the existing "require" blocks are all direct-only, so + // we know we need to add a new block instead.) + line = &Line{Token: []string{"require", path, vers}} + lastIndirectOnlyBlock = line + firstIndirectOnlyBlock = line // only block implies first block + if lastDirectOrMixedBlock == nil { + f.Syntax.Stmt = append(f.Syntax.Stmt, line) } else { - continue // drop stmt + for i, stmt := range f.Syntax.Stmt { + if isOrContainsStmt(stmt, lastDirectOrMixedBlock) { + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size + copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up + f.Syntax.Stmt[i+1] = line + break + } + } + } + } + } else { + if lastDirectOrMixedBlock != nil { + line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers) + } else { + // Add a new require block before the first indirect block (if any). + // + // That way if the file initially contains only indirect lines, + // the direct lines still appear before it: we preserve existing + // structure, but only to the extent that that structure already + // reflects the direct/indirect split. + line = &Line{Token: []string{"require", path, vers}} + lastDirectOrMixedBlock = line + if firstIndirectOnlyBlock == nil { + f.Syntax.Stmt = append(f.Syntax.Stmt, line) + } else { + for i, stmt := range f.Syntax.Stmt { + if isOrContainsStmt(stmt, firstIndirectOnlyBlock) { + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size + copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up + f.Syntax.Stmt[i] = line + break + } + } } } } - newStmts = append(newStmts, stmt) + + line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before) + line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix) + + r := &Require{ + Mod: module.Version{Path: path, Version: vers}, + Indirect: indirect, + Syntax: line, + } + r.setIndirect(indirect) + f.Require = append(f.Require, r) } - f.Syntax.Stmt = newStmts - for path, vers := range need { - f.AddNewRequire(path, vers, indirect[path]) + for k, vers := range need { + addRequire(k.path, vers, k.indirect, comments[k.path]) } f.SortBlocks() } @@ -926,7 +1126,7 @@ func (f *File) SetRequire(req []*Require) { func (f *File) DropRequire(path string) error { for _, r := range f.Require { if r.Mod.Path == path { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Require{} } } @@ -957,7 +1157,7 @@ func (f *File) AddExclude(path, vers string) error { func (f *File) DropExclude(path, vers string) error { for _, x := range f.Exclude { if x.Mod.Path == path && x.Mod.Version == vers { - f.Syntax.removeLine(x.Syntax) + x.Syntax.markRemoved() *x = Exclude{} } } @@ -988,7 +1188,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { continue } // Already added; delete other replacements for same. - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Replace{} } if r.Old.Path == oldPath { @@ -1004,7 +1204,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { func (f *File) DropReplace(oldPath, oldVers string) error { for _, r := range f.Replace { if r.Old.Path == oldPath && r.Old.Version == oldVers { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Replace{} } } @@ -1045,7 +1245,7 @@ func (f *File) AddRetract(vi VersionInterval, rationale string) error { func (f *File) DropRetract(vi VersionInterval) error { for _, r := range f.Retract { if r.VersionInterval == vi { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Retract{} } } diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 9a1723d32c..34dbdaf5dd 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm ## explicit; go 1.17 golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 -# golang.org/x/mod v0.4.3-0.20210512182355-6088ed88cecd +# golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile |