summaryrefslogtreecommitdiffstats
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2022-02-18 13:10:34 -0800
committerIan Lance Taylor <iant@golang.org>2022-02-18 13:12:08 -0800
commit20a33efdf32bf0aedcb0c9813ddc7572bb1ab8c7 (patch)
tree94aec72c2092a11fa49f0b45da8e036f13416209 /libgo
parentpieces-memset-21.c: Expect vzeroupper for ia32 (diff)
downloadgcc-20a33efdf32bf0aedcb0c9813ddc7572bb1ab8c7.tar.gz
gcc-20a33efdf32bf0aedcb0c9813ddc7572bb1ab8c7.tar.bz2
gcc-20a33efdf32bf0aedcb0c9813ddc7572bb1ab8c7.tar.xz
libgo: update to Go1.18rc1 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/386594
Diffstat (limited to 'libgo')
-rw-r--r--libgo/MERGE2
-rw-r--r--libgo/Makefile.am6
-rw-r--r--libgo/Makefile.in9
-rw-r--r--libgo/VERSION2
-rw-r--r--libgo/go/builtin/builtin.go6
-rw-r--r--libgo/go/bytes/bytes.go4
-rw-r--r--libgo/go/cmd/go/alldocs.go38
-rw-r--r--libgo/go/cmd/go/go_test.go2
-rw-r--r--libgo/go/cmd/go/internal/base/flag.go7
-rw-r--r--libgo/go/cmd/go/internal/cfg/cfg.go6
-rw-r--r--libgo/go/cmd/go/internal/envcmd/env.go4
-rw-r--r--libgo/go/cmd/go/internal/help/helpdoc.go10
-rw-r--r--libgo/go/cmd/go/internal/list/list.go1
-rw-r--r--libgo/go/cmd/go/internal/load/pkg.go22
-rw-r--r--libgo/go/cmd/go/internal/modcmd/download.go1
-rw-r--r--libgo/go/cmd/go/internal/modcmd/graph.go1
-rw-r--r--libgo/go/cmd/go/internal/modcmd/verify.go1
-rw-r--r--libgo/go/cmd/go/internal/modcmd/why.go1
-rw-r--r--libgo/go/cmd/go/internal/modfetch/coderepo.go216
-rw-r--r--libgo/go/cmd/go/internal/modfetch/coderepo_test.go301
-rw-r--r--libgo/go/cmd/go/internal/modfetch/fetch.go11
-rw-r--r--libgo/go/cmd/go/internal/modload/import.go18
-rw-r--r--libgo/go/cmd/go/internal/modload/init.go35
-rw-r--r--libgo/go/cmd/go/internal/modload/load.go30
-rw-r--r--libgo/go/cmd/go/internal/run/run.go1
-rw-r--r--libgo/go/cmd/go/internal/test/testflag.go1
-rw-r--r--libgo/go/cmd/go/internal/version/version.go9
-rw-r--r--libgo/go/cmd/go/internal/vet/vet.go2
-rw-r--r--libgo/go/cmd/go/internal/work/build.go9
-rw-r--r--libgo/go/cmd/go/internal/work/exec.go1
-rw-r--r--libgo/go/cmd/go/internal/work/security.go1
-rw-r--r--libgo/go/cmd/go/internal/work/security_test.go1
-rw-r--r--libgo/go/cmd/go/internal/workcmd/edit.go46
-rw-r--r--libgo/go/cmd/go/internal/workcmd/init.go11
-rw-r--r--libgo/go/cmd/go/internal/workcmd/sync.go7
-rw-r--r--libgo/go/cmd/go/internal/workcmd/use.go147
-rw-r--r--libgo/go/cmd/go/internal/workcmd/work.go2
-rw-r--r--libgo/go/cmd/go/script_test.go8
-rw-r--r--libgo/go/cmd/go/testdata/script/build_internal.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_download_partial.txt11
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt6
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_invalid_version.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_dir.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_replace_dir.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/run_issue51125.txt54
-rw-r--r--libgo/go/cmd/go/testdata/script/test_fuzz_dup_cache.txt52
-rw-r--r--libgo/go/cmd/go/testdata/script/test_fuzz_return.txt19
-rw-r--r--libgo/go/cmd/go/testdata/script/test_relative_cmdline.txt2
-rw-r--r--libgo/go/cmd/go/testdata/script/work.txt8
-rw-r--r--libgo/go/cmd/go/testdata/script/work_edit.txt3
-rw-r--r--libgo/go/cmd/go/testdata/script/work_env.txt4
-rw-r--r--libgo/go/cmd/go/testdata/script/work_gowork.txt24
-rw-r--r--libgo/go/cmd/go/testdata/script/work_init_gowork.txt19
-rw-r--r--libgo/go/cmd/go/testdata/script/work_issue51204.txt57
-rw-r--r--libgo/go/cmd/go/testdata/script/work_module_not_in_go_work.txt25
-rw-r--r--libgo/go/cmd/go/testdata/script/work_nowork.txt20
-rw-r--r--libgo/go/cmd/go/testdata/script/work_replace_conflict.txt6
-rw-r--r--libgo/go/cmd/go/testdata/script/work_use_deleted.txt22
-rw-r--r--libgo/go/cmd/go/testdata/script/work_use_dot.txt49
-rw-r--r--libgo/go/cmd/go/testdata/script/work_use_issue50958.txt17
-rw-r--r--libgo/go/cmd/go/testdata/script/work_vet.txt19
-rw-r--r--libgo/go/cmd/go/testdata/script/work_workfile.txt21
-rw-r--r--libgo/go/cmd/gofmt/gofmt.go128
-rw-r--r--libgo/go/cmd/internal/objabi/funcdata.go1
-rw-r--r--libgo/go/crypto/ecdsa/ecdsa.go95
-rw-r--r--libgo/go/crypto/elliptic/elliptic.go45
-rw-r--r--libgo/go/crypto/elliptic/elliptic_test.go55
-rw-r--r--libgo/go/crypto/elliptic/gen_p256_table.go47
-rw-r--r--libgo/go/crypto/elliptic/p224.go3
-rw-r--r--libgo/go/crypto/elliptic/p256.go8
-rw-r--r--libgo/go/crypto/elliptic/p256_asm.go4
-rw-r--r--libgo/go/crypto/elliptic/p256_asm_table.go1430
-rw-r--r--libgo/go/crypto/elliptic/p384.go3
-rw-r--r--libgo/go/crypto/elliptic/p521.go3
-rw-r--r--libgo/go/crypto/x509/parser.go13
-rw-r--r--libgo/go/crypto/x509/parser_test.go102
-rw-r--r--libgo/go/database/sql/fakedb_test.go3
-rw-r--r--libgo/go/database/sql/sql_test.go31
-rw-r--r--libgo/go/debug/buildinfo/buildinfo.go4
-rw-r--r--libgo/go/debug/buildinfo/buildinfo_test.go10
-rw-r--r--libgo/go/go/build/deps_test.go3
-rw-r--r--libgo/go/go/doc/reader.go1
-rw-r--r--libgo/go/go/doc/testdata/b.0.golden3
-rw-r--r--libgo/go/go/doc/testdata/b.1.golden6
-rw-r--r--libgo/go/go/doc/testdata/b.2.golden3
-rw-r--r--libgo/go/go/doc/testdata/b.go6
-rw-r--r--libgo/go/go/parser/parser.go184
-rw-r--r--libgo/go/go/parser/resolver.go93
-rw-r--r--libgo/go/go/parser/short_test.go44
-rw-r--r--libgo/go/go/parser/testdata/resolution/typeparams.go210
-rw-r--r--libgo/go/go/parser/testdata/typeparams.src2
-rw-r--r--libgo/go/go/printer/nodes.go28
-rw-r--r--libgo/go/go/printer/testdata/generics.golden26
-rw-r--r--libgo/go/go/printer/testdata/generics.input26
-rw-r--r--libgo/go/go/types/api.go10
-rw-r--r--libgo/go/go/types/api_test.go100
-rw-r--r--libgo/go/go/types/builtins.go70
-rw-r--r--libgo/go/go/types/builtins_test.go6
-rw-r--r--libgo/go/go/types/call.go2
-rw-r--r--libgo/go/go/types/check.go13
-rw-r--r--libgo/go/go/types/errorcodes.go12
-rw-r--r--libgo/go/go/types/errors.go20
-rw-r--r--libgo/go/go/types/example_test.go2
-rw-r--r--libgo/go/go/types/expr.go220
-rw-r--r--libgo/go/go/types/index.go4
-rw-r--r--libgo/go/go/types/infer.go129
-rw-r--r--libgo/go/go/types/instantiate.go37
-rw-r--r--libgo/go/go/types/issues_test.go9
-rw-r--r--libgo/go/go/types/lookup.go209
-rw-r--r--libgo/go/go/types/methodlist.go9
-rw-r--r--libgo/go/go/types/named.go4
-rw-r--r--libgo/go/go/types/predicates.go25
-rw-r--r--libgo/go/go/types/stmt.go28
-rw-r--r--libgo/go/go/types/subst.go11
-rw-r--r--libgo/go/go/types/testdata/check/builtins.go26
-rw-r--r--libgo/go/go/types/testdata/check/builtins.src8
-rw-r--r--libgo/go/go/types/testdata/check/expr2.src28
-rw-r--r--libgo/go/go/types/testdata/check/issues.go211
-rw-r--r--libgo/go/go/types/testdata/check/issues.src48
-rw-r--r--libgo/go/go/types/testdata/check/stmt0.src2
-rw-r--r--libgo/go/go/types/testdata/check/typeparams.go249
-rw-r--r--libgo/go/go/types/testdata/examples/inference.go22
-rw-r--r--libgo/go/go/types/testdata/examples/types.go24
-rw-r--r--libgo/go/go/types/testdata/fixedbugs/issue39634.go22
-rw-r--r--libgo/go/go/types/testdata/fixedbugs/issue43110.src2
-rw-r--r--libgo/go/go/types/testdata/fixedbugs/issue49005.go31
-rw-r--r--libgo/go/go/types/testdata/fixedbugs/issue50918.go21
-rw-r--r--libgo/go/go/types/testdata/fixedbugs/issue50965.go17
-rw-r--r--libgo/go/go/types/testdata/fixedbugs/issue51145.go18
-rw-r--r--libgo/go/go/types/type.go10
-rw-r--r--libgo/go/go/types/typeparam.go6
-rw-r--r--libgo/go/go/types/typeset.go7
-rw-r--r--libgo/go/go/types/typexpr.go20
-rw-r--r--libgo/go/go/types/unify.go100
-rw-r--r--libgo/go/internal/cfg/cfg.go1
-rw-r--r--libgo/go/internal/fuzz/fuzz.go32
-rw-r--r--libgo/go/internal/fuzz/worker.go4
-rw-r--r--libgo/go/internal/nettrace/nettrace.go2
-rw-r--r--libgo/go/net/dnsclient_unix.go6
-rw-r--r--libgo/go/net/dnsclient_unix_test.go2
-rw-r--r--libgo/go/net/http/transport.go6
-rw-r--r--libgo/go/net/http/transport_internal_test.go9
-rw-r--r--libgo/go/net/lookup_test.go69
-rw-r--r--libgo/go/net/net_test.go64
-rw-r--r--libgo/go/net/netip/netip.go2
-rw-r--r--libgo/go/net/smtp/auth.go3
-rw-r--r--libgo/go/net/udpsock_test.go9
-rw-r--r--libgo/go/os/example_test.go22
-rw-r--r--libgo/go/os/os_test.go40
-rw-r--r--libgo/go/os/tempfile.go2
-rw-r--r--libgo/go/regexp/syntax/parse.go72
-rw-r--r--libgo/go/regexp/syntax/parse_test.go7
-rw-r--r--libgo/go/runtime/crash_cgo_test.go26
-rw-r--r--libgo/go/runtime/crash_unix_test.go2
-rw-r--r--libgo/go/runtime/debug/mod.go157
-rw-r--r--libgo/go/runtime/debug/mod_test.go75
-rw-r--r--libgo/go/runtime/export_test.go20
-rw-r--r--libgo/go/runtime/histogram.go52
-rw-r--r--libgo/go/runtime/histogram_test.go40
-rw-r--r--libgo/go/runtime/internal/syscall/errno.c27
-rw-r--r--libgo/go/runtime/internal/syscall/syscall_linux.go23
-rw-r--r--libgo/go/runtime/mbarrier.go2
-rw-r--r--libgo/go/runtime/mbitmap.go12
-rw-r--r--libgo/go/runtime/mgcmark.go2
-rw-r--r--libgo/go/runtime/mgcpacer.go72
-rw-r--r--libgo/go/runtime/mgcpacer_test.go45
-rw-r--r--libgo/go/runtime/mgcscavenge.go58
-rw-r--r--libgo/go/runtime/pprof/pprof_test.go67
-rw-r--r--libgo/go/runtime/proc.go143
-rw-r--r--libgo/go/runtime/runtime2.go19
-rw-r--r--libgo/go/runtime/sigqueue.go48
-rw-r--r--libgo/go/runtime/slice.go2
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/aprof.go7
-rw-r--r--libgo/go/runtime/testdata/testprogcgo/pprof_callback.go89
-rw-r--r--libgo/go/runtime/trace.go10
-rw-r--r--libgo/go/strings/strings.go4
-rw-r--r--libgo/go/syscall/syscall_linux_test.go71
-rw-r--r--libgo/go/syscall/syscall_unix_test.go21
-rw-r--r--libgo/go/testing/fuzz.go3
-rw-r--r--libgo/go/testing/testing.go3
-rw-r--r--libgo/go/time/format.go1
-rw-r--r--libgo/libgo-packages.txt1
-rwxr-xr-xlibgo/merge.sh12
-rw-r--r--libgo/misc/cgo/errors/badsym_test.go4
-rw-r--r--libgo/misc/cgo/test/test.go5
-rw-r--r--libgo/misc/cgo/testcarchive/carchive_test.go30
-rw-r--r--libgo/misc/cgo/testcshared/cshared_test.go3
187 files changed, 3699 insertions, 2975 deletions
diff --git a/libgo/MERGE b/libgo/MERGE
index 662af9af882..11da9a29dd0 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
141f485b9a7d8fd647c415be1d11b612063dff21c 1cb5a598d7f2ebd276686403d141a97c026d33458
2 2
3The first line of this file holds the git revision number of the 3The first line of this file holds the git revision number of the
4last merge done from the master library sources. 4last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 9318f38714a..e0a1eec52a2 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -817,6 +817,7 @@ libgo_go_objs = \
817 syscall/errno.lo \ 817 syscall/errno.lo \
818 syscall/signame.lo \ 818 syscall/signame.lo \
819 syscall/wait.lo \ 819 syscall/wait.lo \
820 runtime/internal/syscall/errno.lo \
820 os/dir_gccgo_c.lo \ 821 os/dir_gccgo_c.lo \
821 $(golangorg_x_net_lif_lo) \ 822 $(golangorg_x_net_lif_lo) \
822 $(golangorg_x_net_route_lo) \ 823 $(golangorg_x_net_route_lo) \
@@ -1180,6 +1181,11 @@ syscall/wait.lo: go/syscall/wait.c runtime.inc
1180 @$(MKDIR_P) syscall 1181 @$(MKDIR_P) syscall
1181 $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c 1182 $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
1182 1183
1184# Some runtime/internal/syscall functions are written in C.
1185runtime/internal/syscall/errno.lo: go/runtime/internal/syscall/errno.c runtime.inc
1186 @$(MKDIR_P) runtime/internal/syscall
1187 $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/syscall/errno.c
1188
1183# An os function is written in C. 1189# An os function is written in C.
1184os/dir_gccgo_c.lo: go/os/dir_gccgo_c.c runtime.inc 1190os/dir_gccgo_c.lo: go/os/dir_gccgo_c.c runtime.inc
1185 @$(MKDIR_P) os 1191 @$(MKDIR_P) os
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 642688e9dae..7bef5df90d1 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -225,7 +225,8 @@ LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
225am__DEPENDENCIES_3 = $(addsuffix .lo,$(PACKAGES)) \ 225am__DEPENDENCIES_3 = $(addsuffix .lo,$(PACKAGES)) \
226 internal/bytealg/bytealg.lo reflect/makefunc_ffi_c.lo \ 226 internal/bytealg/bytealg.lo reflect/makefunc_ffi_c.lo \
227 $(am__DEPENDENCIES_1) syscall/errno.lo syscall/signame.lo \ 227 $(am__DEPENDENCIES_1) syscall/errno.lo syscall/signame.lo \
228 syscall/wait.lo os/dir_gccgo_c.lo $(golangorg_x_net_lif_lo) \ 228 syscall/wait.lo runtime/internal/syscall/errno.lo \
229 os/dir_gccgo_c.lo $(golangorg_x_net_lif_lo) \
229 $(golangorg_x_net_route_lo) log/syslog/syslog_c.lo \ 230 $(golangorg_x_net_route_lo) log/syslog/syslog_c.lo \
230 runtime/internal/atomic_c.lo sync/atomic_c.lo \ 231 runtime/internal/atomic_c.lo sync/atomic_c.lo \
231 internal/cpu/cpu_gccgo.lo $(am__DEPENDENCIES_2) 232 internal/cpu/cpu_gccgo.lo $(am__DEPENDENCIES_2)
@@ -955,6 +956,7 @@ libgo_go_objs = \
955 syscall/errno.lo \ 956 syscall/errno.lo \
956 syscall/signame.lo \ 957 syscall/signame.lo \
957 syscall/wait.lo \ 958 syscall/wait.lo \
959 runtime/internal/syscall/errno.lo \
958 os/dir_gccgo_c.lo \ 960 os/dir_gccgo_c.lo \
959 $(golangorg_x_net_lif_lo) \ 961 $(golangorg_x_net_lif_lo) \
960 $(golangorg_x_net_route_lo) \ 962 $(golangorg_x_net_route_lo) \
@@ -3091,6 +3093,11 @@ syscall/wait.lo: go/syscall/wait.c runtime.inc
3091 @$(MKDIR_P) syscall 3093 @$(MKDIR_P) syscall
3092 $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c 3094 $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
3093 3095
3096# Some runtime/internal/syscall functions are written in C.
3097runtime/internal/syscall/errno.lo: go/runtime/internal/syscall/errno.c runtime.inc
3098 @$(MKDIR_P) runtime/internal/syscall
3099 $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/syscall/errno.c
3100
3094# An os function is written in C. 3101# An os function is written in C.
3095os/dir_gccgo_c.lo: go/os/dir_gccgo_c.c runtime.inc 3102os/dir_gccgo_c.lo: go/os/dir_gccgo_c.c runtime.inc
3096 @$(MKDIR_P) os 3103 @$(MKDIR_P) os
diff --git a/libgo/VERSION b/libgo/VERSION
index 301234bc893..6a12199bd21 100644
--- a/libgo/VERSION
+++ b/libgo/VERSION
@@ -1 +1 @@
go1.18beta2 go1.18rc1
diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go
index 08ae7ed313a..5657be45642 100644
--- a/libgo/go/builtin/builtin.go
+++ b/libgo/go/builtin/builtin.go
@@ -95,11 +95,11 @@ type rune = int32
95type any = interface{} 95type any = interface{}
96 96
97// comparable is an interface that is implemented by all comparable types 97// comparable is an interface that is implemented by all comparable types
98// (booleans, numbers, strings, pointers, channels, interfaces, 98// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
99// arrays of comparable types, structs whose fields are all comparable types). 99// structs whose fields are all comparable types).
100// The comparable interface may only be used as a type parameter constraint, 100// The comparable interface may only be used as a type parameter constraint,
101// not as the type of a variable. 101// not as the type of a variable.
102type comparable comparable 102type comparable interface{ comparable }
103 103
104// iota is a predeclared identifier representing the untyped integer ordinal 104// iota is a predeclared identifier representing the untyped integer ordinal
105// number of the current const specification in a (usually parenthesized) 105// number of the current const specification in a (usually parenthesized)
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
index 6fdaa49c734..41323ad549b 100644
--- a/libgo/go/bytes/bytes.go
+++ b/libgo/go/bytes/bytes.go
@@ -372,6 +372,8 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
372// n > 0: at most n subslices; the last subslice will be the unsplit remainder. 372// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
373// n == 0: the result is nil (zero subslices) 373// n == 0: the result is nil (zero subslices)
374// n < 0: all subslices 374// n < 0: all subslices
375//
376// To split around the first instance of a separator, see Cut.
375func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } 377func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
376 378
377// SplitAfterN slices s into subslices after each instance of sep and 379// SplitAfterN slices s into subslices after each instance of sep and
@@ -389,6 +391,8 @@ func SplitAfterN(s, sep []byte, n int) [][]byte {
389// the subslices between those separators. 391// the subslices between those separators.
390// If sep is empty, Split splits after each UTF-8 sequence. 392// If sep is empty, Split splits after each UTF-8 sequence.
391// It is equivalent to SplitN with a count of -1. 393// It is equivalent to SplitN with a count of -1.
394//
395// To split around the first instance of a separator, see Cut.
392func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) } 396func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
393 397
394// SplitAfter slices s into all subslices after each instance of sep and 398// SplitAfter slices s into all subslices after each instance of sep and
diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go
index 826b0ccf19c..63e7900e02f 100644
--- a/libgo/go/cmd/go/alldocs.go
+++ b/libgo/go/cmd/go/alldocs.go
@@ -177,14 +177,6 @@
177// directory, but it is not accessed. When -modfile is specified, an 177// directory, but it is not accessed. When -modfile is specified, an
178// alternate go.sum file is also used: its path is derived from the 178// alternate go.sum file is also used: its path is derived from the
179// -modfile flag by trimming the ".mod" extension and appending ".sum". 179// -modfile flag by trimming the ".mod" extension and appending ".sum".
180// -workfile file
181// in module aware mode, use the given go.work file as a workspace file.
182// By default or when -workfile is "auto", the go command searches for a
183// file named go.work in the current directory and then containing directories
184// until one is found. If a valid go.work file is found, the modules
185// specified will collectively be used as the main modules. If -workfile
186// is "off", or a go.work file is not found in "auto" mode, workspace
187// mode is disabled.
188// -overlay file 180// -overlay file
189// read a JSON config file that provides an overlay for build operations. 181// read a JSON config file that provides an overlay for build operations.
190// The file is a JSON struct with a single field, named 'Replace', that 182// The file is a JSON struct with a single field, named 'Replace', that
@@ -1379,7 +1371,7 @@
1379// builds from local modules. 1371// builds from local modules.
1380// 1372//
1381// go.work files are line-oriented. Each line holds a single directive, 1373// go.work files are line-oriented. Each line holds a single directive,
1382// made up of a keyword followed by aruments. For example: 1374// made up of a keyword followed by arguments. For example:
1383// 1375//
1384// go 1.18 1376// go 1.18
1385// 1377//
@@ -1472,19 +1464,14 @@
1472// The -json flag prints the final go.work file in JSON format instead of 1464// The -json flag prints the final go.work file in JSON format instead of
1473// writing it back to go.mod. The JSON output corresponds to these Go types: 1465// writing it back to go.mod. The JSON output corresponds to these Go types:
1474// 1466//
1475// type Module struct {
1476// Path string
1477// Version string
1478// }
1479//
1480// type GoWork struct { 1467// type GoWork struct {
1481// Go string 1468// Go string
1482// Directory []Directory 1469// Use []Use
1483// Replace []Replace 1470// Replace []Replace
1484// } 1471// }
1485// 1472//
1486// type Use struct { 1473// type Use struct {
1487// Path string 1474// DiskPath string
1488// ModulePath string 1475// ModulePath string
1489// } 1476// }
1490// 1477//
@@ -1493,6 +1480,11 @@
1493// New Module 1480// New Module
1494// } 1481// }
1495// 1482//
1483// type Module struct {
1484// Path string
1485// Version string
1486// }
1487//
1496// See the workspaces design proposal at 1488// See the workspaces design proposal at
1497// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for 1489// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
1498// more information. 1490// more information.
@@ -2036,6 +2028,8 @@
2036// GOENV 2028// GOENV
2037// The location of the Go environment configuration file. 2029// The location of the Go environment configuration file.
2038// Cannot be set using 'go env -w'. 2030// Cannot be set using 'go env -w'.
2031// Setting GOENV=off in the environment disables the use of the
2032// default configuration file.
2039// GOFLAGS 2033// GOFLAGS
2040// A space-separated list of -flag=value settings to apply 2034// A space-separated list of -flag=value settings to apply
2041// to go commands by default, when the given flag is known by 2035// to go commands by default, when the given flag is known by
@@ -2073,6 +2067,14 @@
2073// GOVCS 2067// GOVCS
2074// Lists version control commands that may be used with matching servers. 2068// Lists version control commands that may be used with matching servers.
2075// See 'go help vcs'. 2069// See 'go help vcs'.
2070// GOWORK
2071// In module aware mode, use the given go.work file as a workspace file.
2072// By default or when GOWORK is "auto", the go command searches for a
2073// file named go.work in the current directory and then containing directories
2074// until one is found. If a valid go.work file is found, the modules
2075// specified will collectively be used as the main modules. If GOWORK
2076// is "off", or a go.work file is not found in "auto" mode, workspace
2077// mode is disabled.
2076// 2078//
2077// Environment variables for use with cgo: 2079// Environment variables for use with cgo:
2078// 2080//
diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go
index 7aaec4eb986..1ea347ca6e5 100644
--- a/libgo/go/cmd/go/go_test.go
+++ b/libgo/go/cmd/go/go_test.go
@@ -133,7 +133,7 @@ func TestMain(m *testing.M) {
133 } 133 }
134 gotool, err := testenv.GoTool() 134 gotool, err := testenv.GoTool()
135 if err != nil { 135 if err != nil {
136 fmt.Fprintln(os.Stderr, err) 136 fmt.Fprintln(os.Stderr, "locating go tool: ", err)
137 os.Exit(2) 137 os.Exit(2)
138 } 138 }
139 139
diff --git a/libgo/go/cmd/go/internal/base/flag.go b/libgo/go/cmd/go/internal/base/flag.go
index 2c72c7e562b..120420a1265 100644
--- a/libgo/go/cmd/go/internal/base/flag.go
+++ b/libgo/go/cmd/go/internal/base/flag.go
@@ -62,13 +62,6 @@ func AddModFlag(flags *flag.FlagSet) {
62 flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "") 62 flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
63} 63}
64 64
65// AddWorkfileFlag adds the workfile flag to the flag set. It enables workspace
66// mode for commands that support it by resetting the cfg.WorkFile variable
67// to "" (equivalent to auto) rather than off.
68func AddWorkfileFlag(flags *flag.FlagSet) {
69 flags.Var(explicitStringFlag{value: &cfg.WorkFile, explicit: &cfg.WorkFileExplicit}, "workfile", "")
70}
71
72// AddModCommonFlags adds the module-related flags common to build commands 65// AddModCommonFlags adds the module-related flags common to build commands
73// and 'go mod' subcommands. 66// and 'go mod' subcommands.
74func AddModCommonFlags(flags *flag.FlagSet) { 67func AddModCommonFlags(flags *flag.FlagSet) {
diff --git a/libgo/go/cmd/go/internal/cfg/cfg.go b/libgo/go/cmd/go/internal/cfg/cfg.go
index 7f68d7bb628..deab3dddd0d 100644
--- a/libgo/go/cmd/go/internal/cfg/cfg.go
+++ b/libgo/go/cmd/go/internal/cfg/cfg.go
@@ -49,10 +49,8 @@ var (
49 BuildWork bool // -work flag 49 BuildWork bool // -work flag
50 BuildX bool // -x flag 50 BuildX bool // -x flag
51 51
52 ModCacheRW bool // -modcacherw flag 52 ModCacheRW bool // -modcacherw flag
53 ModFile string // -modfile flag 53 ModFile string // -modfile flag
54 WorkFile string // -workfile flag
55 WorkFileExplicit bool // whether -workfile was set explicitly
56 54
57 CmdName string // "build", "install", "list", "mod tidy", etc. 55 CmdName string // "build", "install", "list", "mod tidy", etc.
58 56
diff --git a/libgo/go/cmd/go/internal/envcmd/env.go b/libgo/go/cmd/go/internal/envcmd/env.go
index e56dd8223f0..c1adf8cef4c 100644
--- a/libgo/go/cmd/go/internal/envcmd/env.go
+++ b/libgo/go/cmd/go/internal/envcmd/env.go
@@ -154,6 +154,10 @@ func ExtraEnvVars() []cfg.EnvVar {
154 } 154 }
155 modload.InitWorkfile() 155 modload.InitWorkfile()
156 gowork := modload.WorkFilePath() 156 gowork := modload.WorkFilePath()
157 // As a special case, if a user set off explicitly, report that in GOWORK.
158 if cfg.Getenv("GOWORK") == "off" {
159 gowork = "off"
160 }
157 return []cfg.EnvVar{ 161 return []cfg.EnvVar{
158 {Name: "GOMOD", Value: gomod}, 162 {Name: "GOMOD", Value: gomod},
159 {Name: "GOWORK", Value: gowork}, 163 {Name: "GOWORK", Value: gowork},
diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go
index 7dc066cfbad..28ddaac8f17 100644
--- a/libgo/go/cmd/go/internal/help/helpdoc.go
+++ b/libgo/go/cmd/go/internal/help/helpdoc.go
@@ -506,6 +506,8 @@ General-purpose environment variables:
506 GOENV 506 GOENV
507 The location of the Go environment configuration file. 507 The location of the Go environment configuration file.
508 Cannot be set using 'go env -w'. 508 Cannot be set using 'go env -w'.
509 Setting GOENV=off in the environment disables the use of the
510 default configuration file.
509 GOFLAGS 511 GOFLAGS
510 A space-separated list of -flag=value settings to apply 512 A space-separated list of -flag=value settings to apply
511 to go commands by default, when the given flag is known by 513 to go commands by default, when the given flag is known by
@@ -543,6 +545,14 @@ General-purpose environment variables:
543 GOVCS 545 GOVCS
544 Lists version control commands that may be used with matching servers. 546 Lists version control commands that may be used with matching servers.
545 See 'go help vcs'. 547 See 'go help vcs'.
548 GOWORK
549 In module aware mode, use the given go.work file as a workspace file.
550 By default or when GOWORK is "auto", the go command searches for a
551 file named go.work in the current directory and then containing directories
552 until one is found. If a valid go.work file is found, the modules
553 specified will collectively be used as the main modules. If GOWORK
554 is "off", or a go.work file is not found in "auto" mode, workspace
555 mode is disabled.
546 556
547Environment variables for use with cgo: 557Environment variables for use with cgo:
548 558
diff --git a/libgo/go/cmd/go/internal/list/list.go b/libgo/go/cmd/go/internal/list/list.go
index d9a7078ccf2..8be92119352 100644
--- a/libgo/go/cmd/go/internal/list/list.go
+++ b/libgo/go/cmd/go/internal/list/list.go
@@ -316,7 +316,6 @@ For more about modules, see https://golang.org/ref/mod.
316func init() { 316func init() {
317 CmdList.Run = runList // break init cycle 317 CmdList.Run = runList // break init cycle
318 work.AddBuildFlags(CmdList, work.DefaultBuildFlags) 318 work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
319 base.AddWorkfileFlag(&CmdList.Flag)
320} 319}
321 320
322var ( 321var (
diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go
index 67b359d19d2..44bd61caea7 100644
--- a/libgo/go/cmd/go/internal/load/pkg.go
+++ b/libgo/go/cmd/go/internal/load/pkg.go
@@ -819,11 +819,11 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
819 } 819 }
820 r := resolvedImportCache.Do(importKey, func() any { 820 r := resolvedImportCache.Do(importKey, func() any {
821 var r resolvedImport 821 var r resolvedImport
822 if build.IsLocalImport(path) { 822 if cfg.ModulesEnabled {
823 r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path)
824 } else if build.IsLocalImport(path) {
823 r.dir = filepath.Join(parentDir, path) 825 r.dir = filepath.Join(parentDir, path)
824 r.path = dirToImportPath(r.dir) 826 r.path = dirToImportPath(r.dir)
825 } else if cfg.ModulesEnabled {
826 r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path)
827 } else if mode&ResolveImport != 0 { 827 } else if mode&ResolveImport != 0 {
828 // We do our own path resolution, because we want to 828 // We do our own path resolution, because we want to
829 // find out the key to use in packageCache without the 829 // find out the key to use in packageCache without the
@@ -1113,6 +1113,7 @@ func dirAndRoot(path string, dir, root string) (string, string) {
1113 } 1113 }
1114 1114
1115 if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || path != "command-line-arguments" && !build.IsLocalImport(path) && filepath.Join(root, path) != dir { 1115 if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || path != "command-line-arguments" && !build.IsLocalImport(path) && filepath.Join(root, path) != dir {
1116 debug.PrintStack()
1116 base.Fatalf("unexpected directory layout:\n"+ 1117 base.Fatalf("unexpected directory layout:\n"+
1117 " import path: %s\n"+ 1118 " import path: %s\n"+
1118 " root: %s\n"+ 1119 " root: %s\n"+
@@ -2235,13 +2236,17 @@ func (p *Package) setBuildInfo() {
2235 2236
2236 var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module 2237 var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module
2237 debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module { 2238 debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module {
2239 version := mi.Version
2240 if version == "" {
2241 version = "(devel)"
2242 }
2238 dm := &debug.Module{ 2243 dm := &debug.Module{
2239 Path: mi.Path, 2244 Path: mi.Path,
2240 Version: mi.Version, 2245 Version: version,
2241 } 2246 }
2242 if mi.Replace != nil { 2247 if mi.Replace != nil {
2243 dm.Replace = debugModFromModinfo(mi.Replace) 2248 dm.Replace = debugModFromModinfo(mi.Replace)
2244 } else { 2249 } else if mi.Version != "" {
2245 dm.Sum = modfetch.Sum(module.Version{Path: mi.Path, Version: mi.Version}) 2250 dm.Sum = modfetch.Sum(module.Version{Path: mi.Path, Version: mi.Version})
2246 } 2251 }
2247 return dm 2252 return dm
@@ -2424,12 +2429,7 @@ func (p *Package) setBuildInfo() {
2424 appendSetting("vcs.modified", strconv.FormatBool(st.Uncommitted)) 2429 appendSetting("vcs.modified", strconv.FormatBool(st.Uncommitted))
2425 } 2430 }
2426 2431
2427 text, err := info.MarshalText() 2432 p.Internal.BuildInfo = info.String()
2428 if err != nil {
2429 setPkgErrorf("error formatting build info: %v", err)
2430 return
2431 }
2432 p.Internal.BuildInfo = string(text)
2433} 2433}
2434 2434
2435// SafeArg reports whether arg is a "safe" command-line argument, 2435// SafeArg reports whether arg is a "safe" command-line argument,
diff --git a/libgo/go/cmd/go/internal/modcmd/download.go b/libgo/go/cmd/go/internal/modcmd/download.go
index 6b8a010fd9d..5bc6cbc4bb5 100644
--- a/libgo/go/cmd/go/internal/modcmd/download.go
+++ b/libgo/go/cmd/go/internal/modcmd/download.go
@@ -70,7 +70,6 @@ func init() {
70 // TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands. 70 // TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
71 cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "") 71 cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
72 base.AddModCommonFlags(&cmdDownload.Flag) 72 base.AddModCommonFlags(&cmdDownload.Flag)
73 base.AddWorkfileFlag(&cmdDownload.Flag)
74} 73}
75 74
76type moduleJSON struct { 75type moduleJSON struct {
diff --git a/libgo/go/cmd/go/internal/modcmd/graph.go b/libgo/go/cmd/go/internal/modcmd/graph.go
index 9b6aa1fb14d..9568c657404 100644
--- a/libgo/go/cmd/go/internal/modcmd/graph.go
+++ b/libgo/go/cmd/go/internal/modcmd/graph.go
@@ -42,7 +42,6 @@ var (
42func init() { 42func init() {
43 cmdGraph.Flag.Var(&graphGo, "go", "") 43 cmdGraph.Flag.Var(&graphGo, "go", "")
44 base.AddModCommonFlags(&cmdGraph.Flag) 44 base.AddModCommonFlags(&cmdGraph.Flag)
45 base.AddWorkfileFlag(&cmdGraph.Flag)
46} 45}
47 46
48func runGraph(ctx context.Context, cmd *base.Command, args []string) { 47func runGraph(ctx context.Context, cmd *base.Command, args []string) {
diff --git a/libgo/go/cmd/go/internal/modcmd/verify.go b/libgo/go/cmd/go/internal/modcmd/verify.go
index 3f0c005d5d9..459bf5d0700 100644
--- a/libgo/go/cmd/go/internal/modcmd/verify.go
+++ b/libgo/go/cmd/go/internal/modcmd/verify.go
@@ -39,7 +39,6 @@ See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
39 39
40func init() { 40func init() {
41 base.AddModCommonFlags(&cmdVerify.Flag) 41 base.AddModCommonFlags(&cmdVerify.Flag)
42 base.AddWorkfileFlag(&cmdVerify.Flag)
43} 42}
44 43
45func runVerify(ctx context.Context, cmd *base.Command, args []string) { 44func runVerify(ctx context.Context, cmd *base.Command, args []string) {
diff --git a/libgo/go/cmd/go/internal/modcmd/why.go b/libgo/go/cmd/go/internal/modcmd/why.go
index d8355cca957..2d3f1eb05bc 100644
--- a/libgo/go/cmd/go/internal/modcmd/why.go
+++ b/libgo/go/cmd/go/internal/modcmd/why.go
@@ -59,7 +59,6 @@ var (
59func init() { 59func init() {
60 cmdWhy.Run = runWhy // break init cycle 60 cmdWhy.Run = runWhy // break init cycle
61 base.AddModCommonFlags(&cmdWhy.Flag) 61 base.AddModCommonFlags(&cmdWhy.Flag)
62 base.AddWorkfileFlag(&cmdWhy.Flag)
63} 62}
64 63
65func runWhy(ctx context.Context, cmd *base.Command, args []string) { 64func runWhy(ctx context.Context, cmd *base.Command, args []string) {
diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo.go b/libgo/go/cmd/go/internal/modfetch/coderepo.go
index 79da010809b..2206c7c8401 100644
--- a/libgo/go/cmd/go/internal/modfetch/coderepo.go
+++ b/libgo/go/cmd/go/internal/modfetch/coderepo.go
@@ -298,16 +298,13 @@ func (r *codeRepo) Latest() (*RevInfo, error) {
298// If statVers is a valid module version, it is used for the Version field. 298// If statVers is a valid module version, it is used for the Version field.
299// Otherwise, the Version is derived from the passed-in info and recent tags. 299// Otherwise, the Version is derived from the passed-in info and recent tags.
300func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) { 300func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) {
301 info2 := &RevInfo{
302 Name: info.Name,
303 Short: info.Short,
304 Time: info.Time,
305 }
306
307 // If this is a plain tag (no dir/ prefix) 301 // If this is a plain tag (no dir/ prefix)
308 // and the module path is unversioned, 302 // and the module path is unversioned,
309 // and if the underlying file tree has no go.mod, 303 // and if the underlying file tree has no go.mod,
310 // then allow using the tag with a +incompatible suffix. 304 // then allow using the tag with a +incompatible suffix.
305 //
306 // (If the version is +incompatible, then the go.mod file must not exist:
307 // +incompatible is not an ongoing opt-out from semantic import versioning.)
311 var canUseIncompatible func() bool 308 var canUseIncompatible func() bool
312 canUseIncompatible = func() bool { 309 canUseIncompatible = func() bool {
313 var ok bool 310 var ok bool
@@ -321,19 +318,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
321 return ok 318 return ok
322 } 319 }
323 320
324 invalidf := func(format string, args ...any) error { 321 // checkCanonical verifies that the canonical version v is compatible with the
325 return &module.ModuleError{ 322 // module path represented by r, adding a "+incompatible" suffix if needed.
326 Path: r.modPath, 323 //
327 Err: &module.InvalidVersionError{ 324 // If statVers is also canonical, checkCanonical also verifies that v is
328 Version: info2.Version, 325 // either statVers or statVers with the added "+incompatible" suffix.
329 Err: fmt.Errorf(format, args...), 326 checkCanonical := func(v string) (*RevInfo, error) {
330 },
331 }
332 }
333
334 // checkGoMod verifies that the go.mod file for the module exists or does not
335 // exist as required by info2.Version and the module path represented by r.
336 checkGoMod := func() (*RevInfo, error) {
337 // If r.codeDir is non-empty, then the go.mod file must exist: the module 327 // If r.codeDir is non-empty, then the go.mod file must exist: the module
338 // author — not the module consumer, — gets to decide how to carve up the repo 328 // author — not the module consumer, — gets to decide how to carve up the repo
339 // into modules. 329 // into modules.
@@ -344,73 +334,91 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
344 // r.findDir verifies both of these conditions. Execute it now so that 334 // r.findDir verifies both of these conditions. Execute it now so that
345 // r.Stat will correctly return a notExistError if the go.mod location or 335 // r.Stat will correctly return a notExistError if the go.mod location or
346 // declared module path doesn't match. 336 // declared module path doesn't match.
347 _, _, _, err := r.findDir(info2.Version) 337 _, _, _, err := r.findDir(v)
348 if err != nil { 338 if err != nil {
349 // TODO: It would be nice to return an error like "not a module". 339 // TODO: It would be nice to return an error like "not a module".
350 // Right now we return "missing go.mod", which is a little confusing. 340 // Right now we return "missing go.mod", which is a little confusing.
351 return nil, &module.ModuleError{ 341 return nil, &module.ModuleError{
352 Path: r.modPath, 342 Path: r.modPath,
353 Err: &module.InvalidVersionError{ 343 Err: &module.InvalidVersionError{
354 Version: info2.Version, 344 Version: v,
355 Err: notExistError{err: err}, 345 Err: notExistError{err: err},
356 }, 346 },
357 } 347 }
358 } 348 }
359 349
360 // If the version is +incompatible, then the go.mod file must not exist: 350 invalidf := func(format string, args ...any) error {
361 // +incompatible is not an ongoing opt-out from semantic import versioning. 351 return &module.ModuleError{
362 if strings.HasSuffix(info2.Version, "+incompatible") { 352 Path: r.modPath,
363 if !canUseIncompatible() { 353 Err: &module.InvalidVersionError{
354 Version: v,
355 Err: fmt.Errorf(format, args...),
356 },
357 }
358 }
359
360 // Add the +incompatible suffix if needed or requested explicitly, and
361 // verify that its presence or absence is appropriate for this version
362 // (which depends on whether it has an explicit go.mod file).
363
364 if v == strings.TrimSuffix(statVers, "+incompatible") {
365 v = statVers
366 }
367 base := strings.TrimSuffix(v, "+incompatible")
368 var errIncompatible error
369 if !module.MatchPathMajor(base, r.pathMajor) {
370 if canUseIncompatible() {
371 v = base + "+incompatible"
372 } else {
364 if r.pathMajor != "" { 373 if r.pathMajor != "" {
365 return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match") 374 errIncompatible = invalidf("module path includes a major version suffix, so major version must match")
366 } else { 375 } else {
367 return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required") 376 errIncompatible = invalidf("module contains a go.mod file, so module path must match major version (%q)", path.Join(r.pathPrefix, semver.Major(v)))
368 } 377 }
369 } 378 }
379 } else if strings.HasSuffix(v, "+incompatible") {
380 errIncompatible = invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(v))
381 }
370 382
371 if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil { 383 if statVers != "" && statVers == module.CanonicalVersion(statVers) {
372 return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version)) 384 // Since the caller-requested version is canonical, it would be very
385 // confusing to resolve it to anything but itself, possibly with a
386 // "+incompatible" suffix. Error out explicitly.
387 if statBase := strings.TrimSuffix(statVers, "+incompatible"); statBase != base {
388 return nil, &module.ModuleError{
389 Path: r.modPath,
390 Err: &module.InvalidVersionError{
391 Version: statVers,
392 Err: fmt.Errorf("resolves to version %v (%s is not a tag)", v, statBase),
393 },
394 }
373 } 395 }
374 } 396 }
375 397
376 return info2, nil 398 if errIncompatible != nil {
399 return nil, errIncompatible
400 }
401
402 return &RevInfo{
403 Name: info.Name,
404 Short: info.Short,
405 Time: info.Time,
406 Version: v,
407 }, nil
377 } 408 }
378 409
379 // Determine version. 410 // Determine version.
380 //
381 // If statVers is canonical, then the original call was repo.Stat(statVers).
382 // Since the version is canonical, we must not resolve it to anything but
383 // itself, possibly with a '+incompatible' annotation: we do not need to do
384 // the work required to look for an arbitrary pseudo-version.
385 if statVers != "" && statVers == module.CanonicalVersion(statVers) {
386 info2.Version = statVers
387
388 if module.IsPseudoVersion(info2.Version) {
389 if err := r.validatePseudoVersion(info, info2.Version); err != nil {
390 return nil, err
391 }
392 return checkGoMod()
393 }
394 411
395 if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil { 412 if module.IsPseudoVersion(statVers) {
396 if canUseIncompatible() { 413 if err := r.validatePseudoVersion(info, statVers); err != nil {
397 info2.Version += "+incompatible" 414 return nil, err
398 return checkGoMod()
399 } else {
400 if vErr, ok := err.(*module.InvalidVersionError); ok {
401 // We're going to describe why the version is invalid in more detail,
402 // so strip out the existing “invalid version” wrapper.
403 err = vErr.Err
404 }
405 return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err)
406 }
407 } 415 }
408 416 return checkCanonical(statVers)
409 return checkGoMod()
410 } 417 }
411 418
412 // statVers is empty or non-canonical, so we need to resolve it to a canonical 419 // statVers is not a pseudo-version, so we need to either resolve it to a
413 // version or pseudo-version. 420 // canonical version or verify that it is already a canonical tag
421 // (not a branch).
414 422
415 // Derive or verify a version from a code repo tag. 423 // Derive or verify a version from a code repo tag.
416 // Tag must have a prefix matching codeDir. 424 // Tag must have a prefix matching codeDir.
@@ -441,71 +449,62 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
441 if v == "" || !strings.HasPrefix(trimmed, v) { 449 if v == "" || !strings.HasPrefix(trimmed, v) {
442 return "", false // Invalid or incomplete version (just vX or vX.Y). 450 return "", false // Invalid or incomplete version (just vX or vX.Y).
443 } 451 }
444 if isRetracted(v) {
445 return "", false
446 }
447 if v == trimmed { 452 if v == trimmed {
448 tagIsCanonical = true 453 tagIsCanonical = true
449 } 454 }
450
451 if err := module.CheckPathMajor(v, r.pathMajor); err != nil {
452 if canUseIncompatible() {
453 return v + "+incompatible", tagIsCanonical
454 }
455 return "", false
456 }
457
458 return v, tagIsCanonical 455 return v, tagIsCanonical
459 } 456 }
460 457
461 // If the VCS gave us a valid version, use that. 458 // If the VCS gave us a valid version, use that.
462 if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical { 459 if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical {
463 info2.Version = v 460 if info, err := checkCanonical(v); err == nil {
464 return checkGoMod() 461 return info, err
462 }
465 } 463 }
466 464
467 // Look through the tags on the revision for either a usable canonical version 465 // Look through the tags on the revision for either a usable canonical version
468 // or an appropriate base for a pseudo-version. 466 // or an appropriate base for a pseudo-version.
469 var pseudoBase string 467 var (
468 highestCanonical string
469 pseudoBase string
470 )
470 for _, pathTag := range info.Tags { 471 for _, pathTag := range info.Tags {
471 v, tagIsCanonical := tagToVersion(pathTag) 472 v, tagIsCanonical := tagToVersion(pathTag)
472 if tagIsCanonical { 473 if statVers != "" && semver.Compare(v, statVers) == 0 {
473 if statVers != "" && semver.Compare(v, statVers) == 0 { 474 // The tag is equivalent to the version requested by the user.
474 // The user requested a non-canonical version, but the tag for the 475 if tagIsCanonical {
475 // canonical equivalent refers to the same revision. Use it. 476 // This tag is the canonical form of the requested version,
476 info2.Version = v 477 // not some other form with extra build metadata.
477 return checkGoMod() 478 // Use this tag so that the resolved version will match exactly.
479 // (If it isn't actually allowed, we'll error out in checkCanonical.)
480 return checkCanonical(v)
478 } else { 481 } else {
479 // Save the highest canonical tag for the revision. If we don't find a 482 // The user explicitly requested something equivalent to this tag. We
480 // better match, we'll use it as the canonical version. 483 // can't use the version from the tag directly: since the tag is not
484 // canonical, it could be ambiguous. For example, tags v0.0.1+a and
485 // v0.0.1+b might both exist and refer to different revisions.
481 // 486 //
482 // NOTE: Do not replace this with semver.Max. Despite the name, 487 // The tag is otherwise valid for the module, so we can at least use it as
483 // semver.Max *also* canonicalizes its arguments, which uses 488 // the base of an unambiguous pseudo-version.
484 // semver.Canonical instead of module.CanonicalVersion and thereby 489 //
485 // strips our "+incompatible" suffix. 490 // If multiple tags match, tagToVersion will canonicalize them to the same
486 if semver.Compare(info2.Version, v) < 0 { 491 // base version.
487 info2.Version = v 492 pseudoBase = v
488 } 493 }
494 }
495 // Save the highest non-retracted canonical tag for the revision.
496 // If we don't find a better match, we'll use it as the canonical version.
497 if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) {
498 if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() {
499 highestCanonical = v
489 } 500 }
490 } else if v != "" && semver.Compare(v, statVers) == 0 {
491 // The user explicitly requested something equivalent to this tag. We
492 // can't use the version from the tag directly: since the tag is not
493 // canonical, it could be ambiguous. For example, tags v0.0.1+a and
494 // v0.0.1+b might both exist and refer to different revisions.
495 //
496 // The tag is otherwise valid for the module, so we can at least use it as
497 // the base of an unambiguous pseudo-version.
498 //
499 // If multiple tags match, tagToVersion will canonicalize them to the same
500 // base version.
501 pseudoBase = v
502 } 501 }
503 } 502 }
504 503
505 // If we found any canonical tag for the revision, return it. 504 // If we found a valid canonical tag for the revision, return it.
506 // Even if we found a good pseudo-version base, a canonical version is better. 505 // Even if we found a good pseudo-version base, a canonical version is better.
507 if info2.Version != "" { 506 if highestCanonical != "" {
508 return checkGoMod() 507 return checkCanonical(highestCanonical)
509 } 508 }
510 509
511 // Find the highest tagged version in the revision's history, subject to 510 // Find the highest tagged version in the revision's history, subject to
@@ -528,11 +527,10 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
528 tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0")) 527 tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0"))
529 } 528 }
530 } 529 }
531 pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid 530 pseudoBase, _ = tagToVersion(tag)
532 } 531 }
533 532
534 info2.Version = module.PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short) 533 return checkCanonical(module.PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short))
535 return checkGoMod()
536} 534}
537 535
538// validatePseudoVersion checks that version has a major version compatible with 536// validatePseudoVersion checks that version has a major version compatible with
@@ -556,10 +554,6 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
556 } 554 }
557 }() 555 }()
558 556
559 if err := module.CheckPathMajor(version, r.pathMajor); err != nil {
560 return err
561 }
562
563 rev, err := module.PseudoVersionRev(version) 557 rev, err := module.PseudoVersionRev(version)
564 if err != nil { 558 if err != nil {
565 return err 559 return err
diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
index 02e399f3525..d98ea87da2c 100644
--- a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
+++ b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
@@ -418,171 +418,204 @@ var codeRepoTests = []codeRepoTest{
418 zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=", 418 zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=",
419 zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5", 419 zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5",
420 }, 420 },
421 {
422 // Git branch with a semver name, +incompatible version, and no go.mod file.
423 vcs: "git",
424 path: "vcs-test.golang.org/go/mod/gitrepo1",
425 rev: "v2.3.4+incompatible",
426 err: `resolves to version v2.0.1+incompatible (v2.3.4 is not a tag)`,
427 },
428 {
429 // Git branch with a semver name, matching go.mod file, and compatible version.
430 vcs: "git",
431 path: "vcs-test.golang.org/git/semver-branch.git",
432 rev: "v1.0.0",
433 err: `resolves to version v0.1.1-0.20220202191944-09c4d8f6938c (v1.0.0 is not a tag)`,
434 },
435 {
436 // Git branch with a semver name, matching go.mod file, and disallowed +incompatible version.
437 // The version/tag mismatch takes precedence over the +incompatible mismatched.
438 vcs: "git",
439 path: "vcs-test.golang.org/git/semver-branch.git",
440 rev: "v2.0.0+incompatible",
441 err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
442 },
443 {
444 // Git branch with a semver name, matching go.mod file, and mismatched version.
445 // The version/tag mismatch takes precedence over the +incompatible mismatched.
446 vcs: "git",
447 path: "vcs-test.golang.org/git/semver-branch.git",
448 rev: "v2.0.0",
449 err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
450 },
451 {
452 // v3.0.0-devel is the same as tag v4.0.0-beta.1, but v4.0.0-beta.1 would
453 // not be allowed because it is incompatible and a go.mod file exists.
454 // The error message should refer to a valid pseudo-version, not the
455 // unusable semver tag.
456 vcs: "git",
457 path: "vcs-test.golang.org/git/semver-branch.git",
458 rev: "v3.0.0-devel",
459 err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
460 },
421} 461}
422 462
423func TestCodeRepo(t *testing.T) { 463func TestCodeRepo(t *testing.T) {
424 testenv.MustHaveExternalNetwork(t) 464 testenv.MustHaveExternalNetwork(t)
465 tmpdir := t.TempDir()
425 466
426 tmpdir, err := os.MkdirTemp("", "modfetch-test-") 467 for _, tt := range codeRepoTests {
427 if err != nil { 468 f := func(tt codeRepoTest) func(t *testing.T) {
428 t.Fatal(err) 469 return func(t *testing.T) {
429 } 470 t.Parallel()
430 defer os.RemoveAll(tmpdir) 471 if tt.vcs != "mod" {
472 testenv.MustHaveExecPath(t, tt.vcs)
473 }
431 474
432 t.Run("parallel", func(t *testing.T) { 475 repo := Lookup("direct", tt.path)
433 for _, tt := range codeRepoTests {
434 f := func(tt codeRepoTest) func(t *testing.T) {
435 return func(t *testing.T) {
436 t.Parallel()
437 if tt.vcs != "mod" {
438 testenv.MustHaveExecPath(t, tt.vcs)
439 }
440 476
441 repo := Lookup("direct", tt.path) 477 if tt.mpath == "" {
478 tt.mpath = tt.path
479 }
480 if mpath := repo.ModulePath(); mpath != tt.mpath {
481 t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
482 }
442 483
443 if tt.mpath == "" { 484 info, err := repo.Stat(tt.rev)
444 tt.mpath = tt.path 485 if err != nil {
445 } 486 if tt.err != "" {
446 if mpath := repo.ModulePath(); mpath != tt.mpath { 487 if !strings.Contains(err.Error(), tt.err) {
447 t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath) 488 t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
489 }
490 return
448 } 491 }
492 t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
493 }
494 if tt.err != "" {
495 t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
496 }
497 if info.Version != tt.version {
498 t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
499 }
500 if info.Name != tt.name {
501 t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
502 }
503 if info.Short != tt.short {
504 t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
505 }
506 if !info.Time.Equal(tt.time) {
507 t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
508 }
449 509
450 info, err := repo.Stat(tt.rev) 510 if tt.gomod != "" || tt.gomodErr != "" {
451 if err != nil { 511 data, err := repo.GoMod(tt.version)
452 if tt.err != "" { 512 if err != nil && tt.gomodErr == "" {
453 if !strings.Contains(err.Error(), tt.err) { 513 t.Errorf("repo.GoMod(%q): %v", tt.version, err)
454 t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err) 514 } else if err != nil && tt.gomodErr != "" {
455 } 515 if err.Error() != tt.gomodErr {
456 return 516 t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
457 } 517 }
458 t.Fatalf("repo.Stat(%q): %v", tt.rev, err) 518 } else if tt.gomodErr != "" {
459 } 519 t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
460 if tt.err != "" { 520 } else if string(data) != tt.gomod {
461 t.Errorf("repo.Stat(%q): success, wanted error", tt.rev) 521 t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
462 }
463 if info.Version != tt.version {
464 t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
465 } 522 }
466 if info.Name != tt.name { 523 }
467 t.Errorf("info.Name = %q, want %q", info.Name, tt.name) 524
468 } 525 needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
469 if info.Short != tt.short { 526 if tt.zip != nil || tt.zipErr != "" || needHash {
470 t.Errorf("info.Short = %q, want %q", info.Short, tt.short) 527 f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
528 if err != nil {
529 t.Fatalf("os.CreateTemp: %v", err)
471 } 530 }
472 if !info.Time.Equal(tt.time) { 531 zipfile := f.Name()
473 t.Errorf("info.Time = %v, want %v", info.Time, tt.time) 532 defer func() {
533 f.Close()
534 os.Remove(zipfile)
535 }()
536
537 var w io.Writer
538 var h hash.Hash
539 if needHash {
540 h = sha256.New()
541 w = io.MultiWriter(f, h)
542 } else {
543 w = f
474 } 544 }
475 545 err = repo.Zip(w, tt.version)
476 if tt.gomod != "" || tt.gomodErr != "" { 546 f.Close()
477 data, err := repo.GoMod(tt.version) 547 if err != nil {
478 if err != nil && tt.gomodErr == "" { 548 if tt.zipErr != "" {
479 t.Errorf("repo.GoMod(%q): %v", tt.version, err) 549 if err.Error() == tt.zipErr {
480 } else if err != nil && tt.gomodErr != "" { 550 return
481 if err.Error() != tt.gomodErr {
482 t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
483 } 551 }
484 } else if tt.gomodErr != "" { 552 t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
485 t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
486 } else if string(data) != tt.gomod {
487 t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
488 } 553 }
554 t.Fatalf("repo.Zip(%q): %v", tt.version, err)
555 }
556 if tt.zipErr != "" {
557 t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
489 } 558 }
490 559
491 needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "") 560 if tt.zip != nil {
492 if tt.zip != nil || tt.zipErr != "" || needHash { 561 prefix := tt.path + "@" + tt.version + "/"
493 f, err := os.CreateTemp(tmpdir, tt.version+".zip.") 562 z, err := zip.OpenReader(zipfile)
494 if err != nil { 563 if err != nil {
495 t.Fatalf("os.CreateTemp: %v", err) 564 t.Fatalf("open zip %s: %v", zipfile, err)
496 } 565 }
497 zipfile := f.Name() 566 var names []string
498 defer func() { 567 for _, file := range z.File {
499 f.Close() 568 if !strings.HasPrefix(file.Name, prefix) {
500 os.Remove(zipfile) 569 t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
501 }() 570 continue
502
503 var w io.Writer
504 var h hash.Hash
505 if needHash {
506 h = sha256.New()
507 w = io.MultiWriter(f, h)
508 } else {
509 w = f
510 }
511 err = repo.Zip(w, tt.version)
512 f.Close()
513 if err != nil {
514 if tt.zipErr != "" {
515 if err.Error() == tt.zipErr {
516 return
517 }
518 t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
519 } 571 }
520 t.Fatalf("repo.Zip(%q): %v", tt.version, err) 572 names = append(names, file.Name[len(prefix):])
521 }
522 if tt.zipErr != "" {
523 t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
524 } 573 }
525 574 z.Close()
526 if tt.zip != nil { 575 if !reflect.DeepEqual(names, tt.zip) {
527 prefix := tt.path + "@" + tt.version + "/" 576 t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
528 z, err := zip.OpenReader(zipfile)
529 if err != nil {
530 t.Fatalf("open zip %s: %v", zipfile, err)
531 }
532 var names []string
533 for _, file := range z.File {
534 if !strings.HasPrefix(file.Name, prefix) {
535 t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
536 continue
537 }
538 names = append(names, file.Name[len(prefix):])
539 }
540 z.Close()
541 if !reflect.DeepEqual(names, tt.zip) {
542 t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
543 }
544 } 577 }
578 }
545 579
546 if needHash { 580 if needHash {
547 sum, err := dirhash.HashZip(zipfile, dirhash.Hash1) 581 sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
548 if err != nil { 582 if err != nil {
549 t.Errorf("repo.Zip(%q): %v", tt.version, err) 583 t.Errorf("repo.Zip(%q): %v", tt.version, err)
550 } else if sum != tt.zipSum { 584 } else if sum != tt.zipSum {
551 t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum) 585 t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
552 } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash { 586 } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
553 t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash) 587 t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
554 }
555 } 588 }
556 } 589 }
557 } 590 }
558 } 591 }
559 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt)) 592 }
560 if strings.HasPrefix(tt.path, vgotest1git) { 593 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
561 for vcs, alt := range altVgotests { 594 if strings.HasPrefix(tt.path, vgotest1git) {
562 altTest := tt 595 for vcs, alt := range altVgotests {
563 altTest.vcs = vcs 596 altTest := tt
564 altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git) 597 altTest.vcs = vcs
565 if strings.HasPrefix(altTest.mpath, vgotest1git) { 598 altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
566 altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git) 599 if strings.HasPrefix(altTest.mpath, vgotest1git) {
567 } 600 altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
568 var m map[string]string 601 }
569 if alt == vgotest1hg { 602 var m map[string]string
570 m = hgmap 603 if alt == vgotest1hg {
571 } 604 m = hgmap
572 altTest.version = remap(altTest.version, m)
573 altTest.name = remap(altTest.name, m)
574 altTest.short = remap(altTest.short, m)
575 altTest.rev = remap(altTest.rev, m)
576 altTest.err = remap(altTest.err, m)
577 altTest.gomodErr = remap(altTest.gomodErr, m)
578 altTest.zipErr = remap(altTest.zipErr, m)
579 altTest.zipSum = ""
580 altTest.zipFileHash = ""
581 t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
582 } 605 }
606 altTest.version = remap(altTest.version, m)
607 altTest.name = remap(altTest.name, m)
608 altTest.short = remap(altTest.short, m)
609 altTest.rev = remap(altTest.rev, m)
610 altTest.err = remap(altTest.err, m)
611 altTest.gomodErr = remap(altTest.gomodErr, m)
612 altTest.zipErr = remap(altTest.zipErr, m)
613 altTest.zipSum = ""
614 altTest.zipFileHash = ""
615 t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
583 } 616 }
584 } 617 }
585 }) 618 }
586} 619}
587 620
588var hgmap = map[string]string{ 621var hgmap = map[string]string{
diff --git a/libgo/go/cmd/go/internal/modfetch/fetch.go b/libgo/go/cmd/go/internal/modfetch/fetch.go
index f5423b48ad3..21d5f54688f 100644
--- a/libgo/go/cmd/go/internal/modfetch/fetch.go
+++ b/libgo/go/cmd/go/internal/modfetch/fetch.go
@@ -319,7 +319,7 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
319// 319//
320// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns 320// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns
321// an error and does not write ziphashfile. 321// an error and does not write ziphashfile.
322func hashZip(mod module.Version, zipfile, ziphashfile string) error { 322func hashZip(mod module.Version, zipfile, ziphashfile string) (err error) {
323 hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash) 323 hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash)
324 if err != nil { 324 if err != nil {
325 return err 325 return err
@@ -331,16 +331,17 @@ func hashZip(mod module.Version, zipfile, ziphashfile string) error {
331 if err != nil { 331 if err != nil {
332 return err 332 return err
333 } 333 }
334 defer func() {
335 if closeErr := hf.Close(); err == nil && closeErr != nil {
336 err = closeErr
337 }
338 }()
334 if err := hf.Truncate(int64(len(hash))); err != nil { 339 if err := hf.Truncate(int64(len(hash))); err != nil {
335 return err 340 return err
336 } 341 }
337 if _, err := hf.WriteAt([]byte(hash), 0); err != nil { 342 if _, err := hf.WriteAt([]byte(hash), 0); err != nil {
338 return err 343 return err
339 } 344 }
340 if err := hf.Close(); err != nil {
341 return err
342 }
343
344 return nil 345 return nil
345} 346}
346 347
diff --git a/libgo/go/cmd/go/internal/modload/import.go b/libgo/go/cmd/go/internal/modload/import.go
index 812e48a1568..4862f625b48 100644
--- a/libgo/go/cmd/go/internal/modload/import.go
+++ b/libgo/go/cmd/go/internal/modload/import.go
@@ -248,12 +248,26 @@ func (e *invalidImportError) Unwrap() error {
248// return the module, its root directory, and a list of other modules that 248// return the module, its root directory, and a list of other modules that
249// lexically could have provided the package but did not. 249// lexically could have provided the package but did not.
250func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, dir string, altMods []module.Version, err error) { 250func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, dir string, altMods []module.Version, err error) {
251 invalidf := func(format string, args ...interface{}) (module.Version, string, []module.Version, error) {
252 return module.Version{}, "", nil, &invalidImportError{
253 importPath: path,
254 err: fmt.Errorf(format, args...),
255 }
256 }
257
251 if strings.Contains(path, "@") { 258 if strings.Contains(path, "@") {
252 return module.Version{}, "", nil, fmt.Errorf("import path should not have @version") 259 return invalidf("import path %q should not have @version", path)
253 } 260 }
254 if build.IsLocalImport(path) { 261 if build.IsLocalImport(path) {
255 return module.Version{}, "", nil, fmt.Errorf("relative import not supported") 262 return invalidf("%q is relative, but relative import paths are not supported in module mode", path)
256 } 263 }
264 if filepath.IsAbs(path) {
265 return invalidf("%q is not a package path; see 'go help packages'", path)
266 }
267 if search.IsMetaPackage(path) {
268 return invalidf("%q is not an importable package; see 'go help packages'", path)
269 }
270
257 if path == "C" { 271 if path == "C" {
258 // There's no directory for import "C". 272 // There's no directory for import "C".
259 return module.Version{}, "", nil, nil 273 return module.Version{}, "", nil, nil
diff --git a/libgo/go/cmd/go/internal/modload/init.go b/libgo/go/cmd/go/internal/modload/init.go
index cdcfbeb8ded..a07066696e8 100644
--- a/libgo/go/cmd/go/internal/modload/init.go
+++ b/libgo/go/cmd/go/internal/modload/init.go
@@ -288,20 +288,20 @@ func BinDir() string {
288// operate in workspace mode. It should not be called by other commands, 288// operate in workspace mode. It should not be called by other commands,
289// for example 'go mod tidy', that don't operate in workspace mode. 289// for example 'go mod tidy', that don't operate in workspace mode.
290func InitWorkfile() { 290func InitWorkfile() {
291 switch cfg.WorkFile { 291 switch gowork := cfg.Getenv("GOWORK"); gowork {
292 case "off": 292 case "off":
293 workFilePath = "" 293 workFilePath = ""
294 case "", "auto": 294 case "", "auto":
295 workFilePath = findWorkspaceFile(base.Cwd()) 295 workFilePath = findWorkspaceFile(base.Cwd())
296 default: 296 default:
297 if !filepath.IsAbs(cfg.WorkFile) { 297 if !filepath.IsAbs(gowork) {
298 base.Fatalf("the path provided to -workfile must be an absolute path") 298 base.Fatalf("the path provided to GOWORK must be an absolute path")
299 } 299 }
300 workFilePath = cfg.WorkFile 300 workFilePath = gowork
301 } 301 }
302} 302}
303 303
304// WorkFilePath returns the path of the go.work file, or "" if not in 304// WorkFilePath returns the absolute path of the go.work file, or "" if not in
305// workspace mode. WorkFilePath must be called after InitWorkfile. 305// workspace mode. WorkFilePath must be called after InitWorkfile.
306func WorkFilePath() string { 306func WorkFilePath() string {
307 return workFilePath 307 return workFilePath
@@ -610,6 +610,9 @@ func UpdateWorkFile(wf *modfile.WorkFile) {
610 missingModulePaths := map[string]string{} // module directory listed in file -> abspath modroot 610 missingModulePaths := map[string]string{} // module directory listed in file -> abspath modroot
611 611
612 for _, d := range wf.Use { 612 for _, d := range wf.Use {
613 if d.Path == "" {
614 continue // d is marked for deletion.
615 }
613 modRoot := d.Path 616 modRoot := d.Path
614 if d.ModulePath == "" { 617 if d.ModulePath == "" {
615 missingModulePaths[d.Path] = modRoot 618 missingModulePaths[d.Path] = modRoot
@@ -1030,11 +1033,25 @@ func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile
1030 for _, r := range modFiles[i].Replace { 1033 for _, r := range modFiles[i].Replace {
1031 if replacedByWorkFile[r.Old.Path] { 1034 if replacedByWorkFile[r.Old.Path] {
1032 continue 1035 continue
1033 } else if prev, ok := replacements[r.Old]; ok && !curModuleReplaces[r.Old] && prev != r.New { 1036 }
1034 base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v\nuse \"go work edit -replace %v=[override]\" to resolve", r.Old, prev, r.New, r.Old) 1037 var newV module.Version = r.New
1038 if WorkFilePath() != "" && newV.Version == "" && !filepath.IsAbs(newV.Path) {
1039 // Since we are in a workspace, we may be loading replacements from
1040 // multiple go.mod files. Relative paths in those replacement are
1041 // relative to the go.mod file, not the workspace, so the same string
1042 // may refer to two different paths and different strings may refer to
1043 // the same path. Convert them all to be absolute instead.
1044 //
1045 // (We could do this outside of a workspace too, but it would mean that
1046 // replacement paths in error strings needlessly differ from what's in
1047 // the go.mod file.)
1048 newV.Path = filepath.Join(rootDirs[i], newV.Path)
1049 }
1050 if prev, ok := replacements[r.Old]; ok && !curModuleReplaces[r.Old] && prev != newV {
1051 base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v\nuse \"go work edit -replace %v=[override]\" to resolve", r.Old, prev, newV, r.Old)
1035 } 1052 }
1036 curModuleReplaces[r.Old] = true 1053 curModuleReplaces[r.Old] = true
1037 replacements[r.Old] = r.New 1054 replacements[r.Old] = newV
1038 1055
1039 v, ok := mainModules.highestReplaced[r.Old.Path] 1056 v, ok := mainModules.highestReplaced[r.Old.Path]
1040 if !ok || semver.Compare(r.Old.Version, v) > 0 { 1057 if !ok || semver.Compare(r.Old.Version, v) > 0 {
@@ -1092,7 +1109,7 @@ func setDefaultBuildMod() {
1092 if inWorkspaceMode() && cfg.BuildMod != "readonly" { 1109 if inWorkspaceMode() && cfg.BuildMod != "readonly" {
1093 base.Fatalf("go: -mod may only be set to readonly when in workspace mode, but it is set to %q"+ 1110 base.Fatalf("go: -mod may only be set to readonly when in workspace mode, but it is set to %q"+
1094 "\n\tRemove the -mod flag to use the default readonly value,"+ 1111 "\n\tRemove the -mod flag to use the default readonly value,"+
1095 "\n\tor set -workfile=off to disable workspace mode.", cfg.BuildMod) 1112 "\n\tor set GOWORK=off to disable workspace mode.", cfg.BuildMod)
1096 } 1113 }
1097 // Don't override an explicit '-mod=' argument. 1114 // Don't override an explicit '-mod=' argument.
1098 return 1115 return
diff --git a/libgo/go/cmd/go/internal/modload/load.go b/libgo/go/cmd/go/internal/modload/load.go
index 617b634d263..d4847efb988 100644
--- a/libgo/go/cmd/go/internal/modload/load.go
+++ b/libgo/go/cmd/go/internal/modload/load.go
@@ -479,7 +479,11 @@ func matchLocalDirs(ctx context.Context, modRoots []string, m *search.Match, rs
479 } 479 }
480 if !found && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(ctx, absDir, rs) == "" { 480 if !found && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(ctx, absDir, rs) == "" {
481 m.Dirs = []string{} 481 m.Dirs = []string{}
482 m.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir))) 482 scope := "main module or its selected dependencies"
483 if inWorkspaceMode() {
484 scope = "modules listed in go.work or their selected dependencies"
485 }
486 m.AddError(fmt.Errorf("directory prefix %s does not contain %s", base.ShortPath(absDir), scope))
483 return 487 return
484 } 488 }
485 } 489 }
@@ -601,7 +605,11 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
601 605
602 pkg := pathInModuleCache(ctx, absDir, rs) 606 pkg := pathInModuleCache(ctx, absDir, rs)
603 if pkg == "" { 607 if pkg == "" {
604 return "", fmt.Errorf("directory %s outside available modules", base.ShortPath(absDir)) 608 scope := "main module or its selected dependencies"
609 if inWorkspaceMode() {
610 scope = "modules listed in go.work or their selected dependencies"
611 }
612 return "", fmt.Errorf("directory %s outside %s", base.ShortPath(absDir), scope)
605 } 613 }
606 return pkg, nil 614 return pkg, nil
607} 615}
@@ -1667,24 +1675,6 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
1667 1675
1668// load loads an individual package. 1676// load loads an individual package.
1669func (ld *loader) load(ctx context.Context, pkg *loadPkg) { 1677func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
1670 if strings.Contains(pkg.path, "@") {
1671 // Leave for error during load.
1672 return
1673 }
1674 if build.IsLocalImport(pkg.path) || filepath.IsAbs(pkg.path) {
1675 // Leave for error during load.
1676 // (Module mode does not allow local imports.)
1677 return
1678 }
1679
1680 if search.IsMetaPackage(pkg.path) {
1681 pkg.err = &invalidImportError{
1682 importPath: pkg.path,
1683 err: fmt.Errorf("%q is not an importable package; see 'go help packages'", pkg.path),
1684 }
1685 return
1686 }
1687
1688 var mg *ModuleGraph 1678 var mg *ModuleGraph
1689 if ld.requirements.pruning == unpruned { 1679 if ld.requirements.pruning == unpruned {
1690 var err error 1680 var err error
diff --git a/libgo/go/cmd/go/internal/run/run.go b/libgo/go/cmd/go/internal/run/run.go
index c4b70b64fe6..00a3e4b332f 100644
--- a/libgo/go/cmd/go/internal/run/run.go
+++ b/libgo/go/cmd/go/internal/run/run.go
@@ -65,7 +65,6 @@ func init() {
65 CmdRun.Run = runRun // break init loop 65 CmdRun.Run = runRun // break init loop
66 66
67 work.AddBuildFlags(CmdRun, work.DefaultBuildFlags) 67 work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
68 base.AddWorkfileFlag(&CmdRun.Flag)
69 CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "") 68 CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
70} 69}
71 70
diff --git a/libgo/go/cmd/go/internal/test/testflag.go b/libgo/go/cmd/go/internal/test/testflag.go
index b9d1ec91ff7..c046caca25d 100644
--- a/libgo/go/cmd/go/internal/test/testflag.go
+++ b/libgo/go/cmd/go/internal/test/testflag.go
@@ -28,7 +28,6 @@ import (
28 28
29func init() { 29func init() {
30 work.AddBuildFlags(CmdTest, work.OmitVFlag) 30 work.AddBuildFlags(CmdTest, work.OmitVFlag)
31 base.AddWorkfileFlag(&CmdTest.Flag)
32 31
33 cf := CmdTest.Flag 32 cf := CmdTest.Flag
34 cf.BoolVar(&testC, "c", false, "") 33 cf.BoolVar(&testC, "c", false, "")
diff --git a/libgo/go/cmd/go/internal/version/version.go b/libgo/go/cmd/go/internal/version/version.go
index 52502e95c6d..1c0eb5407d9 100644
--- a/libgo/go/cmd/go/internal/version/version.go
+++ b/libgo/go/cmd/go/internal/version/version.go
@@ -6,7 +6,6 @@
6package version 6package version
7 7
8import ( 8import (
9 "bytes"
10 "context" 9 "context"
11 "debug/buildinfo" 10 "debug/buildinfo"
12 "errors" 11 "errors"
@@ -156,12 +155,8 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) {
156 155
157 fmt.Printf("%s: %s\n", file, bi.GoVersion) 156 fmt.Printf("%s: %s\n", file, bi.GoVersion)
158 bi.GoVersion = "" // suppress printing go version again 157 bi.GoVersion = "" // suppress printing go version again
159 mod, err := bi.MarshalText() 158 mod := bi.String()
160 if err != nil {
161 fmt.Fprintf(os.Stderr, "%s: formatting build info: %v\n", file, err)
162 return
163 }
164 if *versionM && len(mod) > 0 { 159 if *versionM && len(mod) > 0 {
165 fmt.Printf("\t%s\n", bytes.ReplaceAll(mod[:len(mod)-1], []byte("\n"), []byte("\n\t"))) 160 fmt.Printf("\t%s\n", strings.ReplaceAll(mod[:len(mod)-1], "\n", "\n\t"))
166 } 161 }
167} 162}
diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go
index 88b3c570a03..d3e0dd8116f 100644
--- a/libgo/go/cmd/go/internal/vet/vet.go
+++ b/libgo/go/cmd/go/internal/vet/vet.go
@@ -13,6 +13,7 @@ import (
13 "cmd/go/internal/base" 13 "cmd/go/internal/base"
14 "cmd/go/internal/cfg" 14 "cmd/go/internal/cfg"
15 "cmd/go/internal/load" 15 "cmd/go/internal/load"
16 "cmd/go/internal/modload"
16 "cmd/go/internal/trace" 17 "cmd/go/internal/trace"
17 "cmd/go/internal/work" 18 "cmd/go/internal/work"
18) 19)
@@ -54,6 +55,7 @@ See also: go fmt, go fix.
54 55
55func runVet(ctx context.Context, cmd *base.Command, args []string) { 56func runVet(ctx context.Context, cmd *base.Command, args []string) {
56 vetFlags, pkgArgs := vetFlags(args) 57 vetFlags, pkgArgs := vetFlags(args)
58 modload.InitWorkfile() // The vet command does custom flag processing; initialize workspaces after that.
57 59
58 if cfg.DebugTrace != "" { 60 if cfg.DebugTrace != "" {
59 var close func() error 61 var close func() error
diff --git a/libgo/go/cmd/go/internal/work/build.go b/libgo/go/cmd/go/internal/work/build.go
index 1c278d3d992..0b5848a77da 100644
--- a/libgo/go/cmd/go/internal/work/build.go
+++ b/libgo/go/cmd/go/internal/work/build.go
@@ -130,14 +130,6 @@ and test commands:
130 directory, but it is not accessed. When -modfile is specified, an 130 directory, but it is not accessed. When -modfile is specified, an
131 alternate go.sum file is also used: its path is derived from the 131 alternate go.sum file is also used: its path is derived from the
132 -modfile flag by trimming the ".mod" extension and appending ".sum". 132 -modfile flag by trimming the ".mod" extension and appending ".sum".
133 -workfile file
134 in module aware mode, use the given go.work file as a workspace file.
135 By default or when -workfile is "auto", the go command searches for a
136 file named go.work in the current directory and then containing directories
137 until one is found. If a valid go.work file is found, the modules
138 specified will collectively be used as the main modules. If -workfile
139 is "off", or a go.work file is not found in "auto" mode, workspace
140 mode is disabled.
141 -overlay file 133 -overlay file
142 read a JSON config file that provides an overlay for build operations. 134 read a JSON config file that provides an overlay for build operations.
143 The file is a JSON struct with a single field, named 'Replace', that 135 The file is a JSON struct with a single field, named 'Replace', that
@@ -217,7 +209,6 @@ func init() {
217 209
218 AddBuildFlags(CmdBuild, DefaultBuildFlags) 210 AddBuildFlags(CmdBuild, DefaultBuildFlags)
219 AddBuildFlags(CmdInstall, DefaultBuildFlags) 211 AddBuildFlags(CmdInstall, DefaultBuildFlags)
220 base.AddWorkfileFlag(&CmdBuild.Flag)
221} 212}
222 213
223// Note that flags consulted by other parts of the code 214// Note that flags consulted by other parts of the code
diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go
index d3f0ecac049..a4ab060c18e 100644
--- a/libgo/go/cmd/go/internal/work/exec.go
+++ b/libgo/go/cmd/go/internal/work/exec.go
@@ -2015,6 +2015,7 @@ func (b *Builder) showOutput(a *Action, dir, desc, out string) {
2015 if reldir := base.ShortPath(dir); reldir != dir { 2015 if reldir := base.ShortPath(dir); reldir != dir {
2016 suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir) 2016 suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir)
2017 suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir) 2017 suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir)
2018 suffix = strings.ReplaceAll(suffix, "\n\t"+dir, "\n\t"+reldir)
2018 } 2019 }
2019 suffix = strings.ReplaceAll(suffix, " "+b.WorkDir, " $WORK") 2020 suffix = strings.ReplaceAll(suffix, " "+b.WorkDir, " $WORK")
2020 2021
diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go
index e9b9f6c6c0f..d1e2c673fad 100644
--- a/libgo/go/cmd/go/internal/work/security.go
+++ b/libgo/go/cmd/go/internal/work/security.go
@@ -131,6 +131,7 @@ var validCompilerFlagsWithNextArg = []string{
131 "-D", 131 "-D",
132 "-U", 132 "-U",
133 "-I", 133 "-I",
134 "-F",
134 "-framework", 135 "-framework",
135 "-include", 136 "-include",
136 "-isysroot", 137 "-isysroot",
diff --git a/libgo/go/cmd/go/internal/work/security_test.go b/libgo/go/cmd/go/internal/work/security_test.go
index 8d4be0abfc0..d2aeb54e0ce 100644
--- a/libgo/go/cmd/go/internal/work/security_test.go
+++ b/libgo/go/cmd/go/internal/work/security_test.go
@@ -15,6 +15,7 @@ var goodCompilerFlags = [][]string{
15 {"-Ufoo"}, 15 {"-Ufoo"},
16 {"-Ufoo1"}, 16 {"-Ufoo1"},
17 {"-F/Qt"}, 17 {"-F/Qt"},
18 {"-F", "/Qt"},
18 {"-I/"}, 19 {"-I/"},
19 {"-I/etc/passwd"}, 20 {"-I/etc/passwd"},
20 {"-I."}, 21 {"-I."},
diff --git a/libgo/go/cmd/go/internal/workcmd/edit.go b/libgo/go/cmd/go/internal/workcmd/edit.go
index c42000710e0..05f4f3dddfc 100644
--- a/libgo/go/cmd/go/internal/workcmd/edit.go
+++ b/libgo/go/cmd/go/internal/workcmd/edit.go
@@ -63,19 +63,14 @@ writing it back to go.mod.
63The -json flag prints the final go.work file in JSON format instead of 63The -json flag prints the final go.work file in JSON format instead of
64writing it back to go.mod. The JSON output corresponds to these Go types: 64writing it back to go.mod. The JSON output corresponds to these Go types:
65 65
66 type Module struct {
67 Path string
68 Version string
69 }
70
71 type GoWork struct { 66 type GoWork struct {
72 Go string 67 Go string
73 Directory []Directory 68 Use []Use
74 Replace []Replace 69 Replace []Replace
75 } 70 }
76 71
77 type Use struct { 72 type Use struct {
78 Path string 73 DiskPath string
79 ModulePath string 74 ModulePath string
80 } 75 }
81 76
@@ -84,6 +79,11 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
84 New Module 79 New Module
85 } 80 }
86 81
82 type Module struct {
83 Path string
84 Version string
85 }
86
87See the workspaces design proposal at 87See the workspaces design proposal at
88https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for 88https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
89more information. 89more information.
@@ -110,22 +110,9 @@ func init() {
110 cmdEdit.Flag.Var(flagFunc(flagEditworkDropUse), "dropuse", "") 110 cmdEdit.Flag.Var(flagFunc(flagEditworkDropUse), "dropuse", "")
111 cmdEdit.Flag.Var(flagFunc(flagEditworkReplace), "replace", "") 111 cmdEdit.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
112 cmdEdit.Flag.Var(flagFunc(flagEditworkDropReplace), "dropreplace", "") 112 cmdEdit.Flag.Var(flagFunc(flagEditworkDropReplace), "dropreplace", "")
113
114 base.AddWorkfileFlag(&cmdEdit.Flag)
115} 113}
116 114
117func runEditwork(ctx context.Context, cmd *base.Command, args []string) { 115func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
118 anyFlags :=
119 *editGo != "" ||
120 *editJSON ||
121 *editPrint ||
122 *editFmt ||
123 len(workedits) > 0
124
125 if !anyFlags {
126 base.Fatalf("go: no flags specified (see 'go help work edit').")
127 }
128
129 if *editJSON && *editPrint { 116 if *editJSON && *editPrint {
130 base.Fatalf("go: cannot use both -json and -print") 117 base.Fatalf("go: cannot use both -json and -print")
131 } 118 }
@@ -147,6 +134,21 @@ func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
147 } 134 }
148 } 135 }
149 136
137 if gowork == "" {
138 base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
139 }
140
141 anyFlags :=
142 *editGo != "" ||
143 *editJSON ||
144 *editPrint ||
145 *editFmt ||
146 len(workedits) > 0
147
148 if !anyFlags {
149 base.Fatalf("go: no flags specified (see 'go help work edit').")
150 }
151
150 workFile, err := modload.ReadWorkFile(gowork) 152 workFile, err := modload.ReadWorkFile(gowork)
151 if err != nil { 153 if err != nil {
152 base.Fatalf("go: errors parsing %s:\n%s", base.ShortPath(gowork), err) 154 base.Fatalf("go: errors parsing %s:\n%s", base.ShortPath(gowork), err)
diff --git a/libgo/go/cmd/go/internal/workcmd/init.go b/libgo/go/cmd/go/internal/workcmd/init.go
index cefecee8329..63bee6e4f50 100644
--- a/libgo/go/cmd/go/internal/workcmd/init.go
+++ b/libgo/go/cmd/go/internal/workcmd/init.go
@@ -33,7 +33,6 @@ current go version will also be listed in the go.work file.
33 33
34func init() { 34func init() {
35 base.AddModCommonFlags(&cmdInit.Flag) 35 base.AddModCommonFlags(&cmdInit.Flag)
36 base.AddWorkfileFlag(&cmdInit.Flag)
37} 36}
38 37
39func runInit(ctx context.Context, cmd *base.Command, args []string) { 38func runInit(ctx context.Context, cmd *base.Command, args []string) {
@@ -41,12 +40,10 @@ func runInit(ctx context.Context, cmd *base.Command, args []string) {
41 40
42 modload.ForceUseModules = true 41 modload.ForceUseModules = true
43 42
44 // TODO(matloob): support using the -workfile path 43 workFile := modload.WorkFilePath()
45 // To do that properly, we'll have to make the module directories 44 if workFile == "" {
46 // make dirs relative to workFile path before adding the paths to 45 workFile = filepath.Join(base.Cwd(), "go.work")
47 // the directory entries 46 }
48
49 workFile := filepath.Join(base.Cwd(), "go.work")
50 47
51 modload.CreateWorkFile(ctx, workFile, args) 48 modload.CreateWorkFile(ctx, workFile, args)
52} 49}
diff --git a/libgo/go/cmd/go/internal/workcmd/sync.go b/libgo/go/cmd/go/internal/workcmd/sync.go
index 1cca817517c..b0f61c5fa24 100644
--- a/libgo/go/cmd/go/internal/workcmd/sync.go
+++ b/libgo/go/cmd/go/internal/workcmd/sync.go
@@ -39,13 +39,14 @@ that in each workspace module.
39 39
40func init() { 40func init() {
41 base.AddModCommonFlags(&cmdSync.Flag) 41 base.AddModCommonFlags(&cmdSync.Flag)
42 base.AddWorkfileFlag(&cmdSync.Flag)
43} 42}
44 43
45func runSync(ctx context.Context, cmd *base.Command, args []string) { 44func runSync(ctx context.Context, cmd *base.Command, args []string) {
46 modload.InitWorkfile()
47
48 modload.ForceUseModules = true 45 modload.ForceUseModules = true
46 modload.InitWorkfile()
47 if modload.WorkFilePath() == "" {
48 base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
49 }
49 50
50 workGraph := modload.LoadModGraph(ctx, "") 51 workGraph := modload.LoadModGraph(ctx, "")
51 _ = workGraph 52 _ = workGraph
diff --git a/libgo/go/cmd/go/internal/workcmd/use.go b/libgo/go/cmd/go/internal/workcmd/use.go
index 852e5b910c2..1ee2d4e3c4d 100644
--- a/libgo/go/cmd/go/internal/workcmd/use.go
+++ b/libgo/go/cmd/go/internal/workcmd/use.go
@@ -10,7 +10,10 @@ import (
10 "cmd/go/internal/base" 10 "cmd/go/internal/base"
11 "cmd/go/internal/fsys" 11 "cmd/go/internal/fsys"
12 "cmd/go/internal/modload" 12 "cmd/go/internal/modload"
13 "cmd/go/internal/str"
13 "context" 14 "context"
15 "errors"
16 "fmt"
14 "io/fs" 17 "io/fs"
15 "os" 18 "os"
16 "path/filepath" 19 "path/filepath"
@@ -39,47 +42,50 @@ func init() {
39 cmdUse.Run = runUse // break init cycle 42 cmdUse.Run = runUse // break init cycle
40 43
41 base.AddModCommonFlags(&cmdUse.Flag) 44 base.AddModCommonFlags(&cmdUse.Flag)
42 base.AddWorkfileFlag(&cmdUse.Flag)
43} 45}
44 46
45func runUse(ctx context.Context, cmd *base.Command, args []string) { 47func runUse(ctx context.Context, cmd *base.Command, args []string) {
46 modload.InitWorkfile()
47
48 modload.ForceUseModules = true 48 modload.ForceUseModules = true
49 49
50 var gowork string 50 var gowork string
51 modload.InitWorkfile() 51 modload.InitWorkfile()
52 gowork = modload.WorkFilePath() 52 gowork = modload.WorkFilePath()
53 53
54 if gowork == "" {
55 base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
56 }
54 workFile, err := modload.ReadWorkFile(gowork) 57 workFile, err := modload.ReadWorkFile(gowork)
55 if err != nil { 58 if err != nil {
56 base.Fatalf("go: %v", err) 59 base.Fatalf("go: %v", err)
57 } 60 }
58 61 workDir := filepath.Dir(gowork) // Absolute, since gowork itself is absolute.
59 haveDirs := make(map[string]bool) 62
60 for _, dir := range workFile.Use { 63 haveDirs := make(map[string][]string) // absolute → original(s)
61 haveDirs[filepath.Join(filepath.Dir(gowork), filepath.FromSlash(dir.Path))] = true 64 for _, use := range workFile.Use {
65 var abs string
66 if filepath.IsAbs(use.Path) {
67 abs = filepath.Clean(use.Path)
68 } else {
69 abs = filepath.Join(workDir, use.Path)
70 }
71 haveDirs[abs] = append(haveDirs[abs], use.Path)
62 } 72 }
63 73
64 addDirs := make(map[string]bool) 74 // keepDirs maps each absolute path to keep to the literal string to use for
65 removeDirs := make(map[string]bool) 75 // that path (either an absolute or a relative path), or the empty string if
76 // all entries for the absolute path should be removed.
77 keepDirs := make(map[string]string)
78
79 // lookDir updates the entry in keepDirs for the directory dir,
80 // which is either absolute or relative to the current working directory
81 // (not necessarily the directory containing the workfile).
66 lookDir := func(dir string) { 82 lookDir := func(dir string) {
67 absDir := filepath.Join(base.Cwd(), dir) 83 absDir, dir := pathRel(workDir, dir)
68 // If the path is absolute, keep it absolute. If it's relative, 84
69 // make it relative to the go.work file rather than the working directory. 85 fi, err := os.Stat(filepath.Join(absDir, "go.mod"))
70 if !filepath.IsAbs(dir) {
71 rel, err := filepath.Rel(filepath.Dir(gowork), absDir)
72 if err == nil {
73 dir = rel
74 }
75 }
76 fi, err := os.Stat(filepath.Join(dir, "go.mod"))
77 if err != nil { 86 if err != nil {
78 if os.IsNotExist(err) { 87 if os.IsNotExist(err) {
79 88 keepDirs[absDir] = ""
80 if haveDirs[absDir] {
81 removeDirs[dir] = true
82 }
83 return 89 return
84 } 90 }
85 base.Errorf("go: %v", err) 91 base.Errorf("go: %v", err)
@@ -89,31 +95,96 @@ func runUse(ctx context.Context, cmd *base.Command, args []string) {
89 base.Errorf("go: %v is not regular", filepath.Join(dir, "go.mod")) 95 base.Errorf("go: %v is not regular", filepath.Join(dir, "go.mod"))
90 } 96 }
91 97
92 if !haveDirs[absDir] { 98 if dup := keepDirs[absDir]; dup != "" && dup != dir {
93 addDirs[dir] = true 99 base.Errorf(`go: already added "%s" as "%s"`, dir, dup)
94 } 100 }
101 keepDirs[absDir] = dir
95 } 102 }
96 103
97 for _, useDir := range args { 104 for _, useDir := range args {
98 if *useR { 105 if !*useR {
99 fsys.Walk(useDir, func(path string, info fs.FileInfo, err error) error { 106 lookDir(useDir)
100 if !info.IsDir() { 107 continue
101 return nil 108 }
109
110 // Add or remove entries for any subdirectories that still exist.
111 err := fsys.Walk(useDir, func(path string, info fs.FileInfo, err error) error {
112 if !info.IsDir() {
113 if info.Mode()&fs.ModeSymlink != 0 {
114 if target, err := fsys.Stat(path); err == nil && target.IsDir() {
115 fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
116 }
102 } 117 }
103 lookDir(path)
104 return nil 118 return nil
105 }) 119 }
106 continue 120 lookDir(path)
121 return nil
122 })
123 if err != nil && !errors.Is(err, os.ErrNotExist) {
124 base.Errorf("go: %v", err)
107 } 125 }
108 lookDir(useDir)
109 }
110 126
111 for dir := range removeDirs { 127 // Remove entries for subdirectories that no longer exist.
112 workFile.DropUse(filepath.ToSlash(dir)) 128 // Because they don't exist, they will be skipped by Walk.
129 absArg, _ := pathRel(workDir, useDir)
130 for absDir, _ := range haveDirs {
131 if str.HasFilePathPrefix(absDir, absArg) {
132 if _, ok := keepDirs[absDir]; !ok {
133 keepDirs[absDir] = "" // Mark for deletion.
134 }
135 }
136 }
113 } 137 }
114 for dir := range addDirs { 138
115 workFile.AddUse(filepath.ToSlash(dir), "") 139 base.ExitIfErrors()
140
141 for absDir, keepDir := range keepDirs {
142 nKept := 0
143 for _, dir := range haveDirs[absDir] {
144 if dir == keepDir { // (note that dir is always non-empty)
145 nKept++
146 } else {
147 workFile.DropUse(dir)
148 }
149 }
150 if keepDir != "" && nKept != 1 {
151 // If we kept more than one copy, delete them all.
152 // We'll recreate a unique copy with AddUse.
153 if nKept > 1 {
154 workFile.DropUse(keepDir)
155 }
156 workFile.AddUse(keepDir, "")
157 }
116 } 158 }
117 modload.UpdateWorkFile(workFile) 159 modload.UpdateWorkFile(workFile)
118 modload.WriteWorkFile(gowork, workFile) 160 modload.WriteWorkFile(gowork, workFile)
119} 161}
162
163// pathRel returns the absolute and canonical forms of dir for use in a
164// go.work file located in directory workDir.
165//
166// If dir is relative, it is intepreted relative to base.Cwd()
167// and its canonical form is relative to workDir if possible.
168// If dir is absolute or cannot be made relative to workDir,
169// its canonical form is absolute.
170//
171// Canonical absolute paths are clean.
172// Canonical relative paths are clean and slash-separated.
173func pathRel(workDir, dir string) (abs, canonical string) {
174 if filepath.IsAbs(dir) {
175 abs = filepath.Clean(dir)
176 return abs, abs
177 }
178
179 abs = filepath.Join(base.Cwd(), dir)
180 rel, err := filepath.Rel(workDir, abs)
181 if err != nil {
182 // The path can't be made relative to the go.work file,
183 // so it must be kept absolute instead.
184 return abs, abs
185 }
186
187 // Normalize relative paths to use slashes, so that checked-in go.work
188 // files with relative paths within the repo are platform-independent.
189 return abs, filepath.ToSlash(rel)
190}
diff --git a/libgo/go/cmd/go/internal/workcmd/work.go b/libgo/go/cmd/go/internal/workcmd/work.go
index 5bb0a2e8bad..d3cc250231a 100644
--- a/libgo/go/cmd/go/internal/workcmd/work.go
+++ b/libgo/go/cmd/go/internal/workcmd/work.go
@@ -27,7 +27,7 @@ workspace that does not specify modules to be used cannot be used to do
27builds from local modules. 27builds from local modules.
28 28
29go.work files are line-oriented. Each line holds a single directive, 29go.work files are line-oriented. Each line holds a single directive,
30made up of a keyword followed by aruments. For example: 30made up of a keyword followed by arguments. For example:
31 31
32 go 1.18 32 go 1.18
33 33
diff --git a/libgo/go/cmd/go/script_test.go b/libgo/go/cmd/go/script_test.go
index 0fc4b0f7abd..55a88e0e0b0 100644
--- a/libgo/go/cmd/go/script_test.go
+++ b/libgo/go/cmd/go/script_test.go
@@ -142,6 +142,8 @@ var extraEnvKeys = []string{
142 "SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210 142 "SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210
143 "WINDIR", // must be preserved on Windows to be able to run PowerShell command; golang.org/issue/30711 143 "WINDIR", // must be preserved on Windows to be able to run PowerShell command; golang.org/issue/30711
144 "LD_LIBRARY_PATH", // must be preserved on Unix systems to find shared libraries 144 "LD_LIBRARY_PATH", // must be preserved on Unix systems to find shared libraries
145 "LIBRARY_PATH", // allow override of non-standard static library paths
146 "C_INCLUDE_PATH", // allow override non-standard include paths
145 "CC", // don't lose user settings when invoking cgo 147 "CC", // don't lose user settings when invoking cgo
146 "GO_TESTING_GOTOOLS", // for gccgo testing 148 "GO_TESTING_GOTOOLS", // for gccgo testing
147 "GCCGO", // for gccgo testing 149 "GCCGO", // for gccgo testing
@@ -648,9 +650,9 @@ func (ts *testScript) doCmdCmp(want simpleStatus, args []string, env, quiet bool
648 } 650 }
649 case successOrFailure: 651 case successOrFailure:
650 if eq { 652 if eq {
651 fmt.Fprintf(&ts.log, "%s and %s do not differ", name1, name2) 653 fmt.Fprintf(&ts.log, "%s and %s do not differ\n", name1, name2)
652 } else { 654 } else {
653 fmt.Fprintf(&ts.log, "%s and %s differ", name1, name2) 655 fmt.Fprintf(&ts.log, "%s and %s differ\n", name1, name2)
654 } 656 }
655 default: 657 default:
656 ts.fatalf("unsupported: %v cmp", want) 658 ts.fatalf("unsupported: %v cmp", want)
@@ -902,7 +904,7 @@ func (ts *testScript) cmdStale(want simpleStatus, args []string) {
902 tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{{else}}" 904 tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{{else}}"
903 switch want { 905 switch want {
904 case failure: 906 case failure:
905 tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale{{end}}" 907 tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale: {{.StaleReason}}{{end}}"
906 case success: 908 case success:
907 tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}" 909 tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}"
908 default: 910 default:
diff --git a/libgo/go/cmd/go/testdata/script/build_internal.txt b/libgo/go/cmd/go/testdata/script/build_internal.txt
index 25aa18cfcb3..5b786f2fbce 100644
--- a/libgo/go/cmd/go/testdata/script/build_internal.txt
+++ b/libgo/go/cmd/go/testdata/script/build_internal.txt
@@ -10,8 +10,10 @@ stderr 'internal'
10 10
11# Test internal packages outside GOROOT are respected 11# Test internal packages outside GOROOT are respected
12cd ../testinternal2 12cd ../testinternal2
13env GO111MODULE=off
13! go build -v . 14! go build -v .
14stderr 'p\.go:3:8: use of internal package .*internal/w not allowed' 15stderr 'p\.go:3:8: use of internal package .*internal/w not allowed'
16env GO111MODULE=''
15 17
16[gccgo] skip # gccgo does not have GOROOT 18[gccgo] skip # gccgo does not have GOROOT
17cd ../testinternal 19cd ../testinternal
diff --git a/libgo/go/cmd/go/testdata/script/mod_download_partial.txt b/libgo/go/cmd/go/testdata/script/mod_download_partial.txt
index 3a02fcd7474..617b1fd8e36 100644
--- a/libgo/go/cmd/go/testdata/script/mod_download_partial.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_download_partial.txt
@@ -15,12 +15,13 @@ cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial
15go mod verify 15go mod verify
16 16
17# 'go list' should not load packages from the directory. 17# 'go list' should not load packages from the directory.
18# NOTE: the message "directory $dir outside available modules" is reported 18# NOTE: the message "directory $dir outside main module or its selected dependencies"
19# for directories not in the main module, active modules in the module cache, 19# is reported for directories not in the main module, active modules in the
20# or local replacements. In this case, the directory is in the right place, 20# module cache, or local replacements. In this case, the directory is in the
21# but it's incomplete, so 'go list' acts as if it's not an active module. 21# right place, but it's incomplete, so 'go list' acts as if it's not an
22# active module.
22! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 23! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
23stderr 'outside available modules' 24stderr 'outside main module or its selected dependencies'
24 25
25# 'go list -m' should not print the directory. 26# 'go list -m' should not print the directory.
26go list -m -f '{{.Dir}}' rsc.io/quote 27go list -m -f '{{.Dir}}' rsc.io/quote
diff --git a/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt b/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
index a20fefd6d39..276d04e538e 100644
--- a/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
@@ -51,11 +51,11 @@ stdout '^at$'
51# a package path. 51# a package path.
52cd ../badat/bad@ 52cd ../badat/bad@
53! go list . 53! go list .
54stderr 'directory . outside available modules' 54stderr 'directory . outside main module or its selected dependencies'
55! go list $PWD 55! go list $PWD
56stderr 'directory . outside available modules' 56stderr 'directory . outside main module or its selected dependencies'
57! go list $PWD/... 57! go list $PWD/...
58stderr 'directory . outside available modules' 58stderr 'directory . outside main module or its selected dependencies'
59 59
60-- x/go.mod -- 60-- x/go.mod --
61module m 61module m
diff --git a/libgo/go/cmd/go/testdata/script/mod_invalid_version.txt b/libgo/go/cmd/go/testdata/script/mod_invalid_version.txt
index 428b8aa60e6..8385b08d95f 100644
--- a/libgo/go/cmd/go/testdata/script/mod_invalid_version.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_invalid_version.txt
@@ -194,10 +194,10 @@ cp go.mod.orig go.mod
194go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible 194go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible
195cd outside 195cd outside
196! go list -m github.com/pierrec/lz4 196! go list -m github.com/pierrec/lz4
197stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' 197stderr '^go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
198cd .. 198cd ..
199! go list -m github.com/pierrec/lz4 199! go list -m github.com/pierrec/lz4
200stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' 200stderr '^go: github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
201 201
202# A +incompatible pseudo-version is valid for a revision of the module 202# A +incompatible pseudo-version is valid for a revision of the module
203# that lacks a go.mod file. 203# that lacks a go.mod file.
@@ -222,7 +222,7 @@ stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible'
222# not resolve to a pseudo-version with a different major version. 222# not resolve to a pseudo-version with a different major version.
223cp go.mod.orig go.mod 223cp go.mod.orig go.mod
224! go get github.com/pierrec/lz4@v2.0.8 224! go get github.com/pierrec/lz4@v2.0.8
225stderr 'go: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2' 225stderr 'go: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
226 226
227# An invalid +incompatible suffix for a canonical version should error out, 227# An invalid +incompatible suffix for a canonical version should error out,
228# not resolve to a pseudo-version. 228# not resolve to a pseudo-version.
@@ -233,10 +233,10 @@ cp go.mod.orig go.mod
233go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible 233go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible
234cd outside 234cd outside
235! go list -m github.com/pierrec/lz4 235! go list -m github.com/pierrec/lz4
236stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' 236stderr '^go: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
237cd .. 237cd ..
238! go list -m github.com/pierrec/lz4 238! go list -m github.com/pierrec/lz4
239stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' 239stderr '^go: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
240 240
241-- go.mod.orig -- 241-- go.mod.orig --
242module example.com 242module example.com
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_dir.txt b/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
index 7ad65ffbc73..157d3b6a8a6 100644
--- a/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
@@ -24,7 +24,7 @@ go get rsc.io/sampler@v1.3.1
24go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.1 24go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.1
25stdout '^rsc.io/sampler$' 25stdout '^rsc.io/sampler$'
26! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0 26! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0
27stderr 'outside available modules' 27stderr 'outside main module or its selected dependencies'
28 28
29-- go.mod -- 29-- go.mod --
30module x 30module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_replace_dir.txt b/libgo/go/cmd/go/testdata/script/mod_list_replace_dir.txt
index eac5ca7dd32..b446543916f 100644
--- a/libgo/go/cmd/go/testdata/script/mod_list_replace_dir.txt
+++ b/libgo/go/cmd/go/testdata/script/mod_list_replace_dir.txt
@@ -9,7 +9,7 @@ go get
9go mod download rsc.io/quote@v1.5.2 9go mod download rsc.io/quote@v1.5.2
10 10
11! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 11! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
12stderr '^directory ..[/\\]pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2 outside available modules$' 12stderr '^directory ..[/\\]pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2 outside main module or its selected dependencies$'
13 13
14go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.1 14go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.1
15stdout 'rsc.io/quote' 15stdout 'rsc.io/quote'
diff --git a/libgo/go/cmd/go/testdata/script/run_issue51125.txt b/libgo/go/cmd/go/testdata/script/run_issue51125.txt
new file mode 100644
index 00000000000..8fa4486ca41
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/run_issue51125.txt
@@ -0,0 +1,54 @@
1# Regression test for https://go.dev/issue/51125:
2# Relative import paths (a holdover from GOPATH) were accidentally allowed in module mode.
3
4cd $WORK
5
6# Relative imports should not be allowed with a go.mod file.
7
8! go run driver.go
9stderr '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$'
10
11go list -e -f '{{with .Error}}{{.}}{{end}}' -deps driver.go
12stdout '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$'
13! stderr .
14
15
16# Relative imports should not be allowed in module mode even without a go.mod file.
17rm go.mod
18
19! go run driver.go
20stderr '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$'
21
22go list -e -f '{{with .Error}}{{.}}{{end}}' -deps driver.go
23stdout '^driver.go:3:8: "./mypkg" is relative, but relative import paths are not supported in module mode$'
24! stderr .
25
26
27# In GOPATH mode, they're still allowed (but only outside of GOPATH/src).
28env GO111MODULE=off
29
30[!short] go run driver.go
31
32go list -deps driver.go
33
34
35-- $WORK/go.mod --
36module example
37
38go 1.17
39-- $WORK/driver.go --
40package main
41
42import "./mypkg"
43
44func main() {
45 mypkg.MyFunc()
46}
47-- $WORK/mypkg/code.go --
48package mypkg
49
50import "fmt"
51
52func MyFunc() {
53 fmt.Println("Hello, world!")
54}
diff --git a/libgo/go/cmd/go/testdata/script/test_fuzz_dup_cache.txt b/libgo/go/cmd/go/testdata/script/test_fuzz_dup_cache.txt
new file mode 100644
index 00000000000..52d44a26ff8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/test_fuzz_dup_cache.txt
@@ -0,0 +1,52 @@
1[!fuzz] skip
2[short] skip
3
4# This test checks that cached corpus loading properly handles duplicate entries (this can
5# happen when a f.Add value has a duplicate entry in the cached corpus.) Duplicate entries
6# should be discarded, and the rest of the cache should be loaded as normal.
7
8env GOCACHE=$WORK/cache
9env GODEBUG=fuzzdebug=1
10
11mkdir -p $GOCACHE/fuzz/fuzztest/FuzzTarget
12go run ./populate $GOCACHE/fuzz/fuzztest/FuzzTarget
13
14go test -fuzz=FuzzTarget -fuzztime=10x .
15stdout 'entries: 5'
16
17-- go.mod --
18module fuzztest
19
20go 1.17
21
22-- fuzz_test.go --
23package fuzz
24
25import "testing"
26
27func FuzzTarget(f *testing.F) {
28 f.Add(int(0))
29 f.Fuzz(func(t *testing.T, _ int) {})
30}
31
32-- populate/main.go --
33package main
34
35import (
36 "path/filepath"
37 "fmt"
38 "os"
39)
40
41func main() {
42 for i := 0; i < 10; i++ {
43 b := byte(0)
44 if i > 5 {
45 b = byte(i)
46 }
47 tmpl := "go test fuzz v1\nint(%d)\n"
48 if err := os.WriteFile(filepath.Join(os.Args[1], fmt.Sprint(i)), []byte(fmt.Sprintf(tmpl, b)), 0777); err != nil {
49 panic(err)
50 }
51 }
52} \ No newline at end of file
diff --git a/libgo/go/cmd/go/testdata/script/test_fuzz_return.txt b/libgo/go/cmd/go/testdata/script/test_fuzz_return.txt
new file mode 100644
index 00000000000..63275aad01d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/test_fuzz_return.txt
@@ -0,0 +1,19 @@
1[short] skip
2
3! go test .
4stdout '^panic: testing: fuzz target must not return a value \[recovered\]$'
5
6-- go.mod --
7module test
8go 1.18
9-- x_test.go --
10package test
11
12import "testing"
13
14func FuzzReturnErr(f *testing.F) {
15 f.Add("hello, validation!")
16 f.Fuzz(func(t *testing.T, in string) string {
17 return in
18 })
19}
diff --git a/libgo/go/cmd/go/testdata/script/test_relative_cmdline.txt b/libgo/go/cmd/go/testdata/script/test_relative_cmdline.txt
index 37aa3b1ec77..4c1fdf99022 100644
--- a/libgo/go/cmd/go/testdata/script/test_relative_cmdline.txt
+++ b/libgo/go/cmd/go/testdata/script/test_relative_cmdline.txt
@@ -1,5 +1,7 @@
1# Relative imports in command line package 1# Relative imports in command line package
2 2
3env GO111MODULE=off
4
3# Run tests outside GOPATH. 5# Run tests outside GOPATH.
4env GO111MODULE=off 6env GO111MODULE=off
5env GOPATH=$WORK/tmp 7env GOPATH=$WORK/tmp
diff --git a/libgo/go/cmd/go/testdata/script/work.txt b/libgo/go/cmd/go/testdata/script/work.txt
index cbb3746a69a..a10bf5a1c35 100644
--- a/libgo/go/cmd/go/testdata/script/work.txt
+++ b/libgo/go/cmd/go/testdata/script/work.txt
@@ -32,7 +32,9 @@ stdout 'example.com/b'
32go list -mod=readonly all 32go list -mod=readonly all
33! go list -mod=mod all 33! go list -mod=mod all
34stderr '^go: -mod may only be set to readonly when in workspace mode' 34stderr '^go: -mod may only be set to readonly when in workspace mode'
35go list -mod=mod -workfile=off all 35env GOWORK=off
36go list -mod=mod all
37env GOWORK=
36 38
37# Test that duplicates in the use list return an error 39# Test that duplicates in the use list return an error
38cp go.work go.work.backup 40cp go.work go.work.backup
@@ -53,7 +55,9 @@ go run example.com/d
53# This exercises the code that determines which module command-line-arguments 55# This exercises the code that determines which module command-line-arguments
54# belongs to. 56# belongs to.
55go list ./b/main.go 57go list ./b/main.go
56go build -n -workfile=off -o foo foo.go 58env GOWORK=off
59go build -n -o foo foo.go
60env GOWORK=
57go build -n -o foo foo.go 61go build -n -o foo foo.go
58 62
59-- go.work.dup -- 63-- go.work.dup --
diff --git a/libgo/go/cmd/go/testdata/script/work_edit.txt b/libgo/go/cmd/go/testdata/script/work_edit.txt
index fd04bbda6e8..71959ca0dd7 100644
--- a/libgo/go/cmd/go/testdata/script/work_edit.txt
+++ b/libgo/go/cmd/go/testdata/script/work_edit.txt
@@ -30,7 +30,8 @@ cmp stdout go.work.want_print
30go work edit -json -go 1.19 -use b -dropuse c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0 30go work edit -json -go 1.19 -use b -dropuse c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
31cmp stdout go.work.want_json 31cmp stdout go.work.want_json
32 32
33go work edit -print -fmt -workfile $GOPATH/src/unformatted 33env GOWORK=$GOPATH/src/unformatted
34go work edit -print -fmt
34cmp stdout formatted 35cmp stdout formatted
35 36
36-- m/go.mod -- 37-- m/go.mod --
diff --git a/libgo/go/cmd/go/testdata/script/work_env.txt b/libgo/go/cmd/go/testdata/script/work_env.txt
index ec3d3be3ed7..511bb4e2cb6 100644
--- a/libgo/go/cmd/go/testdata/script/work_env.txt
+++ b/libgo/go/cmd/go/testdata/script/work_env.txt
@@ -13,6 +13,10 @@ cd src
13go env GOWORK 13go env GOWORK
14stdout 'go.work' 14stdout 'go.work'
15 15
16env GOWORK='off'
17go env GOWORK
18stdout 'off'
19
16! go env -w GOWORK=off 20! go env -w GOWORK=off
17stderr '^go: GOWORK cannot be modified$' 21stderr '^go: GOWORK cannot be modified$'
18 22
diff --git a/libgo/go/cmd/go/testdata/script/work_gowork.txt b/libgo/go/cmd/go/testdata/script/work_gowork.txt
new file mode 100644
index 00000000000..1cfbf0ca18f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_gowork.txt
@@ -0,0 +1,24 @@
1env GOWORK=stop.work
2! go list a # require absolute path
3! stderr panic
4env GOWORK=doesnotexist
5! go list a
6! stderr panic
7
8env GOWORK=$GOPATH/src/stop.work
9go list -n a
10go build -n a
11go test -n a
12
13-- stop.work --
14go 1.18
15
16use ./a
17-- a/a.go --
18package a
19-- a/a_test.go --
20package a
21-- a/go.mod --
22module a
23
24go 1.18 \ No newline at end of file
diff --git a/libgo/go/cmd/go/testdata/script/work_init_gowork.txt b/libgo/go/cmd/go/testdata/script/work_init_gowork.txt
new file mode 100644
index 00000000000..55ac99b8c00
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_init_gowork.txt
@@ -0,0 +1,19 @@
1# Test that the GOWORK environment variable flag is used by go work init.
2
3! exists go.work
4go work init
5exists go.work
6
7env GOWORK=$GOPATH/src/foo/foo.work
8! exists foo/foo.work
9go work init
10exists foo/foo.work
11
12env GOWORK=
13cd foo/bar
14! go work init
15stderr 'already exists'
16
17# Create directories to make go.work files in.
18-- foo/dummy.txt --
19-- foo/bar/dummy.txt --
diff --git a/libgo/go/cmd/go/testdata/script/work_issue51204.txt b/libgo/go/cmd/go/testdata/script/work_issue51204.txt
new file mode 100644
index 00000000000..d4830020607
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_issue51204.txt
@@ -0,0 +1,57 @@
1go work sync
2
3go list -f '{{.Dir}}' example.com/test
4stdout '^'$PWD${/}test'$'
5
6-- go.work --
7go 1.18
8
9use (
10 ./test2
11 ./test2/sub
12)
13-- test/go.mod --
14module example.com/test
15
16go 1.18
17-- test/file.go --
18package test
19
20func DoSomething() {
21}
22-- test2/go.mod --
23module example.com/test2
24
25go 1.18
26
27replace example.com/test => ../test
28
29require example.com/test v0.0.0-00010101000000-000000000000
30-- test2/file.go --
31package test2
32
33import (
34 "example.com/test"
35)
36
37func DoSomething() {
38 test.DoSomething()
39}
40-- test2/sub/go.mod --
41module example.com/test2/sub
42
43go 1.18
44
45replace example.com/test => ../../test
46
47require example.com/test v0.0.0
48-- test2/sub/file.go --
49package test2
50
51import (
52 "example.com/test"
53)
54
55func DoSomething() {
56 test.DoSomething()
57}
diff --git a/libgo/go/cmd/go/testdata/script/work_module_not_in_go_work.txt b/libgo/go/cmd/go/testdata/script/work_module_not_in_go_work.txt
new file mode 100644
index 00000000000..23d908c3022
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_module_not_in_go_work.txt
@@ -0,0 +1,25 @@
1# This is a regression test for issue #49632.
2# The Go command should mention go.work if the user
3# tries to load a local package that's in a module
4# that's not in go.work and can't be resolved.
5
6! go list ./...
7stderr 'pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies'
8
9! go list ./a
10stderr 'directory a outside modules listed in go.work'
11
12-- go.work --
13go 1.18
14
15use ./b
16-- a/go.mod --
17module example.com/a
18
19go 1.18
20-- a/a.go --
21package a
22-- b/go.mod --
23module example.com/b
24
25go 1.18
diff --git a/libgo/go/cmd/go/testdata/script/work_nowork.txt b/libgo/go/cmd/go/testdata/script/work_nowork.txt
new file mode 100644
index 00000000000..b4c9b1d9cf3
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_nowork.txt
@@ -0,0 +1,20 @@
1! go work use
2stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
3
4! go work use .
5stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
6
7! go work edit
8stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
9
10! go work edit -go=1.18
11stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
12
13! go work sync
14stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
15
16-- go.mod --
17module example
18go 1.18
19-- README.txt --
20There is no go.work file here.
diff --git a/libgo/go/cmd/go/testdata/script/work_replace_conflict.txt b/libgo/go/cmd/go/testdata/script/work_replace_conflict.txt
index 81d1fcb0435..7b71b0fbd78 100644
--- a/libgo/go/cmd/go/testdata/script/work_replace_conflict.txt
+++ b/libgo/go/cmd/go/testdata/script/work_replace_conflict.txt
@@ -2,7 +2,7 @@
2# overriding it in the go.work file. 2# overriding it in the go.work file.
3 3
4! go list -m example.com/dep 4! go list -m example.com/dep
5stderr 'go: conflicting replacements for example.com/dep@v1.0.0:\n\t./dep1\n\t./dep2\nuse "go work edit -replace example.com/dep@v1.0.0=\[override\]" to resolve' 5stderr 'go: conflicting replacements for example.com/dep@v1.0.0:\n\t'$PWD${/}'dep1\n\t'$PWD${/}'dep2\nuse "go work edit -replace example.com/dep@v1.0.0=\[override\]" to resolve'
6go work edit -replace example.com/dep@v1.0.0=./dep1 6go work edit -replace example.com/dep@v1.0.0=./dep1
7go list -m example.com/dep 7go list -m example.com/dep
8stdout 'example.com/dep v1.0.0 => ./dep1' 8stdout 'example.com/dep v1.0.0 => ./dep1'
@@ -15,7 +15,7 @@ use n
15module example.com/m 15module example.com/m
16 16
17require example.com/dep v1.0.0 17require example.com/dep v1.0.0
18replace example.com/dep v1.0.0 => ./dep1 18replace example.com/dep v1.0.0 => ../dep1
19-- m/m.go -- 19-- m/m.go --
20package m 20package m
21 21
@@ -28,7 +28,7 @@ func F() {
28module example.com/n 28module example.com/n
29 29
30require example.com/dep v1.0.0 30require example.com/dep v1.0.0
31replace example.com/dep v1.0.0 => ./dep2 31replace example.com/dep v1.0.0 => ../dep2
32-- n/n.go -- 32-- n/n.go --
33package n 33package n
34 34
diff --git a/libgo/go/cmd/go/testdata/script/work_use_deleted.txt b/libgo/go/cmd/go/testdata/script/work_use_deleted.txt
new file mode 100644
index 00000000000..660eb56e2dd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_use_deleted.txt
@@ -0,0 +1,22 @@
1go work use -r .
2cmp go.work go.work.want
3
4-- go.work --
5go 1.18
6
7use (
8 .
9 sub
10 sub/dir/deleted
11)
12-- go.work.want --
13go 1.18
14
15use sub/dir
16-- sub/README.txt --
17A go.mod file has been deleted from this directory.
18In addition, the entire subdirectory sub/dir/deleted
19has been deleted, along with sub/dir/deleted/go.mod.
20-- sub/dir/go.mod --
21module example/sub/dir
22go 1.18
diff --git a/libgo/go/cmd/go/testdata/script/work_use_dot.txt b/libgo/go/cmd/go/testdata/script/work_use_dot.txt
new file mode 100644
index 00000000000..ccd83d6a61a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_use_dot.txt
@@ -0,0 +1,49 @@
1cp go.work go.work.orig
2
3# If the current directory contains a go.mod file,
4# 'go work use .' should add an entry for it.
5cd bar/baz
6go work use .
7cmp ../../go.work ../../go.work.rel
8
9# If the current directory lacks a go.mod file, 'go work use .'
10# should remove its entry.
11mv go.mod go.mod.bak
12go work use .
13cmp ../../go.work ../../go.work.orig
14
15# If the path is absolute, it should remain absolute.
16mv go.mod.bak go.mod
17go work use $PWD
18grep -count=1 '^use ' ../../go.work
19grep '^use ["]?'$PWD'["]?$' ../../go.work
20
21# An absolute path should replace an entry for the corresponding relative path
22# and vice-versa.
23go work use .
24cmp ../../go.work ../../go.work.rel
25go work use $PWD
26grep -count=1 '^use ' ../../go.work
27grep '^use ["]?'$PWD'["]?$' ../../go.work
28
29# If both the absolute and relative paths are named, 'go work use' should error
30# out: we don't know which one to use, and shouldn't add both because the
31# resulting workspace would contain a duplicate module.
32cp ../../go.work.orig ../../go.work
33! go work use $PWD .
34stderr '^go: already added "bar/baz" as "'$PWD'"$'
35cmp ../../go.work ../../go.work.orig
36
37
38-- go.mod --
39module example
40go 1.18
41-- go.work --
42go 1.18
43-- go.work.rel --
44go 1.18
45
46use bar/baz
47-- bar/baz/go.mod --
48module example/bar/baz
49go 1.18
diff --git a/libgo/go/cmd/go/testdata/script/work_use_issue50958.txt b/libgo/go/cmd/go/testdata/script/work_use_issue50958.txt
new file mode 100644
index 00000000000..7a25531f3d1
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_use_issue50958.txt
@@ -0,0 +1,17 @@
1go work use -r .
2cmp go.work go.work.want
3
4-- go.mod --
5module example
6go 1.18
7-- go.work --
8go 1.18
9
10use sub
11-- go.work.want --
12go 1.18
13
14use .
15-- sub/README.txt --
16This directory no longer contains a go.mod file.
17
diff --git a/libgo/go/cmd/go/testdata/script/work_vet.txt b/libgo/go/cmd/go/testdata/script/work_vet.txt
new file mode 100644
index 00000000000..e258fc03946
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/work_vet.txt
@@ -0,0 +1,19 @@
1! go vet ./a
2stderr 'fmt.Println call has possible formatting directive'
3
4-- go.work --
5go 1.18
6
7use ./a
8-- a/go.mod --
9module example.com/a
10
11go 1.18
12-- a/a.go --
13package a
14
15import "fmt"
16
17func A() {
18 fmt.Println("%s")
19} \ No newline at end of file
diff --git a/libgo/go/cmd/go/testdata/script/work_workfile.txt b/libgo/go/cmd/go/testdata/script/work_workfile.txt
deleted file mode 100644
index b62918147ef..00000000000
--- a/libgo/go/cmd/go/testdata/script/work_workfile.txt
+++ /dev/null
@@ -1,21 +0,0 @@
1! go list -workfile=stop.work a # require absolute path
2! stderr panic
3! go list -workfile=doesnotexist a
4! stderr panic
5
6go list -n -workfile=$GOPATH/src/stop.work a
7go build -n -workfile=$GOPATH/src/stop.work a
8go test -n -workfile=$GOPATH/src/stop.work a
9
10-- stop.work --
11go 1.18
12
13use ./a
14-- a/a.go --
15package a
16-- a/a_test.go --
17package a
18-- a/go.mod --
19module a
20
21go 1.18 \ No newline at end of file
diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go
index 51f6e652d9a..4280ed44590 100644
--- a/libgo/go/cmd/gofmt/gofmt.go
+++ b/libgo/go/cmd/gofmt/gofmt.go
@@ -52,6 +52,16 @@ const (
52 printerNormalizeNumbers = 1 << 30 52 printerNormalizeNumbers = 1 << 30
53) 53)
54 54
55// fdSem guards the number of concurrently-open file descriptors.
56//
57// For now, this is arbitrarily set to 200, based on the observation that many
58// platforms default to a kernel limit of 256. Ideally, perhaps we should derive
59// it from rlimit on platforms that support that system call.
60//
61// File descriptors opened from outside of this package are not tracked,
62// so this limit may be approximate.
63var fdSem = make(chan bool, 200)
64
55var ( 65var (
56 rewrite func(*token.FileSet, *ast.File) *ast.File 66 rewrite func(*token.FileSet, *ast.File) *ast.File
57 parserMode parser.Mode 67 parserMode parser.Mode
@@ -213,51 +223,9 @@ func (r *reporter) ExitCode() int {
213// If info == nil, we are formatting stdin instead of a file. 223// If info == nil, we are formatting stdin instead of a file.
214// If in == nil, the source is the contents of the file with the given filename. 224// If in == nil, the source is the contents of the file with the given filename.
215func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) error { 225func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) error {
216 if in == nil { 226 src, err := readFile(filename, info, in)
217 var err error 227 if err != nil {
218 in, err = os.Open(filename) 228 return err
219 if err != nil {
220 return err
221 }
222 }
223
224 // Compute the file's size and read its contents with minimal allocations.
225 //
226 // If the size is unknown (or bogus, or overflows an int), fall back to
227 // a size-independent ReadAll.
228 var src []byte
229 size := -1
230 if info != nil && info.Mode().IsRegular() && int64(int(info.Size())) == info.Size() {
231 size = int(info.Size())
232 }
233 if size+1 > 0 {
234 // If we have the FileInfo from filepath.WalkDir, use it to make
235 // a buffer of the right size and avoid ReadAll's reallocations.
236 //
237 // We try to read size+1 bytes so that we can detect modifications: if we
238 // read more than size bytes, then the file was modified concurrently.
239 // (If that happens, we could, say, append to src to finish the read, or
240 // proceed with a truncated buffer — but the fact that it changed at all
241 // indicates a possible race with someone editing the file, so we prefer to
242 // stop to avoid corrupting it.)
243 src = make([]byte, size+1)
244 n, err := io.ReadFull(in, src)
245 if err != nil && err != io.ErrUnexpectedEOF {
246 return err
247 }
248 if n < size {
249 return fmt.Errorf("error: size of %s changed during reading (from %d to %d bytes)", filename, size, n)
250 } else if n > size {
251 return fmt.Errorf("error: size of %s changed during reading (from %d to >=%d bytes)", filename, size, len(src))
252 }
253 src = src[:n]
254 } else {
255 // The file is not known to be regular, so we don't have a reliable size for it.
256 var err error
257 src, err = io.ReadAll(in)
258 if err != nil {
259 return err
260 }
261 } 229 }
262 230
263 fileSet := token.NewFileSet() 231 fileSet := token.NewFileSet()
@@ -306,7 +274,9 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) e
306 if err != nil { 274 if err != nil {
307 return err 275 return err
308 } 276 }
277 fdSem <- true
309 err = os.WriteFile(filename, res, perm) 278 err = os.WriteFile(filename, res, perm)
279 <-fdSem
310 if err != nil { 280 if err != nil {
311 os.Rename(bakname, filename) 281 os.Rename(bakname, filename)
312 return err 282 return err
@@ -333,6 +303,65 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) e
333 return err 303 return err
334} 304}
335 305
306// readFile reads the contents of filename, described by info.
307// If in is non-nil, readFile reads directly from it.
308// Otherwise, readFile opens and reads the file itself,
309// with the number of concurrently-open files limited by fdSem.
310func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) {
311 if in == nil {
312 fdSem <- true
313 var err error
314 f, err := os.Open(filename)
315 if err != nil {
316 return nil, err
317 }
318 in = f
319 defer func() {
320 f.Close()
321 <-fdSem
322 }()
323 }
324
325 // Compute the file's size and read its contents with minimal allocations.
326 //
327 // If we have the FileInfo from filepath.WalkDir, use it to make
328 // a buffer of the right size and avoid ReadAll's reallocations.
329 //
330 // If the size is unknown (or bogus, or overflows an int), fall back to
331 // a size-independent ReadAll.
332 size := -1
333 if info != nil && info.Mode().IsRegular() && int64(int(info.Size())) == info.Size() {
334 size = int(info.Size())
335 }
336 if size+1 <= 0 {
337 // The file is not known to be regular, so we don't have a reliable size for it.
338 var err error
339 src, err := io.ReadAll(in)
340 if err != nil {
341 return nil, err
342 }
343 return src, nil
344 }
345
346 // We try to read size+1 bytes so that we can detect modifications: if we
347 // read more than size bytes, then the file was modified concurrently.
348 // (If that happens, we could, say, append to src to finish the read, or
349 // proceed with a truncated buffer — but the fact that it changed at all
350 // indicates a possible race with someone editing the file, so we prefer to
351 // stop to avoid corrupting it.)
352 src := make([]byte, size+1)
353 n, err := io.ReadFull(in, src)
354 if err != nil && err != io.ErrUnexpectedEOF {
355 return nil, err
356 }
357 if n < size {
358 return nil, fmt.Errorf("error: size of %s changed during reading (from %d to %d bytes)", filename, size, n)
359 } else if n > size {
360 return nil, fmt.Errorf("error: size of %s changed during reading (from %d to >=%d bytes)", filename, size, len(src))
361 }
362 return src[:n], nil
363}
364
336func main() { 365func main() {
337 // Arbitrarily limit in-flight work to 2MiB times the number of threads. 366 // Arbitrarily limit in-flight work to 2MiB times the number of threads.
338 // 367 //
@@ -354,12 +383,16 @@ func gofmtMain(s *sequencer) {
354 flag.Parse() 383 flag.Parse()
355 384
356 if *cpuprofile != "" { 385 if *cpuprofile != "" {
386 fdSem <- true
357 f, err := os.Create(*cpuprofile) 387 f, err := os.Create(*cpuprofile)
358 if err != nil { 388 if err != nil {
359 s.AddReport(fmt.Errorf("creating cpu profile: %s", err)) 389 s.AddReport(fmt.Errorf("creating cpu profile: %s", err))
360 return 390 return
361 } 391 }
362 defer f.Close() 392 defer func() {
393 f.Close()
394 <-fdSem
395 }()
363 pprof.StartCPUProfile(f) 396 pprof.StartCPUProfile(f)
364 defer pprof.StopCPUProfile() 397 defer pprof.StopCPUProfile()
365 } 398 }
@@ -474,6 +507,9 @@ const chmodSupported = runtime.GOOS != "windows"
474// with <number randomly chosen such that the file name is unique. backupFile returns 507// with <number randomly chosen such that the file name is unique. backupFile returns
475// the chosen file name. 508// the chosen file name.
476func backupFile(filename string, data []byte, perm fs.FileMode) (string, error) { 509func backupFile(filename string, data []byte, perm fs.FileMode) (string, error) {
510 fdSem <- true
511 defer func() { <-fdSem }()
512
477 // create backup file 513 // create backup file
478 f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)) 514 f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename))
479 if err != nil { 515 if err != nil {
diff --git a/libgo/go/cmd/internal/objabi/funcdata.go b/libgo/go/cmd/internal/objabi/funcdata.go
index 4d49a8d548d..05a1d49decb 100644
--- a/libgo/go/cmd/internal/objabi/funcdata.go
+++ b/libgo/go/cmd/internal/objabi/funcdata.go
@@ -23,6 +23,7 @@ const (
23 FUNCDATA_OpenCodedDeferInfo = 4 23 FUNCDATA_OpenCodedDeferInfo = 4
24 FUNCDATA_ArgInfo = 5 24 FUNCDATA_ArgInfo = 5
25 FUNCDATA_ArgLiveInfo = 6 25 FUNCDATA_ArgLiveInfo = 6
26 FUNCDATA_WrapInfo = 7
26 27
27 // ArgsSizeUnknown is set in Func.argsize to mark all functions 28 // ArgsSizeUnknown is set in Func.argsize to mark all functions
28 // whose argument size is unknown (C vararg functions, and 29 // whose argument size is unknown (C vararg functions, and
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go
index 282596d2d2d..9f9a09a8842 100644
--- a/libgo/go/crypto/ecdsa/ecdsa.go
+++ b/libgo/go/crypto/ecdsa/ecdsa.go
@@ -3,28 +3,21 @@
3// license that can be found in the LICENSE file. 3// license that can be found in the LICENSE file.
4 4
5// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as 5// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
6// defined in FIPS 186-3. 6// defined in FIPS 186-4 and SEC 1, Version 2.0.
7// 7//
8// This implementation derives the nonce from an AES-CTR CSPRNG keyed by: 8// Signatures generated by this package are not deterministic, but entropy is
9// 9// mixed with the private key and the message, achieving the same level of
10// SHA2-512(priv.D || entropy || hash)[:32] 10// security in case of randomness source failure.
11//
12// The CSPRNG key is indifferentiable from a random oracle as shown in
13// [Coron], the AES-CTR stream is indifferentiable from a random oracle
14// under standard cryptographic assumptions (see [Larsson] for examples).
15//
16// References:
17// [Coron]
18// https://cs.nyu.edu/~dodis/ps/merkle.pdf
19// [Larsson]
20// https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf
21package ecdsa 11package ecdsa
22 12
23// Further references: 13// [FIPS 186-4] references ANSI X9.62-2005 for the bulk of the ECDSA algorithm.
24// [NSA]: Suite B implementer's guide to FIPS 186-3 14// That standard is not freely available, which is a problem in an open source
25// https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm 15// implementation, because not only the implementer, but also any maintainer,
26// [SECG]: SECG, SEC1 16// contributor, reviewer, auditor, and learner needs access to it. Instead, this
27// http://www.secg.org/sec1-v2.pdf 17// package references and follows the equivalent [SEC 1, Version 2.0].
18//
19// [FIPS 186-4]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
20// [SEC 1, Version 2.0]: https://www.secg.org/sec1-v2.pdf
28 21
29import ( 22import (
30 "crypto" 23 "crypto"
@@ -41,15 +34,16 @@ import (
41 "golang.org/x/crypto/cryptobyte/asn1" 34 "golang.org/x/crypto/cryptobyte/asn1"
42) 35)
43 36
44// A invertible implements fast inverse mod Curve.Params().N 37// A invertible implements fast inverse in GF(N).
45type invertible interface { 38type invertible interface {
46 // Inverse returns the inverse of k in GF(P) 39 // Inverse returns the inverse of k mod Params().N.
47 Inverse(k *big.Int) *big.Int 40 Inverse(k *big.Int) *big.Int
48} 41}
49 42
50// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point) 43// A combinedMult implements fast combined multiplication for verification.
51type combinedMult interface { 44type combinedMult interface {
52 CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) 45 // CombinedMult returns [s1]G + [s2]P where G is the generator.
46 CombinedMult(Px, Py *big.Int, s1, s2 []byte) (x, y *big.Int)
53} 47}
54 48
55const ( 49const (
@@ -111,7 +105,7 @@ func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
111// 105//
112// This method implements crypto.Signer, which is an interface to support keys 106// This method implements crypto.Signer, which is an interface to support keys
113// where the private part is kept in, for example, a hardware module. Common 107// where the private part is kept in, for example, a hardware module. Common
114// uses should use the Sign function in this package directly. 108// uses can use the SignASN1 function in this package directly.
115func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { 109func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
116 r, s, err := Sign(rand, priv, digest) 110 r, s, err := Sign(rand, priv, digest)
117 if err != nil { 111 if err != nil {
@@ -128,11 +122,13 @@ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp
128 122
129var one = new(big.Int).SetInt64(1) 123var one = new(big.Int).SetInt64(1)
130 124
131// randFieldElement returns a random element of the field underlying the given 125// randFieldElement returns a random element of the order of the given
132// curve using the procedure given in [NSA] A.2.1. 126// curve using the procedure given in FIPS 186-4, Appendix B.5.1.
133func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) { 127func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
134 params := c.Params() 128 params := c.Params()
135 b := make([]byte, params.BitSize/8+8) 129 // Note that for P-521 this will actually be 63 bits more than the order, as
130 // division rounds down, but the extra bit is inconsequential.
131 b := make([]byte, params.BitSize/8+8) // TODO: use params.N.BitLen()
136 _, err = io.ReadFull(rand, b) 132 _, err = io.ReadFull(rand, b)
137 if err != nil { 133 if err != nil {
138 return 134 return
@@ -159,12 +155,9 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
159 return priv, nil 155 return priv, nil
160} 156}
161 157
162// hashToInt converts a hash value to an integer. There is some disagreement 158// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4,
163// about how this is done. [NSA] suggests that this is done in the obvious 159// we use the left-most bits of the hash to match the bit-length of the order of
164// manner, but [SECG] truncates the hash to the bit-length of the curve order 160// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3.
165// first. We follow [SECG] because that's what OpenSSL does. Additionally,
166// OpenSSL right shifts excess bits from the number if the hash is too large
167// and we mirror that too.
168func hashToInt(hash []byte, c elliptic.Curve) *big.Int { 161func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
169 orderBits := c.Params().N.BitLen() 162 orderBits := c.Params().N.BitLen()
170 orderBytes := (orderBits + 7) / 8 163 orderBytes := (orderBits + 7) / 8
@@ -180,10 +173,11 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
180 return ret 173 return ret
181} 174}
182 175
183// fermatInverse calculates the inverse of k in GF(P) using Fermat's method. 176// fermatInverse calculates the inverse of k in GF(P) using Fermat's method
184// This has better constant-time properties than Euclid's method (implemented 177// (exponentiation modulo P - 2, per Euler's theorem). This has better
185// in math/big.Int.ModInverse) although math/big itself isn't strictly 178// constant-time properties than Euclid's method (implemented in
186// constant-time so it's not perfect. 179// math/big.Int.ModInverse and FIPS 186-4, Appendix C.1) although math/big
180// itself isn't strictly constant-time so it's not perfect.
187func fermatInverse(k, N *big.Int) *big.Int { 181func fermatInverse(k, N *big.Int) *big.Int {
188 two := big.NewInt(2) 182 two := big.NewInt(2)
189 nMinus2 := new(big.Int).Sub(N, two) 183 nMinus2 := new(big.Int).Sub(N, two)
@@ -195,11 +189,22 @@ var errZeroParam = errors.New("zero parameter")
195// Sign signs a hash (which should be the result of hashing a larger message) 189// Sign signs a hash (which should be the result of hashing a larger message)
196// using the private key, priv. If the hash is longer than the bit-length of the 190// using the private key, priv. If the hash is longer than the bit-length of the
197// private key's curve order, the hash will be truncated to that length. It 191// private key's curve order, the hash will be truncated to that length. It
198// returns the signature as a pair of integers. The security of the private key 192// returns the signature as a pair of integers. Most applications should use
199// depends on the entropy of rand. 193// SignASN1 instead of dealing directly with r, s.
200func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { 194func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
201 randutil.MaybeReadByte(rand) 195 randutil.MaybeReadByte(rand)
202 196
197 // This implementation derives the nonce from an AES-CTR CSPRNG keyed by:
198 //
199 // SHA2-512(priv.D || entropy || hash)[:32]
200 //
201 // The CSPRNG key is indifferentiable from a random oracle as shown in
202 // [Coron], the AES-CTR stream is indifferentiable from a random oracle
203 // under standard cryptographic assumptions (see [Larsson] for examples).
204 //
205 // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf
206 // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf
207
203 // Get 256 bits of entropy from rand. 208 // Get 256 bits of entropy from rand.
204 entropy := make([]byte, 32) 209 entropy := make([]byte, 32)
205 _, err = io.ReadFull(rand, entropy) 210 _, err = io.ReadFull(rand, entropy)
@@ -207,7 +212,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
207 return 212 return
208 } 213 }
209 214
210 // Initialize an SHA-512 hash context; digest ... 215 // Initialize an SHA-512 hash context; digest...
211 md := sha512.New() 216 md := sha512.New()
212 md.Write(priv.D.Bytes()) // the private key, 217 md.Write(priv.D.Bytes()) // the private key,
213 md.Write(entropy) // the entropy, 218 md.Write(entropy) // the entropy,
@@ -228,12 +233,12 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
228 S: cipher.NewCTR(block, []byte(aesIV)), 233 S: cipher.NewCTR(block, []byte(aesIV)),
229 } 234 }
230 235
231 // See [NSA] 3.4.1
232 c := priv.PublicKey.Curve 236 c := priv.PublicKey.Curve
233 return sign(priv, &csprng, c, hash) 237 return sign(priv, &csprng, c, hash)
234} 238}
235 239
236func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) { 240func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
241 // SEC 1, Version 2.0, Section 4.1.3
237 N := c.Params().N 242 N := c.Params().N
238 if N.Sign() == 0 { 243 if N.Sign() == 0 {
239 return nil, nil, errZeroParam 244 return nil, nil, errZeroParam
@@ -276,16 +281,15 @@ func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve
276// SignASN1 signs a hash (which should be the result of hashing a larger message) 281// SignASN1 signs a hash (which should be the result of hashing a larger message)
277// using the private key, priv. If the hash is longer than the bit-length of the 282// using the private key, priv. If the hash is longer than the bit-length of the
278// private key's curve order, the hash will be truncated to that length. It 283// private key's curve order, the hash will be truncated to that length. It
279// returns the ASN.1 encoded signature. The security of the private key 284// returns the ASN.1 encoded signature.
280// depends on the entropy of rand.
281func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) { 285func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
282 return priv.Sign(rand, hash, nil) 286 return priv.Sign(rand, hash, nil)
283} 287}
284 288
285// Verify verifies the signature in r, s of hash using the public key, pub. Its 289// Verify verifies the signature in r, s of hash using the public key, pub. Its
286// return value records whether the signature is valid. 290// return value records whether the signature is valid. Most applications should
291// use VerifyASN1 instead of dealing directly with r, s.
287func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { 292func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
288 // See [NSA] 3.4.2
289 c := pub.Curve 293 c := pub.Curve
290 N := c.Params().N 294 N := c.Params().N
291 295
@@ -299,6 +303,7 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
299} 303}
300 304
301func verifyGeneric(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool { 305func verifyGeneric(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
306 // SEC 1, Version 2.0, Section 4.1.4
302 e := hashToInt(hash, c) 307 e := hashToInt(hash, c)
303 var w *big.Int 308 var w *big.Int
304 N := c.Params().N 309 N := c.Params().N
diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go
index d06a2841546..7ead09f8d3f 100644
--- a/libgo/go/crypto/elliptic/elliptic.go
+++ b/libgo/go/crypto/elliptic/elliptic.go
@@ -2,17 +2,10 @@
2// Use of this source code is governed by a BSD-style 2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file. 3// license that can be found in the LICENSE file.
4 4
5// Package elliptic implements several standard elliptic curves over prime 5// Package elliptic implements the standard NIST P-224, P-256, P-384, and P-521
6// fields. 6// elliptic curves over prime fields.
7package elliptic 7package elliptic
8 8
9// This package operates, internally, on Jacobian coordinates. For a given
10// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
11// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
12// calculation can be performed within the transform (as in ScalarMult and
13// ScalarBaseMult). But even for Add and Double, it's faster to apply and
14// reverse the transform than to operate in affine coordinates.
15
16import ( 9import (
17 "io" 10 "io"
18 "math/big" 11 "math/big"
@@ -21,12 +14,12 @@ import (
21 14
22// A Curve represents a short-form Weierstrass curve with a=-3. 15// A Curve represents a short-form Weierstrass curve with a=-3.
23// 16//
24// The output of Add, Double, and ScalarMult when the input is not a point on 17// The behavior of Add, Double, and ScalarMult when the input is not a point on
25// the curve is undefined. 18// the curve is undefined.
26// 19//
27// Note that the conventional point at infinity (0, 0) is not considered on the 20// Note that the conventional point at infinity (0, 0) is not considered on the
28// curve, although it can be returned by Add, Double, ScalarMult, or 21// curve, although it can be returned by Add, Double, ScalarMult, or
29// ScalarBaseMult (but not Unmarshal or UnmarshalCompressed). 22// ScalarBaseMult (but not the Unmarshal or UnmarshalCompressed functions).
30type Curve interface { 23type Curve interface {
31 // Params returns the parameters for the curve. 24 // Params returns the parameters for the curve.
32 Params() *CurveParams 25 Params() *CurveParams
@@ -67,6 +60,13 @@ func (curve *CurveParams) Params() *CurveParams {
67 return curve 60 return curve
68} 61}
69 62
63// CurveParams operates, internally, on Jacobian coordinates. For a given
64// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
65// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
66// calculation can be performed within the transform (as in ScalarMult and
67// ScalarBaseMult). But even for Add and Double, it's faster to apply and
68// reverse the transform than to operate in affine coordinates.
69
70// polynomial returns x³ - 3x + b. 70// polynomial returns x³ - 3x + b.
71func (curve *CurveParams) polynomial(x *big.Int) *big.Int { 71func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
72 x3 := new(big.Int).Mul(x, x) 72 x3 := new(big.Int).Mul(x, x)
@@ -89,6 +89,11 @@ func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
89 return specific.IsOnCurve(x, y) 89 return specific.IsOnCurve(x, y)
90 } 90 }
91 91
92 if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
93 y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
94 return false
95 }
96
92 // y² = x³ - 3x + b 97 // y² = x³ - 3x + b
93 y2 := new(big.Int).Mul(y, y) 98 y2 := new(big.Int).Mul(y, y)
94 y2.Mod(y2, curve.P) 99 y2.Mod(y2, curve.P)
@@ -353,7 +358,8 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e
353} 358}
354 359
355// Marshal converts a point on the curve into the uncompressed form specified in 360// Marshal converts a point on the curve into the uncompressed form specified in
356// section 4.3.6 of ANSI X9.62. 361// SEC 1, Version 2.0, Section 2.3.3. If the point is not on the curve (or is
362// the conventional point at infinity), the behavior is undefined.
357func Marshal(curve Curve, x, y *big.Int) []byte { 363func Marshal(curve Curve, x, y *big.Int) []byte {
358 byteLen := (curve.Params().BitSize + 7) / 8 364 byteLen := (curve.Params().BitSize + 7) / 8
359 365
@@ -367,7 +373,8 @@ func Marshal(curve Curve, x, y *big.Int) []byte {
367} 373}
368 374
369// MarshalCompressed converts a point on the curve into the compressed form 375// MarshalCompressed converts a point on the curve into the compressed form
370// specified in section 4.3.6 of ANSI X9.62. 376// specified in SEC 1, Version 2.0, Section 2.3.3. If the point is not on the
377// curve (or is the conventional point at infinity), the behavior is undefined.
371func MarshalCompressed(curve Curve, x, y *big.Int) []byte { 378func MarshalCompressed(curve Curve, x, y *big.Int) []byte {
372 byteLen := (curve.Params().BitSize + 7) / 8 379 byteLen := (curve.Params().BitSize + 7) / 8
373 compressed := make([]byte, 1+byteLen) 380 compressed := make([]byte, 1+byteLen)
@@ -376,9 +383,9 @@ func MarshalCompressed(curve Curve, x, y *big.Int) []byte {
376 return compressed 383 return compressed
377} 384}
378 385
379// Unmarshal converts a point, serialized by Marshal, into an x, y pair. 386// Unmarshal converts a point, serialized by Marshal, into an x, y pair. It is
380// It is an error if the point is not in uncompressed form or is not on the curve. 387// an error if the point is not in uncompressed form, is not on the curve, or is
381// On error, x = nil. 388// the point at infinity. On error, x = nil.
382func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { 389func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
383 byteLen := (curve.Params().BitSize + 7) / 8 390 byteLen := (curve.Params().BitSize + 7) / 8
384 if len(data) != 1+2*byteLen { 391 if len(data) != 1+2*byteLen {
@@ -399,9 +406,9 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
399 return 406 return
400} 407}
401 408
402// UnmarshalCompressed converts a point, serialized by MarshalCompressed, into an x, y pair. 409// UnmarshalCompressed converts a point, serialized by MarshalCompressed, into
403// It is an error if the point is not in compressed form or is not on the curve. 410// an x, y pair. It is an error if the point is not in compressed form, is not
404// On error, x = nil. 411// on the curve, or is the point at infinity. On error, x = nil.
405func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) { 412func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) {
406 byteLen := (curve.Params().BitSize + 7) / 8 413 byteLen := (curve.Params().BitSize + 7) / 8
407 if len(data) != 1+byteLen { 414 if len(data) != 1+byteLen {
diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go
index f5b36f75ca0..5481929db15 100644
--- a/libgo/go/crypto/elliptic/elliptic_test.go
+++ b/libgo/go/crypto/elliptic/elliptic_test.go
@@ -182,6 +182,61 @@ func testUnmarshalToLargeCoordinates(t *testing.T, curve Curve) {
182 } 182 }
183} 183}
184 184
185// TestInvalidCoordinates tests big.Int values that are not valid field elements
186// (negative or bigger than P). They are expected to return false from
187// IsOnCurve, all other behavior is undefined.
188func TestInvalidCoordinates(t *testing.T) {
189 testAllCurves(t, testInvalidCoordinates)
190}
191
192func testInvalidCoordinates(t *testing.T, curve Curve) {
193 checkIsOnCurveFalse := func(name string, x, y *big.Int) {
194 if curve.IsOnCurve(x, y) {
195 t.Errorf("IsOnCurve(%s) unexpectedly returned true", name)
196 }
197 }
198
199 p := curve.Params().P
200 _, x, y, _ := GenerateKey(curve, rand.Reader)
201 xx, yy := new(big.Int), new(big.Int)
202
203 // Check if the sign is getting dropped.
204 xx.Neg(x)
205 checkIsOnCurveFalse("-x, y", xx, y)
206 yy.Neg(y)
207 checkIsOnCurveFalse("x, -y", x, yy)
208
209 // Check if negative values are reduced modulo P.
210 xx.Sub(x, p)
211 checkIsOnCurveFalse("x-P, y", xx, y)
212 yy.Sub(y, p)
213 checkIsOnCurveFalse("x, y-P", x, yy)
214
215 // Check if positive values are reduced modulo P.
216 xx.Add(x, p)
217 checkIsOnCurveFalse("x+P, y", xx, y)
218 yy.Add(y, p)
219 checkIsOnCurveFalse("x, y+P", x, yy)
220
221 // Check if the overflow is dropped.
222 xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535))
223 checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y)
224 yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535))
225 checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy)
226
227 // Check if P is treated like zero (if possible).
228 // y^2 = x^3 - 3x + B
229 // y = mod_sqrt(x^3 - 3x + B)
230 // y = mod_sqrt(B) if x = 0
231 // If there is no modsqrt, there is no point with x = 0, can't test x = P.
232 if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil {
233 if !curve.IsOnCurve(big.NewInt(0), yy) {
234 t.Fatal("(0, mod_sqrt(B)) is not on the curve?")
235 }
236 checkIsOnCurveFalse("P, y", p, yy)
237 }
238}
239
185func TestMarshalCompressed(t *testing.T) { 240func TestMarshalCompressed(t *testing.T) {
186 t.Run("P-256/03", func(t *testing.T) { 241 t.Run("P-256/03", func(t *testing.T) {
187 data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79") 242 data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
diff --git a/libgo/go/crypto/elliptic/gen_p256_table.go b/libgo/go/crypto/elliptic/gen_p256_table.go
index 367bd4b67d9..0ebbc664945 100644
--- a/libgo/go/crypto/elliptic/gen_p256_table.go
+++ b/libgo/go/crypto/elliptic/gen_p256_table.go
@@ -7,30 +7,13 @@
7package main 7package main
8 8
9import ( 9import (
10 "bytes"
11 "crypto/elliptic" 10 "crypto/elliptic"
12 "encoding/binary" 11 "encoding/binary"
13 "fmt"
14 "go/format"
15 "log" 12 "log"
16 "os" 13 "os"
17) 14)
18 15
19func main() { 16func main() {
20 buf := new(bytes.Buffer)
21 fmt.Fprint(buf, `
22// Copyright 2021 The Go Authors. All rights reserved.
23// Use of this source code is governed by a BSD-style
24// license that can be found in the LICENSE file.
25
26// Generated by gen_p256_table.go. DO NOT EDIT.
27
28//go:build amd64 || arm64
29
30package elliptic
31
32`[1:])
33
34 // Generate precomputed p256 tables. 17 // Generate precomputed p256 tables.
35 var pre [43][32 * 8]uint64 18 var pre [43][32 * 8]uint64
36 basePoint := []uint64{ 19 basePoint := []uint64{
@@ -70,41 +53,21 @@ package elliptic
70 } 53 }
71 } 54 }
72 55
73 fmt.Fprint(buf, "const p256Precomputed = \"\" +\n\n") 56 var bin []byte
74 57
75 // Dump the precomputed tables, flattened, little-endian. 58 // Dump the precomputed tables, flattened, little-endian.
76 // These tables are used directly by assembly on little-endian platforms. 59 // These tables are used directly by assembly on little-endian platforms.
77 // Putting the data in a const string lets it be stored readonly. 60 // go:embedding the data into a string lets it be stored readonly.
78 for i := range &pre { 61 for i := range &pre {
79 for j, v := range &pre[i] { 62 for _, v := range &pre[i] {
80 fmt.Fprintf(buf, "\"")
81 var u8 [8]byte 63 var u8 [8]byte
82 binary.LittleEndian.PutUint64(u8[:], v) 64 binary.LittleEndian.PutUint64(u8[:], v)
83 for _, b := range &u8 { 65 bin = append(bin, u8[:]...)
84 fmt.Fprintf(buf, "\\x%02x", b)
85 }
86 fmt.Fprintf(buf, "\"")
87 if i < len(pre)-1 || j < len(pre[i])-1 {
88 fmt.Fprint(buf, "+")
89 }
90 if j%8 == 7 {
91 fmt.Fprint(buf, "\n")
92 }
93 } 66 }
94 fmt.Fprint(buf, "\n")
95 } 67 }
96 68
97 src := buf.Bytes() 69 err := os.WriteFile("p256_asm_table.bin", bin, 0644)
98 fmtsrc, fmterr := format.Source(src)
99 // If formatting failed, keep the original source for debugging.
100 if fmterr == nil {
101 src = fmtsrc
102 }
103 err := os.WriteFile("p256_asm_table.go", src, 0644)
104 if err != nil { 70 if err != nil {
105 log.Fatal(err) 71 log.Fatal(err)
106 } 72 }
107 if fmterr != nil {
108 log.Fatal(fmterr)
109 }
110} 73}
diff --git a/libgo/go/crypto/elliptic/p224.go b/libgo/go/crypto/elliptic/p224.go
index a8533b85ff4..8a431c47692 100644
--- a/libgo/go/crypto/elliptic/p224.go
+++ b/libgo/go/crypto/elliptic/p224.go
@@ -61,6 +61,9 @@ func p224PointFromAffine(x, y *big.Int) (p *nistec.P224Point, ok bool) {
61 if x.Sign() == 0 && y.Sign() == 0 { 61 if x.Sign() == 0 && y.Sign() == 0 {
62 return nistec.NewP224Point(), true 62 return nistec.NewP224Point(), true
63 } 63 }
64 if x.Sign() < 0 || y.Sign() < 0 {
65 return nil, false
66 }
64 if x.BitLen() > 224 || y.BitLen() > 224 { 67 if x.BitLen() > 224 || y.BitLen() > 224 {
65 return nil, false 68 return nil, false
66 } 69 }
diff --git a/libgo/go/crypto/elliptic/p256.go b/libgo/go/crypto/elliptic/p256.go
index 1fbeb680604..a2d00a39b1a 100644
--- a/libgo/go/crypto/elliptic/p256.go
+++ b/libgo/go/crypto/elliptic/p256.go
@@ -6,11 +6,11 @@
6 6
7package elliptic 7package elliptic
8 8
9// This file contains a constant-time, 32-bit implementation of P256. 9// P-256 is implemented by various different backends, including a generic
10// 32-bit constant-time one in this file, which is used when assembly
11// implementations are not available, or not appropriate for the hardware.
10 12
11import ( 13import "math/big"
12 "math/big"
13)
14 14
15type p256Curve struct { 15type p256Curve struct {
16 *CurveParams 16 *CurveParams
diff --git a/libgo/go/crypto/elliptic/p256_asm.go b/libgo/go/crypto/elliptic/p256_asm.go
index ac004291993..63c3606ce52 100644
--- a/libgo/go/crypto/elliptic/p256_asm.go
+++ b/libgo/go/crypto/elliptic/p256_asm.go
@@ -15,11 +15,15 @@
15package elliptic 15package elliptic
16 16
17import ( 17import (
18 _ "embed"
18 "math/big" 19 "math/big"
19) 20)
20 21
21//go:generate go run -tags=tablegen gen_p256_table.go 22//go:generate go run -tags=tablegen gen_p256_table.go
22 23
24//go:embed p256_asm_table.bin
25var p256Precomputed string
26
23type ( 27type (
24 p256Curve struct { 28 p256Curve struct {
25 *CurveParams 29 *CurveParams
diff --git a/libgo/go/crypto/elliptic/p256_asm_table.go b/libgo/go/crypto/elliptic/p256_asm_table.go
deleted file mode 100644
index c0814ba5a38..00000000000
--- a/libgo/go/crypto/elliptic/p256_asm_table.go
+++ /dev/null
@@ -1,1430 +0,0 @@
1// Copyright 2021 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Generated by gen_p256_table.go. DO NOT EDIT.
6
7//go:build ignore && (amd64 || arm64)
8
9package elliptic
10
11const p256Precomputed = "" +
12