libgo, compiler: Upgrade libgo to Go 1.4, except for runtime.

This upgrades all of libgo other than the runtime package to
the Go 1.4 release.  In Go 1.4 much of the runtime was
rewritten into Go.  Merging that code will take more time and
will not change the API, so I'm putting it off for now.

There are a few runtime changes anyhow, to accomodate other
packages that rely on minor modifications to the runtime
support.

The compiler changes slightly to add a one-bit flag to each
type descriptor kind that is stored directly in an interface,
which for gccgo is currently only pointer types.  Another
one-bit flag (gcprog) is reserved because it is used by the gc
compiler, but gccgo does not currently use it.

There is another error check in the compiler since I ran
across it during testing.

gotools/:
	* Makefile.am (go_cmd_go_files): Sort entries.  Add generate.go.
	* Makefile.in: Rebuild.

From-SVN: r219627
This commit is contained in:
Ian Lance Taylor 2015-01-15 00:27:56 +00:00 committed by Ian Lance Taylor
parent 6bd3f109d8
commit f8d9fa9e80
619 changed files with 29942 additions and 6952 deletions

View File

@ -15559,7 +15559,7 @@ bool
Numeric_constant::set_type(Type* type, bool issue_error, Location loc)
{
bool ret;
if (type == NULL)
if (type == NULL || type->is_error())
ret = true;
else if (type->integer_type() != NULL)
ret = this->check_int_type(type->integer_type(), issue_error, loc);

View File

@ -1966,6 +1966,8 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
if (!this->has_pointer())
runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
if (this->points_to() != NULL)
runtime_type_kind |= RUNTIME_TYPE_KIND_DIRECT_IFACE;
Struct_field_list::const_iterator p = fields->begin();
go_assert(p->is_field_name("kind"));
vals->push_back(Expression::make_integer_ul(runtime_type_kind, p->type(),

View File

@ -81,6 +81,8 @@ static const int RUNTIME_TYPE_KIND_STRING = 24;
static const int RUNTIME_TYPE_KIND_STRUCT = 25;
static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
static const int RUNTIME_TYPE_KIND_DIRECT_IFACE = (1 << 5);
static const int RUNTIME_TYPE_KIND_GC_PROG = (1 << 6);
static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
// GC instruction opcodes. These must match the values in libgo/runtime/mgc0.h.

View File

@ -1,3 +1,8 @@
2015-01-14 Ian Lance Taylor <iant@google.com>
* Makefile.am (go_cmd_go_files): Sort entries. Add generate.go.
* Makefile.in: Rebuild.
2015-01-09 Ian Lance Taylor <iant@google.com>
* Makefile.am (GOCOMPILER): Set to GOC or GOC_FOR_TARGET depending

View File

@ -46,27 +46,28 @@ cmdsrcdir = $(srcdir)/../libgo/go/cmd
go_cmd_go_files = \
$(cmdsrcdir)/go/build.go \
$(cmdsrcdir)/go/clean.go \
$(cmdsrcdir)/go/main.go \
$(cmdsrcdir)/go/signal.go \
$(cmdsrcdir)/go/version.go \
$(cmdsrcdir)/go/env.go \
$(cmdsrcdir)/go/help.go \
$(cmdsrcdir)/go/run.go \
$(cmdsrcdir)/go/tool.go \
$(cmdsrcdir)/go/vet.go \
$(cmdsrcdir)/go/context.go \
$(cmdsrcdir)/go/fix.go \
$(cmdsrcdir)/go/get.go \
$(cmdsrcdir)/go/http.go \
$(cmdsrcdir)/go/signal_unix.go \
$(cmdsrcdir)/go/vcs.go \
$(cmdsrcdir)/go/discovery.go \
$(cmdsrcdir)/go/env.go \
$(cmdsrcdir)/go/fix.go \
$(cmdsrcdir)/go/fmt.go \
$(cmdsrcdir)/go/generate.go \
$(cmdsrcdir)/go/get.go \
$(cmdsrcdir)/go/go11.go \
$(cmdsrcdir)/go/help.go \
$(cmdsrcdir)/go/http.go \
$(cmdsrcdir)/go/list.go \
$(cmdsrcdir)/go/main.go \
$(cmdsrcdir)/go/pkg.go \
$(cmdsrcdir)/go/run.go \
$(cmdsrcdir)/go/signal.go \
$(cmdsrcdir)/go/signal_unix.go \
$(cmdsrcdir)/go/test.go \
$(cmdsrcdir)/go/testflag.go
$(cmdsrcdir)/go/testflag.go \
$(cmdsrcdir)/go/tool.go \
$(cmdsrcdir)/go/vcs.go \
$(cmdsrcdir)/go/version.go \
$(cmdsrcdir)/go/vet.go
go_cmd_gofmt_files = \
$(cmdsrcdir)/gofmt/doc.go \

View File

@ -211,27 +211,28 @@ cmdsrcdir = $(srcdir)/../libgo/go/cmd
go_cmd_go_files = \
$(cmdsrcdir)/go/build.go \
$(cmdsrcdir)/go/clean.go \
$(cmdsrcdir)/go/main.go \
$(cmdsrcdir)/go/signal.go \
$(cmdsrcdir)/go/version.go \
$(cmdsrcdir)/go/env.go \
$(cmdsrcdir)/go/help.go \
$(cmdsrcdir)/go/run.go \
$(cmdsrcdir)/go/tool.go \
$(cmdsrcdir)/go/vet.go \
$(cmdsrcdir)/go/context.go \
$(cmdsrcdir)/go/fix.go \
$(cmdsrcdir)/go/get.go \
$(cmdsrcdir)/go/http.go \
$(cmdsrcdir)/go/signal_unix.go \
$(cmdsrcdir)/go/vcs.go \
$(cmdsrcdir)/go/discovery.go \
$(cmdsrcdir)/go/env.go \
$(cmdsrcdir)/go/fix.go \
$(cmdsrcdir)/go/fmt.go \
$(cmdsrcdir)/go/generate.go \
$(cmdsrcdir)/go/get.go \
$(cmdsrcdir)/go/go11.go \
$(cmdsrcdir)/go/help.go \
$(cmdsrcdir)/go/http.go \
$(cmdsrcdir)/go/list.go \
$(cmdsrcdir)/go/main.go \
$(cmdsrcdir)/go/pkg.go \
$(cmdsrcdir)/go/run.go \
$(cmdsrcdir)/go/signal.go \
$(cmdsrcdir)/go/signal_unix.go \
$(cmdsrcdir)/go/test.go \
$(cmdsrcdir)/go/testflag.go
$(cmdsrcdir)/go/testflag.go \
$(cmdsrcdir)/go/tool.go \
$(cmdsrcdir)/go/vcs.go \
$(cmdsrcdir)/go/version.go \
$(cmdsrcdir)/go/vet.go
go_cmd_gofmt_files = \
$(cmdsrcdir)/gofmt/doc.go \

View File

@ -1,4 +1,4 @@
f44017549ff9
14854533dcc7
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.

View File

@ -495,6 +495,7 @@ runtime_files = \
runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \
runtime/go-unsafe-pointer.c \
runtime/go-unsetenv.c \
runtime/go-unwind.c \
runtime/go-varargs.c \
runtime/env_posix.c \
@ -695,7 +696,7 @@ go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
else
if LIBGO_IS_SOLARIS
go_net_cgo_file = go/net/cgo_linux.go
go_net_sock_file = go/net/sock_solaris.go
go_net_sock_file = go/net/sock_stub.go
go_net_sockopt_file = go/net/sockopt_solaris.go
go_net_sockoptip_file = go/net/sockoptip_stub.go
else
@ -761,9 +762,6 @@ else
if LIBGO_IS_DARWIN
go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
else
if LIBGO_IS_SOLARIS
go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
else
if LIBGO_IS_DRAGONFLY
go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
else
@ -771,7 +769,6 @@ go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
endif
endif
endif
endif
go_net_files = \
go/net/cgo_unix.go \
@ -997,7 +994,6 @@ go_runtime_files = \
go/runtime/extern.go \
go/runtime/mem.go \
go/runtime/softfloat64.go \
go/runtime/type.go \
version.go
version.go: s-version; @true
@ -1187,10 +1183,19 @@ go_crypto_md5_files = \
go/crypto/md5/md5.go \
go/crypto/md5/md5block.go \
go/crypto/md5/md5block_generic.go
if LIBGO_IS_LINUX
crypto_rand_file = go/crypto/rand/rand_linux.go
else
crypto_rand_file =
endif
go_crypto_rand_files = \
go/crypto/rand/rand.go \
go/crypto/rand/rand_unix.go \
$(crypto_rand_file) \
go/crypto/rand/util.go
go_crypto_rc4_files = \
go/crypto/rc4/rc4.go \
go/crypto/rc4/rc4_ref.go
@ -1289,9 +1294,11 @@ go_encoding_csv_files = \
go_encoding_gob_files = \
go/encoding/gob/decode.go \
go/encoding/gob/decoder.go \
go/encoding/gob/dec_helpers.go \
go/encoding/gob/doc.go \
go/encoding/gob/encode.go \
go/encoding/gob/encoder.go \
go/encoding/gob/enc_helpers.go \
go/encoding/gob/error.go \
go/encoding/gob/type.go
go_encoding_hex_files = \
@ -1452,7 +1459,6 @@ go_mime_multipart_files = \
go/mime/multipart/writer.go
go_net_http_files = \
go/net/http/chunked.go \
go/net/http/client.go \
go/net/http/cookie.go \
go/net/http/filetransport.go \
@ -1496,12 +1502,12 @@ go_net_http_httptest_files = \
go_net_http_pprof_files = \
go/net/http/pprof/pprof.go
go_net_http_httputil_files = \
go/net/http/httputil/chunked.go \
go/net/http/httputil/dump.go \
go/net/http/httputil/httputil.go \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
go_net_http_internal_files = \
go/net/http/internal/chunked.go
go_old_regexp_files = \
go/old/regexp/regexp.go
@ -1535,7 +1541,8 @@ go_path_filepath_files = \
go/path/filepath/match.go \
go/path/filepath/path.go \
go/path/filepath/path_unix.go \
go/path/filepath/symlink.go
go/path/filepath/symlink.go \
go/path/filepath/symlink_unix.go
go_regexp_syntax_files = \
go/regexp/syntax/compile.go \
@ -1570,7 +1577,8 @@ go_text_template_parse_files = \
go/text/template/parse/parse.go
go_sync_atomic_files = \
go/sync/atomic/doc.go
go/sync/atomic/doc.go \
go/sync/atomic/value.go
go_sync_atomic_c_files = \
go/sync/atomic/atomic.c
@ -1784,10 +1792,21 @@ go_syscall_c_files = \
go_syscall_test_files = \
$(syscall_creds_test_file) \
go/syscall/export_test.go \
go/syscall/mmap_unix_test.go \
go/syscall/syscall_test.go \
go/syscall/syscall_unix_test.go
if LIBGO_IS_LINUX
internal_syscall_getrandom_file = go/internal/syscall/getrandom_linux.go
else
internal_syscall_getrandom_file =
endif
go_internal_syscall_files = \
go/internal/syscall/dummy.go \
$(internal_syscall_getrandom_file)
libcalls.go: s-libcalls; @true
s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
rm -f libcalls.go.tmp
@ -1957,6 +1976,7 @@ libgo_go_objs = \
net/http/fcgi.lo \
net/http/httptest.lo \
net/http/httputil.lo \
net/http/internal.lo \
net/http/pprof.lo \
image/color.lo \
image/color/palette.lo \
@ -1965,6 +1985,7 @@ libgo_go_objs = \
image/jpeg.lo \
image/png.lo \
index/suffixarray.lo \
internal/syscall.lo \
io/ioutil.lo \
log/syslog.lo \
log/syslog/syslog_c.lo \
@ -3160,6 +3181,15 @@ net/http/httputil/check: $(check_deps)
@$(CHECK)
.PHONY: net/http/httputil/check
@go_include@ net/http/internal.lo.dep
net/http/internal.lo.dep: $(go_net_http_internal_files)
$(BUILDDEPS)
net/http/internal.lo: $(go_net_http_internal_files)
$(BUILDPACKAGE)
net/http/internal/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/internal/check
@go_include@ net/http/pprof.lo.dep
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
$(BUILDDEPS)
@ -3260,7 +3290,8 @@ runtime/pprof/check: $(CHECK_DEPS)
.PHONY: runtime/pprof/check
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
runtime_pprof_check_GOCFLAGS = -static-libgo
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
@go_include@ sync/atomic.lo.dep
sync/atomic.lo.dep: $(go_sync_atomic_files)
@ -3363,6 +3394,15 @@ syscall/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: syscall/check
@go_include@ internal/syscall.lo.dep
internal/syscall.lo.dep: $(go_internal_syscall_files)
$(BUILDDEPS)
internal/syscall.lo: $(go_internal_syscall_files)
$(BUILDPACKAGE)
internal/syscall/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: internal/syscall/check
# How to build a .gox file from a .lo file.
BUILDGOX = \
f=`echo $< | sed -e 's/.lo$$/.o/'`; \
@ -3623,6 +3663,9 @@ net/http/httputil.gox: net/http/httputil.lo
net/http/pprof.gox: net/http/pprof.lo
$(BUILDGOX)
net/http/internal.gox: net/http/internal.lo
$(BUILDGOX)
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
@ -3652,6 +3695,9 @@ runtime/pprof.gox: runtime/pprof.lo
sync/atomic.gox: sync/atomic.lo
$(BUILDGOX)
internal/syscall.gox: internal/syscall.lo
$(BUILDGOX)
text/scanner.gox: text/scanner.lo
$(BUILDGOX)
text/tabwriter.gox: text/tabwriter.lo
@ -3774,6 +3820,7 @@ TEST_PACKAGES = \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
net/http/internal/check \
net/mail/check \
net/rpc/check \
net/smtp/check \

View File

@ -164,14 +164,15 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \
hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
net/http/httputil.lo net/http/pprof.lo image/color.lo \
image/color/palette.lo image/draw.lo image/gif.lo \
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
math/rand.lo mime/multipart.lo net/http.lo net/mail.lo \
net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \
image/color.lo image/color/palette.lo image/draw.lo \
image/gif.lo image/jpeg.lo image/png.lo index/suffixarray.lo \
internal/syscall.lo io/ioutil.lo log/syslog.lo \
log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \
net/smtp.lo net/textproto.lo net/url.lo old/regexp.lo \
old/template.lo os/exec.lo $(am__DEPENDENCIES_1) os/signal.lo \
os/user.lo path/filepath.lo regexp/syntax.lo \
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
text/tabwriter.lo text/template.lo text/template/parse.lo \
@ -218,15 +219,15 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
go-type-complex.lo go-type-eface.lo go-type-error.lo \
go-type-float.lo go-type-identity.lo go-type-interface.lo \
go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unwind.lo \
go-varargs.lo env_posix.lo heapdump.lo $(am__objects_1) \
mcache.lo mcentral.lo $(am__objects_2) mfixalloc.lo mgc0.lo \
mheap.lo msize.lo $(am__objects_3) panic.lo parfor.lo print.lo \
proc.lo runtime.lo signal_unix.lo thread.lo yield.lo \
$(am__objects_4) chan.lo cpuprof.lo go-iface.lo lfstack.lo \
malloc.lo map.lo mprof.lo netpoll.lo rdebug.lo reflect.lo \
runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
$(am__objects_5)
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo \
$(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \
mfixalloc.lo mgc0.lo mheap.lo msize.lo $(am__objects_3) \
panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
thread.lo yield.lo $(am__objects_4) chan.lo cpuprof.lo \
go-iface.lo lfstack.lo malloc.lo map.lo mprof.lo netpoll.lo \
rdebug.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo \
time.lo $(am__objects_5)
am_libgo_llgo_la_OBJECTS = $(am__objects_6)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@ -838,6 +839,7 @@ runtime_files = \
runtime/go-unsafe-new.c \
runtime/go-unsafe-newarray.c \
runtime/go-unsafe-pointer.c \
runtime/go-unsetenv.c \
runtime/go-unwind.c \
runtime/go-varargs.c \
runtime/env_posix.c \
@ -992,7 +994,7 @@ go_mime_files = \
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_solaris.go
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_stub.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
@ -1017,9 +1019,8 @@ go_mime_files = \
@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sys_cloexec.go
@LIBGO_IS_LINUX_TRUE@go_net_cloexec_file = go/net/sock_cloexec.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
@LIBGO_IS_OPENBSD_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_openbsd.go
go_net_files = \
@ -1180,7 +1181,6 @@ go_runtime_files = \
go/runtime/extern.go \
go/runtime/mem.go \
go/runtime/softfloat64.go \
go/runtime/type.go \
version.go
go_sort_files = \
@ -1348,9 +1348,12 @@ go_crypto_md5_files = \
go/crypto/md5/md5block.go \
go/crypto/md5/md5block_generic.go
@LIBGO_IS_LINUX_FALSE@crypto_rand_file =
@LIBGO_IS_LINUX_TRUE@crypto_rand_file = go/crypto/rand/rand_linux.go
go_crypto_rand_files = \
go/crypto/rand/rand.go \
go/crypto/rand/rand_unix.go \
$(crypto_rand_file) \
go/crypto/rand/util.go
go_crypto_rc4_files = \
@ -1469,9 +1472,11 @@ go_encoding_csv_files = \
go_encoding_gob_files = \
go/encoding/gob/decode.go \
go/encoding/gob/decoder.go \
go/encoding/gob/dec_helpers.go \
go/encoding/gob/doc.go \
go/encoding/gob/encode.go \
go/encoding/gob/encoder.go \
go/encoding/gob/enc_helpers.go \
go/encoding/gob/error.go \
go/encoding/gob/type.go
@ -1649,7 +1654,6 @@ go_mime_multipart_files = \
go/mime/multipart/writer.go
go_net_http_files = \
go/net/http/chunked.go \
go/net/http/client.go \
go/net/http/cookie.go \
go/net/http/filetransport.go \
@ -1702,12 +1706,14 @@ go_net_http_pprof_files = \
go/net/http/pprof/pprof.go
go_net_http_httputil_files = \
go/net/http/httputil/chunked.go \
go/net/http/httputil/dump.go \
go/net/http/httputil/httputil.go \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
go_net_http_internal_files = \
go/net/http/internal/chunked.go
go_old_regexp_files = \
go/old/regexp/regexp.go
@ -1737,7 +1743,8 @@ go_path_filepath_files = \
go/path/filepath/match.go \
go/path/filepath/path.go \
go/path/filepath/path_unix.go \
go/path/filepath/symlink.go
go/path/filepath/symlink.go \
go/path/filepath/symlink_unix.go
go_regexp_syntax_files = \
go/regexp/syntax/compile.go \
@ -1775,7 +1782,8 @@ go_text_template_parse_files = \
go/text/template/parse/parse.go
go_sync_atomic_files = \
go/sync/atomic/doc.go
go/sync/atomic/doc.go \
go/sync/atomic/value.go
go_sync_atomic_c_files = \
go/sync/atomic/atomic.c
@ -1918,10 +1926,17 @@ go_syscall_c_files = \
go_syscall_test_files = \
$(syscall_creds_test_file) \
go/syscall/export_test.go \
go/syscall/mmap_unix_test.go \
go/syscall/syscall_test.go \
go/syscall/syscall_unix_test.go
@LIBGO_IS_LINUX_FALSE@internal_syscall_getrandom_file =
@LIBGO_IS_LINUX_TRUE@internal_syscall_getrandom_file = go/internal/syscall/getrandom_linux.go
go_internal_syscall_files = \
go/internal/syscall/dummy.go \
$(internal_syscall_getrandom_file)
@LIBGO_IS_LINUX_FALSE@os_lib_inotify_lo =
# os_lib_inotify_lo = os/inotify.lo
@ -2030,6 +2045,7 @@ libgo_go_objs = \
net/http/fcgi.lo \
net/http/httptest.lo \
net/http/httputil.lo \
net/http/internal.lo \
net/http/pprof.lo \
image/color.lo \
image/color/palette.lo \
@ -2038,6 +2054,7 @@ libgo_go_objs = \
image/jpeg.lo \
image/png.lo \
index/suffixarray.lo \
internal/syscall.lo \
io/ioutil.lo \
log/syslog.lo \
log/syslog/syslog_c.lo \
@ -2169,7 +2186,8 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
runtime_pprof_check_GOCFLAGS = -static-libgo
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
# How to build a .gox file from a .lo file.
BUILDGOX = \
@ -2279,6 +2297,7 @@ TEST_PACKAGES = \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
net/http/internal/check \
net/mail/check \
net/rpc/check \
net/smtp/check \
@ -2515,6 +2534,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsetenv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heapdump.Plo@am__quote@
@ -3031,6 +3051,13 @@ go-unsafe-pointer.lo: runtime/go-unsafe-pointer.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
go-unsetenv.lo: runtime/go-unsetenv.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsetenv.lo -MD -MP -MF $(DEPDIR)/go-unsetenv.Tpo -c -o go-unsetenv.lo `test -f 'runtime/go-unsetenv.c' || echo '$(srcdir)/'`runtime/go-unsetenv.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsetenv.Tpo $(DEPDIR)/go-unsetenv.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unsetenv.c' object='go-unsetenv.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsetenv.lo `test -f 'runtime/go-unsetenv.c' || echo '$(srcdir)/'`runtime/go-unsetenv.c
go-unwind.lo: runtime/go-unwind.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unwind.lo -MD -MP -MF $(DEPDIR)/go-unwind.Tpo -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unwind.Tpo $(DEPDIR)/go-unwind.Plo
@ -5498,6 +5525,15 @@ net/http/httputil/check: $(check_deps)
@$(CHECK)
.PHONY: net/http/httputil/check
@go_include@ net/http/internal.lo.dep
net/http/internal.lo.dep: $(go_net_http_internal_files)
$(BUILDDEPS)
net/http/internal.lo: $(go_net_http_internal_files)
$(BUILDPACKAGE)
net/http/internal/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/internal/check
@go_include@ net/http/pprof.lo.dep
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
$(BUILDDEPS)
@ -5698,6 +5734,15 @@ syscall/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: syscall/check
@go_include@ internal/syscall.lo.dep
internal/syscall.lo.dep: $(go_internal_syscall_files)
$(BUILDDEPS)
internal/syscall.lo: $(go_internal_syscall_files)
$(BUILDPACKAGE)
internal/syscall/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: internal/syscall/check
bufio.gox: bufio.lo
$(BUILDGOX)
bytes.gox: bytes.lo
@ -5953,6 +5998,9 @@ net/http/httputil.gox: net/http/httputil.lo
net/http/pprof.gox: net/http/pprof.lo
$(BUILDGOX)
net/http/internal.gox: net/http/internal.lo
$(BUILDGOX)
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
@ -5982,6 +6030,9 @@ runtime/pprof.gox: runtime/pprof.lo
sync/atomic.gox: sync/atomic.lo
$(BUILDGOX)
internal/syscall.gox: internal/syscall.lo
$(BUILDGOX)
text/scanner.gox: text/scanner.lo
$(BUILDGOX)
text/tabwriter.gox: text/tabwriter.lo

View File

@ -319,6 +319,9 @@
/* Define to 1 if you have the `unlinkat' function. */
#undef HAVE_UNLINKAT
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the `unshare' function. */
#undef HAVE_UNSHARE

2
libgo/configure vendored
View File

@ -14805,7 +14805,7 @@ else
fi
for ac_func in strerror_r strsignal wait4 mincore setenv dl_iterate_phdr
for ac_func in strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View File

@ -551,7 +551,7 @@ fi
AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv dl_iterate_phdr)
AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr)
AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)

View File

@ -29,10 +29,11 @@ const maxNanoSecondIntSize = 9
// The Next method advances to the next file in the archive (including the first),
// and then it can be treated as an io.Reader to access the file's data.
type Reader struct {
r io.Reader
err error
pad int64 // amount of padding (ignored) after current file entry
curr numBytesReader // reader for current file entry
r io.Reader
err error
pad int64 // amount of padding (ignored) after current file entry
curr numBytesReader // reader for current file entry
hdrBuff [blockSize]byte // buffer to use in readHeader
}
// A numBytesReader is an io.Reader with a numBytes method, returning the number
@ -426,7 +427,9 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
}
func (tr *Reader) readHeader() *Header {
header := make([]byte, blockSize)
header := tr.hdrBuff[:]
copy(header, zeroBlock)
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
return nil
}

View File

@ -37,8 +37,10 @@ type Writer struct {
nb int64 // number of unwritten bytes for current file entry
pad int64 // amount of padding to write after current file entry
closed bool
usedBinary bool // whether the binary numeric field extension was used
preferPax bool // use pax header instead of binary numeric header
usedBinary bool // whether the binary numeric field extension was used
preferPax bool // use pax header instead of binary numeric header
hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
}
// NewWriter creates a new Writer writing to w.
@ -160,7 +162,18 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
// subsecond time resolution, but for now let's just capture
// too long fields or non ascii characters
header := make([]byte, blockSize)
var header []byte
// We need to select which scratch buffer to use carefully,
// since this method is called recursively to write PAX headers.
// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
// already being used by the non-recursive call, so we must use paxHdrBuff.
header = tw.hdrBuff[:]
if !allowPax {
header = tw.paxHdrBuff[:]
}
copy(header, zeroBlock)
s := slicer(header)
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax

View File

@ -454,3 +454,38 @@ func TestUSTARLongName(t *testing.T) {
t.Fatal("Couldn't recover long name")
}
}
func TestValidTypeflagWithPAXHeader(t *testing.T) {
var buffer bytes.Buffer
tw := NewWriter(&buffer)
fileName := strings.Repeat("ab", 100)
hdr := &Header{
Name: fileName,
Size: 4,
Typeflag: 0,
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatalf("Failed to write header: %s", err)
}
if _, err := tw.Write([]byte("fooo")); err != nil {
t.Fatalf("Failed to write the file's data: %s", err)
}
tw.Close()
tr := NewReader(&buffer)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("Failed to read header: %s", err)
}
if header.Typeflag != 0 {
t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
}
}
}

View File

@ -267,8 +267,13 @@ func readDirectoryHeader(f *File, r io.Reader) error {
b = b[size:]
}
// Should have consumed the whole header.
if len(b) != 0 {
return ErrFormat
// But popular zip & JAR creation tools are broken and
// may pad extra zeros at the end, so accept those
// too. See golang.org/issue/8186.
for _, v := range b {
if v != 0 {
return ErrFormat
}
}
}
return nil

View File

@ -13,6 +13,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
)
@ -508,3 +509,25 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
b := rZipBytes()
return bytes.NewReader(b), int64(len(b))
}
func TestIssue8186(t *testing.T) {
// Directory headers & data found in the TOC of a JAR file.
dirEnts := []string{
"PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\xaa\x1b\x06\xf0\x81\x02\x00\x00\x81\x02\x00\x00-\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00res/drawable-xhdpi-v4/ic_actionbar_accept.png\xfe\xca\x00\x00\x00",
"PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\x90K\x89\xc7t\n\x00\x00t\n\x00\x00\x0e\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x02\x00\x00resources.arsc\x00\x00\x00",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xff$\x18\xed3\x03\x00\x00\xb4\b\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\r\x00\x00AndroidManifest.xml",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\x14\xc5K\xab\x192\x02\x00\xc8\xcd\x04\x00\v\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x10\x00\x00classes.dex",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?E\x96\nD\xac\x01\x00\x00P\x03\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:C\x02\x00res/layout/actionbar_set_wallpaper.xml",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?Ļ\x14\xe3\xd8\x01\x00\x00\xd8\x03\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:E\x02\x00res/layout/wallpaper_cropper.xml",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?}\xc1\x15\x9eZ\x01\x00\x00!\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`G\x02\x00META-INF/MANIFEST.MF",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xe6\x98Ьo\x01\x00\x00\x84\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcH\x02\x00META-INF/CERT.SF",
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xbfP\x96b\x86\x04\x00\x00\xb2\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9J\x02\x00META-INF/CERT.RSA",
}
for i, s := range dirEnts {
var f File
err := readDirectoryHeader(&f, strings.NewReader(s))
if err != nil {
t.Errorf("error reading #%d: %v", i, err)
}
}
}

View File

@ -34,6 +34,12 @@ func NewWriter(w io.Writer) *Writer {
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
}
// Flush flushes any buffered data to the underlying writer.
// Calling Flush is not normally necessary; calling Close is sufficient.
func (w *Writer) Flush() error {
return w.cw.w.(*bufio.Writer).Flush()
}
// Close finishes writing the zip file by writing the central directory.
// It does not (and can not) close the underlying writer.
func (w *Writer) Close() error {

View File

@ -6,6 +6,7 @@ package zip
import (
"bytes"
"io"
"io/ioutil"
"math/rand"
"os"
@ -86,6 +87,24 @@ func TestWriter(t *testing.T) {
}
}
func TestWriterFlush(t *testing.T) {
var buf bytes.Buffer
w := NewWriter(struct{ io.Writer }{&buf})
_, err := w.Create("foo")
if err != nil {
t.Fatal(err)
}
if buf.Len() > 0 {
t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
}
if err := w.Flush(); err != nil {
t.Fatal(err)
}
if buf.Len() == 0 {
t.Fatal("No bytes written after Flush")
}
}
func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
header := &FileHeader{
Name: wt.Name,

View File

@ -30,8 +30,8 @@ var (
// Reader implements buffering for an io.Reader object.
type Reader struct {
buf []byte
rd io.Reader
r, w int
rd io.Reader // reader provided by the client
r, w int // buf read and write positions
err error
lastByte int
lastRuneSize int
@ -131,18 +131,17 @@ func (b *Reader) Peek(n int) ([]byte, error) {
for b.w-b.r < n && b.err == nil {
b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
m := b.w - b.r
if m > n {
m = n
}
var err error
if m < n {
if avail := b.w - b.r; avail < n {
// not enough data in buffer
n = avail
err = b.readErr()
if err == nil {
err = ErrBufferFull
}
}
return b.buf[b.r : b.r+m], err
return b.buf[b.r : b.r+n], err
}
// Read reads data into p.
@ -173,15 +172,13 @@ func (b *Reader) Read(p []byte) (n int, err error) {
return n, b.readErr()
}
b.fill() // buffer is empty
if b.w == b.r {
if b.r == b.w {
return 0, b.readErr()
}
}
if n > b.w-b.r {
n = b.w - b.r
}
copy(p[0:n], b.buf[b.r:])
// copy as much as we can
n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = -1
@ -288,7 +285,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
}
// Buffer full?
if n := b.Buffered(); n >= len(b.buf) {
if b.Buffered() >= len(b.buf) {
b.r = b.w
line = b.buf
err = ErrBufferFull
@ -301,6 +298,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
// Handle last byte, if any.
if i := len(line) - 1; i >= 0 {
b.lastByte = int(line[i])
b.lastRuneSize = -1
}
return
@ -458,11 +456,13 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
return n, b.readErr()
}
var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
// writeBuf writes the Reader's buffer to the writer.
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
n, err := w.Write(b.buf[b.r:b.w])
if n < b.r-b.w {
panic(errors.New("bufio: writer did not write all data"))
if n < 0 {
panic(errNegativeWrite)
}
b.r += n
return int64(n), err

View File

@ -31,9 +31,6 @@ func newRot13Reader(r io.Reader) *rot13Reader {
func (r13 *rot13Reader) Read(p []byte) (int, error) {
n, err := r13.r.Read(p)
if err != nil {
return n, err
}
for i := 0; i < n; i++ {
c := p[i] | 0x20 // lowercase byte
if 'a' <= c && c <= 'm' {
@ -42,7 +39,7 @@ func (r13 *rot13Reader) Read(p []byte) (int, error) {
p[i] -= 13
}
}
return n, nil
return n, err
}
// Call ReadByte to accumulate the text of a file
@ -438,7 +435,7 @@ func TestUnreadRuneError(t *testing.T) {
if err != nil {
t.Error("unexpected error on ReadRune (2):", err)
}
for _ = range buf {
for range buf {
_, err = r.ReadByte()
if err != nil {
t.Error("unexpected error on ReadByte (2):", err)
@ -463,6 +460,18 @@ func TestUnreadRuneError(t *testing.T) {
if r.UnreadRune() == nil {
t.Error("expected error after UnreadByte (3)")
}
// Test error after ReadSlice.
_, _, err = r.ReadRune() // reset state
if err != nil {
t.Error("unexpected error on ReadRune (4):", err)
}
_, err = r.ReadSlice(0)
if err != io.EOF {
t.Error("unexpected error on ReadSlice (4):", err)
}
if r.UnreadRune() == nil {
t.Error("expected error after ReadSlice (4)")
}
}
func TestUnreadRuneAtEOF(t *testing.T) {

View File

@ -36,6 +36,7 @@ type Scanner struct {
start int // First non-processed byte in buf.
end int // End of data in buf.
err error // Sticky error.
empties int // Count of successive empty tokens.
}
// SplitFunc is the signature of the split function used to tokenize the
@ -64,8 +65,9 @@ var (
)
const (
// Maximum size used to buffer a token. The actual maximum token size
// may be smaller as the buffer may need to include, for instance, a newline.
// MaxScanTokenSize is the maximum size used to buffer a token.
// The actual maximum token size may be smaller as the buffer
// may need to include, for instance, a newline.
MaxScanTokenSize = 64 * 1024
)
@ -107,11 +109,15 @@ func (s *Scanner) Text() string {
// After Scan returns false, the Err method will return any error that
// occurred during scanning, except that if it was io.EOF, Err
// will return nil.
// Split panics if the split function returns 100 empty tokens without
// advancing the input. This is a common error mode for scanners.
func (s *Scanner) Scan() bool {
// Loop until we have a token.
for {
// See if we can get a token with what we already have.
if s.end > s.start {
// If we've run out of data but have an error, give the split function
// a chance to recover any remaining, possibly empty token.
if s.end > s.start || s.err != nil {
advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
if err != nil {
s.setErr(err)
@ -122,6 +128,15 @@ func (s *Scanner) Scan() bool {
}
s.token = token
if token != nil {
if s.err == nil || advance > 0 {
s.empties = 0
} else {
// Returning tokens not advancing input at EOF.
s.empties++
if s.empties > 100 {
panic("bufio.Scan: 100 empty tokens without progressing")
}
}
return true
}
}
@ -169,6 +184,7 @@ func (s *Scanner) Scan() bool {
break
}
if n > 0 {
s.empties = 0
break
}
loop++
@ -326,9 +342,6 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
break
}
}
if atEOF && len(data) == 0 {
return 0, nil, nil
}
// Scan until space, marking end of word.
for width, i := 0, start; i < len(data); i += width {
var r rune
@ -342,5 +355,5 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
return len(data), data[start:], nil
}
// Request more data.
return 0, nil, nil
return start, nil, nil
}

View File

@ -15,6 +15,8 @@ import (
"unicode/utf8"
)
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
// Test white space table matches the Unicode definition.
func TestSpace(t *testing.T) {
for r := rune(0); r <= utf8.MaxRune; r++ {
@ -172,7 +174,6 @@ func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
// Test the line splitter, including some carriage returns but no long lines.
func TestScanLongLines(t *testing.T) {
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
// Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
tmp := new(bytes.Buffer)
buf := new(bytes.Buffer)
@ -404,3 +405,120 @@ func TestBadReader(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
}
func TestScanWordsExcessiveWhiteSpace(t *testing.T) {
const word = "ipsum"
s := strings.Repeat(" ", 4*smallMaxTokenSize) + word
scanner := NewScanner(strings.NewReader(s))
scanner.MaxTokenSize(smallMaxTokenSize)
scanner.Split(ScanWords)
if !scanner.Scan() {
t.Fatalf("scan failed: %v", scanner.Err())
}
if token := scanner.Text(); token != word {
t.Fatalf("unexpected token: %v", token)
}
}
// Test that empty tokens, including at end of line or end of file, are found by the scanner.
// Issue 8672: Could miss final empty token.
func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
for i := 0; i < len(data); i++ {
if data[i] == ',' {
return i + 1, data[:i], nil
}
}
if !atEOF {
return 0, nil, nil
}
return 0, data, nil
}
func TestEmptyTokens(t *testing.T) {
s := NewScanner(strings.NewReader("1,2,3,"))
values := []string{"1", "2", "3", ""}
s.Split(commaSplit)
var i int
for i = 0; i < len(values); i++ {
if !s.Scan() {
break
}
if s.Text() != values[i] {
t.Errorf("%d: expected %q got %q", i, values[i], s.Text())
}
}
if i != len(values) {
t.Errorf("got %d fields, expected %d", i, len(values))
}
if err := s.Err(); err != nil {
t.Fatal(err)
}
}
func loopAtEOFSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
if len(data) > 0 {
return 1, data[:1], nil
}
return 0, data, nil
}
func TestDontLoopForever(t *testing.T) {
s := NewScanner(strings.NewReader("abc"))
s.Split(loopAtEOFSplit)
// Expect a panic
defer func() {
err := recover()
if err == nil {
t.Fatal("should have panicked")
}
if msg, ok := err.(string); !ok || !strings.Contains(msg, "empty tokens") {
panic(err)
}
}()
for count := 0; s.Scan(); count++ {
if count > 1000 {
t.Fatal("looping")
}
}
if s.Err() != nil {
t.Fatal("after scan:", s.Err())
}
}
func TestBlankLines(t *testing.T) {
s := NewScanner(strings.NewReader(strings.Repeat("\n", 1000)))
for count := 0; s.Scan(); count++ {
if count > 2000 {
t.Fatal("looping")
}
}
if s.Err() != nil {
t.Fatal("after scan:", s.Err())
}
}
type countdown int
func (c *countdown) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
if *c > 0 {
*c--
return 1, data[:1], nil
}
return 0, nil, nil
}
// Check that the looping-at-EOF check doesn't trigger for merely empty tokens.
func TestEmptyLinesOK(t *testing.T) {
c := countdown(10000)
s := NewScanner(strings.NewReader(strings.Repeat("\n", 10000)))
s.Split(c.split)
for s.Scan() {
}
if s.Err() != nil {
t.Fatal("after scan:", s.Err())
}
if c != 0 {
t.Fatalf("stopped with %d left to process", c)
}
}

View File

@ -267,6 +267,8 @@ func Fields(s []byte) [][]byte {
// It splits the slice s at each run of code points c satisfying f(c) and
// returns a slice of subslices of s. If all code points in s satisfy f(c), or
// len(s) == 0, an empty slice is returned.
// FieldsFunc makes no guarantees about the order in which it calls f(c).
// If f does not return consistent results for a given c, FieldsFunc may crash.
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false
@ -377,9 +379,10 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
// Repeat returns a new byte slice consisting of count copies of b.
func Repeat(b []byte, count int) []byte {
nb := make([]byte, len(b)*count)
bp := 0
for i := 0; i < count; i++ {
bp += copy(nb[bp:], b)
bp := copy(nb, b)
for bp < len(nb) {
copy(nb[bp:], nb[:bp])
bp *= 2
}
return nb
}
@ -604,6 +607,9 @@ func Runes(s []byte) []rune {
// Replace returns a copy of the slice s with the first n
// non-overlapping instances of old replaced by new.
// If old is empty, it matches at the beginning of the slice
// and after each UTF-8 sequence, yielding up to k+1 replacements
// for a k-rune slice.
// If n < 0, there is no limit on the number of replacements.
func Replace(s, old, new []byte, n int) []byte {
m := 0

View File

@ -1232,3 +1232,9 @@ func BenchmarkTrimSpace(b *testing.B) {
TrimSpace(s)
}
}
func BenchmarkRepeat(b *testing.B) {
for i := 0; i < b.N; i++ {
Repeat([]byte("-"), 80)
}
}

View File

@ -272,7 +272,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
case nil:
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
// These are ordered and grouped to match ../../go/ast/ast.go
case *ast.Field:
if len(n.Names) == 0 && context == "field" {
f.walk(&n.Type, "embed-type", visit)
@ -308,6 +308,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
if n.High != nil {
f.walk(&n.High, "expr", visit)
}
if n.Max != nil {
f.walk(&n.Max, "expr", visit)
}
case *ast.TypeAssertExpr:
f.walk(&n.X, "expr", visit)
f.walk(&n.Type, "type", visit)

View File

@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&x[0]).
the pointer to the first element explicitly: C.f(&C.x[0]).
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:

View File

@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name {
// Determine kinds for names we already know about,
// like #defines or 'struct foo', before bothering with gcc.
var names, needType []*Name
for _, n := range f.Name {
for _, key := range nameKeys(f.Name) {
n := f.Name[key]
// If we've already found this name as a #define
// and we can translate it as a constant value, do so.
if n.Define != "" {
@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name {
const (
notType = 1 << iota
notConst
notDeclared
)
for _, line := range strings.Split(stderr, "\n") {
if !strings.Contains(line, ": error:") {
@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name {
completed = true
case "not-declared":
error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
sniff[i] |= notDeclared
case "not-type":
sniff[i] |= notType
case "not-const":
@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name {
}
if !completed {
fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
}
for i, n := range names {
switch sniff[i] {
case 0:
default:
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
case notType:
n.Kind = "const"
@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name {
}
}
if nerrors > 0 {
// Check if compiling the preamble by itself causes any errors,
// because the messages we've printed out so far aren't helpful
// to users debugging preamble mistakes. See issue 8442.
preambleErrors := p.gccErrors([]byte(f.Preamble))
if len(preambleErrors) > 0 {
error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
}
fatalf("unresolved names")
}
@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) {
f.Name[fpName] = name
}
r.Name = name
expr = ast.NewIdent(name.Mangle)
// Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
// function is defined in out.go and simply returns its argument. See
// issue 7757.
expr = &ast.CallExpr{
Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
Args: []ast.Expr{ast.NewIdent(name.Mangle)},
}
} else if r.Name.Kind == "type" {
// Okay - might be new(T)
expr = r.Name.Type.Go
@ -928,9 +944,8 @@ type typeConv struct {
// Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type
// Fields to be processed by godefsField after completing pointers.
todoFlds [][]*ast.Field
// Keys of ptrs in insertion order (deterministic worklist)
ptrKeys []dwarf.Type
// Predeclared types.
bool ast.Expr
@ -940,9 +955,9 @@ type typeConv struct {
float32, float64 ast.Expr
complex64, complex128 ast.Expr
void ast.Expr
unsafePointer ast.Expr
string ast.Expr
goVoid ast.Expr // _Ctype_void, denotes C's void
goVoidPtr ast.Expr // unsafe.Pointer or *byte
ptrSize int64
intSize int64
@ -972,10 +987,17 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
c.float64 = c.Ident("float64")
c.complex64 = c.Ident("complex64")
c.complex128 = c.Ident("complex128")
c.unsafePointer = c.Ident("unsafe.Pointer")
c.void = c.Ident("void")
c.string = c.Ident("string")
c.goVoid = c.Ident("_Ctype_void")
// Normally cgo translates void* to unsafe.Pointer,
// but for historical reasons -cdefs and -godefs use *byte instead.
if *cdefs || *godefs {
c.goVoidPtr = &ast.StarExpr{X: c.byte}
} else {
c.goVoidPtr = c.Ident("unsafe.Pointer")
}
}
// base strips away qualifiers and typedefs to get the underlying type
@ -1037,29 +1059,22 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
}
// FinishType completes any outstanding type mapping work.
// In particular, it resolves incomplete pointer types and also runs
// godefsFields on any new struct types.
// In particular, it resolves incomplete pointer types.
func (c *typeConv) FinishType(pos token.Pos) {
// Completing one pointer type might produce more to complete.
// Keep looping until they're all done.
for len(c.ptrs) > 0 {
for dtype := range c.ptrs {
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
for _, ptr := range c.ptrs[dtype] {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
delete(c.ptrs, dtype)
}
}
for len(c.ptrKeys) > 0 {
dtype := c.ptrKeys[0]
c.ptrKeys = c.ptrKeys[1:]
// Now that pointer types are completed, we can invoke godefsFields
// to rewrite struct definitions.
for _, fld := range c.todoFlds {
godefsFields(fld)
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
for _, ptr := range c.ptrs[dtype] {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
c.ptrs[dtype] = nil // retain the map key
}
c.todoFlds = nil
}
// Type returns a *Type with the same memory layout as
@ -1072,12 +1087,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t
}
// clang won't generate DW_AT_byte_size for pointer types,
// so we have to fix it here.
if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
dt.ByteSize = c.ptrSize
}
t := new(Type)
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
t.Align = -1
@ -1101,12 +1110,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = c.Opaque(t.Size)
break
}
count := dt.Count
if count == -1 {
// Indicates flexible array member, which Go doesn't support.
// Translate to zero-length array instead.
count = 0
}
sub := c.Type(dt.Type, pos)
t.Align = sub.Align
t.Go = &ast.ArrayType{
Len: c.intExpr(dt.Count),
Len: c.intExpr(count),
Elt: sub.Go,
}
// Recalculate t.Size now that we know sub.Size.
t.Size = count * sub.Size
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
case *dwarf.BoolType:
@ -1207,11 +1224,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
case *dwarf.PtrType:
// Clang doesn't emit DW_AT_byte_size for pointer types.
if t.Size != c.ptrSize && t.Size != -1 {
fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
}
t.Size = c.ptrSize
t.Align = c.ptrSize
// Translate void* as unsafe.Pointer
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
t.Go = c.unsafePointer
t.Go = c.goVoidPtr
t.C.Set("void*")
break
}
@ -1219,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// Placeholder initialization; completed in FinishType.
t.Go = &ast.StarExpr{}
t.C.Set("<incomplete>*")
if _, ok := c.ptrs[dt.Type]; !ok {
c.ptrKeys = append(c.ptrKeys, dt.Type)
}
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
case *dwarf.QualType:
@ -1379,34 +1403,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
}
if t.Size <= 0 {
// Clang does not record the size of a pointer in its DWARF entry,
// so if dtype is an array, the call to dtype.Size at the top of the function
// computed the size as the array length * 0 = 0.
// The type switch called Type (this function) recursively on the pointer
// entry, and the code near the top of the function updated the size to
// be correct, so calling dtype.Size again will produce the correct value.
t.Size = dtype.Size()
if t.Size < 0 {
// Unsized types are [0]byte, unless they're typedefs of other types
// or structs with tags.
// if so, use the name we've already defined.
t.Size = 0
switch dt := dtype.(type) {
case *dwarf.TypedefType:
// ok
case *dwarf.StructType:
if dt.StructName != "" {
break
}
t.Go = c.Opaque(0)
default:
t.Go = c.Opaque(0)
if t.Size < 0 {
// Unsized types are [0]byte, unless they're typedefs of other types
// or structs with tags.
// if so, use the name we've already defined.
t.Size = 0
switch dt := dtype.(type) {
case *dwarf.TypedefType:
// ok
case *dwarf.StructType:
if dt.StructName != "" {
break
}
if t.C.Empty() {
t.C.Set("void")
}
return t
t.Go = c.Opaque(0)
default:
t.Go = c.Opaque(0)
}
if t.C.Empty() {
t.C.Set("void")
}
}
@ -1538,6 +1552,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
// Struct conversion: return Go and (6g) C syntax for type.
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
// Minimum alignment for a struct is 1 byte.
align = 1
var buf bytes.Buffer
buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
@ -1579,7 +1596,27 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
fld = c.pad(fld, f.ByteOffset-off)
off = f.ByteOffset
}
t := c.Type(f.Type, pos)
name := f.Name
ft := f.Type
// In godefs or cdefs mode, if this field is a C11
// anonymous union then treat the first field in the
// union as the field in the struct. This handles
// cases like the glibc <sys/resource.h> file; see
// issue 6677.
if *godefs || *cdefs {
if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
name = st.Field[0].Name
ident[name] = name
ft = st.Field[0].Type
}
}
// TODO: Handle fields that are anonymous structs by
// promoting the fields of the inner struct.
t := c.Type(ft, pos)
tgo := t.Go
size := t.Size
talign := t.Align
@ -1598,17 +1635,18 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
talign = size
}
if talign > 0 && f.ByteOffset%talign != 0 {
if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
// Drop misaligned fields, the same way we drop integer bit fields.
// The goal is to make available what can be made available.
// Otherwise one bad and unneeded field in an otherwise okay struct
// makes the whole program not compile. Much of the time these
// structs are in system headers that cannot be corrected.
// Exception: In -cdefs mode, we use #pragma pack, so misaligned
// fields should still work.
continue
}
n := len(fld)
fld = fld[0 : n+1]
name := f.Name
if name == "" {
name = fmt.Sprintf("anon%d", anon)
anon++
@ -1635,7 +1673,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
csyntax = buf.String()
if *godefs || *cdefs {
c.todoFlds = append(c.todoFlds, fld)
godefsFields(fld)
}
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
return
@ -1673,19 +1711,6 @@ func godefsFields(fld []*ast.Field) {
n.Name = upper(n.Name)
}
}
p := &f.Type
t := *p
if star, ok := t.(*ast.StarExpr); ok {
star = &ast.StarExpr{X: star.X}
*p = star
p = &star.X
t = *p
}
if id, ok := t.(*ast.Ident); ok {
if id.Name == "unsafe.Pointer" {
*p = ast.NewIdent("*byte")
}
}
}
}

View File

@ -44,6 +44,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo {
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
} else {
// If we're not importing runtime/cgo, we *are* runtime/cgo,
// which provides crosscall2. We just need a prototype.
@ -58,16 +59,14 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
if *importSyscall {
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
}
if !*gccgo && *importRuntimeCgo {
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
}
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
if *importSyscall {
fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
}
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
@ -87,9 +86,10 @@ func (p *Package) writeDefs() {
}
if *gccgo {
fmt.Fprintf(fc, p.cPrologGccgo())
fmt.Fprint(fc, p.cPrologGccgo())
} else {
fmt.Fprintf(fc, cProlog)
fmt.Fprint(fc, cProlog)
fmt.Fprint(fgo2, goProlog)
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
@ -130,6 +130,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
} else {
fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n")
fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
}
fmt.Fprintf(fc, "\n")
@ -296,10 +297,6 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
if n.AddError {
fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n")
off += 2 * p.PtrSize
}
if off == 0 {
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
}
@ -334,19 +331,18 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
}
// Builtins defined in the C prolog.
inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc"
inProlog := builtinDefs[name] != ""
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
paramnames := []string(nil)
for i, param := range d.Type.Params.List {
paramName := fmt.Sprintf("p%d", i)
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
paramnames = append(paramnames, paramName)
}
if *gccgo {
// Gccgo style hooks.
fmt.Fprint(fgo2, "\n")
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
paramnames := []string(nil)
for i, param := range d.Type.Params.List {
paramName := fmt.Sprintf("p%d", i)
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
paramnames = append(paramnames, paramName)
}
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
if !inProlog {
@ -383,7 +379,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
fmt.Fprint(fgo2, "}\n")
// declare the C function.
fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle)
fmt.Fprintf(fgo2, "//extern %s\n", cname)
d.Name = ast.NewIdent(cname)
if n.AddError {
l := d.Type.Results.List
@ -394,61 +390,50 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
return
}
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, "\n")
if inProlog {
fmt.Fprint(fgo2, builtinDefs[name])
return
}
var argSize int64
_, argSize = p.structType(n)
// C wrapper calls into gcc, passing a pointer to the argument frame.
fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
fmt.Fprintf(fc, "\n")
fmt.Fprintf(fc, "void\n")
if argSize == 0 {
argSize++
fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
fmt.Fprintf(fc, "void %s(void*);\n", cname)
fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
nret := 0
if !void {
d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
nret = 1
}
// TODO(rsc): The struct here should declare pointers only where
// there are pointers in the actual argument frame.
// This is a workaround for golang.org/issue/6397.
fmt.Fprintf(fc, "·%s(struct{", n.Mangle)
if n := argSize / p.PtrSize; n > 0 {
fmt.Fprintf(fc, "void *y[%d];", n)
}
if n := argSize % p.PtrSize; n > 0 {
fmt.Fprintf(fc, "uint8 x[%d];", n)
}
fmt.Fprintf(fc, "}p)\n")
fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
if n.AddError {
// gcc leaves errno in first word of interface at end of p.
// check whether it is zero; if so, turn interface into nil.
// if not, turn interface into errno.
// Go init function initializes ·_Cerrno with an os.Errno
// for us to copy.
fmt.Fprintln(fc, ` {
int32 e;
void **v;
v = (void**)(&p+1) - 2; /* v = final two void* of p */
e = *(int32*)v;
v[0] = (void*)0xdeadbeef;
v[1] = (void*)0xdeadbeef;
if(e == 0) {
/* nil interface */
v[0] = 0;
v[1] = 0;
} else {
·_Cerrno(v, e); /* fill in v as error for errno e */
}
}`)
d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
}
fmt.Fprintf(fc, "}\n")
fmt.Fprintf(fc, "\n")
fmt.Fprint(fgo2, "\n")
fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
// NOTE: Using uintptr to hide from escape analysis.
arg := "0"
if len(paramnames) > 0 {
arg = "uintptr(unsafe.Pointer(&p0))"
} else if !void {
arg = "uintptr(unsafe.Pointer(&r1))"
}
prefix := ""
if n.AddError {
prefix = "errno := "
}
fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
if n.AddError {
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
}
fmt.Fprintf(fgo2, "\treturn\n")
fmt.Fprintf(fgo2, "}\n")
}
// writeOutput creates stubs for a specific source file to be compiled by 6g
@ -521,7 +506,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
fmt.Fprintf(fgcc, "void\n")
if n.AddError {
fmt.Fprintf(fgcc, "int\n")
} else {
fmt.Fprintf(fgcc, "void\n")
}
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\n")
if n.AddError {
@ -531,9 +520,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements.
fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
if n.FuncType.Result != nil {
// Save the stack top for use below.
fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
}
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "a->r = ")
fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
}
@ -556,8 +549,15 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
if n.FuncType.Result != nil {
// The cgo call may have caused a stack copy (via a callback).
// Adjust the return value pointer appropriately.
fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
// Save the return value.
fmt.Fprintf(fgcc, "\ta->r = r;\n")
}
if n.AddError {
fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
fmt.Fprintf(fgcc, "\treturn errno;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
@ -1016,7 +1016,7 @@ func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
fn(i, r.Type)
i++
} else {
for _ = range r.Names {
for range r.Names {
fn(i, r.Type)
i++
}
@ -1143,21 +1143,17 @@ __cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
extern char* _cgo_topofstack(void);
#include <errno.h>
#include <string.h>
`
const builtinProlog = `
#include <sys/types.h> /* for size_t below */
#include <stddef.h> /* for ptrdiff_t and size_t below */
/* Define intgo when compiling with GCC. */
#ifdef __PTRDIFF_TYPE__
typedef __PTRDIFF_TYPE__ intgo;
#elif defined(_LP64)
typedef long long intgo;
#else
typedef int intgo;
#endif
typedef ptrdiff_t intgo;
typedef struct { char *p; intgo n; } _GoString_;
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
@ -1171,47 +1167,86 @@ void *_CMalloc(size_t);
const cProlog = `
#include "runtime.h"
#include "cgocall.h"
#include "textflag.h"
#pragma dataflag NOPTR
static void *cgocall_errno = runtime·cgocall_errno;
#pragma dataflag NOPTR
void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
#pragma dataflag NOPTR
static void *runtime_gostring = runtime·gostring;
#pragma dataflag NOPTR
void *·_cgo_runtime_gostring = &runtime_gostring;
#pragma dataflag NOPTR
static void *runtime_gostringn = runtime·gostringn;
#pragma dataflag NOPTR
void *·_cgo_runtime_gostringn = &runtime_gostringn;
#pragma dataflag NOPTR
static void *runtime_gobytes = runtime·gobytes;
#pragma dataflag NOPTR
void *·_cgo_runtime_gobytes = &runtime_gobytes;
#pragma dataflag NOPTR
static void *runtime_cmalloc = runtime·cmalloc;
#pragma dataflag NOPTR
void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
void ·_Cerrno(void*, int32);
`
void
·_Cfunc_GoString(int8 *p, String s)
{
s = runtime·gostring((byte*)p);
FLUSH(&s);
}
const goProlog = `
var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
`
void
·_Cfunc_GoStringN(int8 *p, int32 l, String s)
{
s = runtime·gostringn((byte*)p, l);
FLUSH(&s);
}
void
·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
{
s = runtime·gobytes((byte*)p, l);
FLUSH(&s);
}
void
·_Cfunc_CString(String s, int8 *p)
{
p = runtime·cmalloc(s.len+1);
runtime·memmove((byte*)p, s.str, s.len);
p[s.len] = 0;
FLUSH(&p);
}
void
·_Cfunc__CMalloc(uintptr n, int8 *p)
{
p = runtime·cmalloc(n);
FLUSH(&p);
const goStringDef = `
var _cgo_runtime_gostring func(*_Ctype_char) string
func _Cfunc_GoString(p *_Ctype_char) string {
return _cgo_runtime_gostring(p)
}
`
const goStringNDef = `
var _cgo_runtime_gostringn func(*_Ctype_char, int) string
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
return _cgo_runtime_gostringn(p, int(l))
}
`
const goBytesDef = `
var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
return _cgo_runtime_gobytes(p, int(l))
}
`
const cStringDef = `
func _Cfunc_CString(s string) *_Ctype_char {
p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
pp := (*[1<<30]byte)(p)
copy(pp[:], s)
pp[len(s)] = 0
return (*_Ctype_char)(p)
}
`
const cMallocDef = `
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
return _cgo_runtime_cmalloc(uintptr(n))
}
`
var builtinDefs = map[string]string{
"GoString": goStringDef,
"GoStringN": goStringNDef,
"GoBytes": goBytesDef,
"CString": cStringDef,
"_CMalloc": cMallocDef,
}
func (p *Package) cPrologGccgo() string {
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
}

View File

@ -57,6 +57,7 @@ and test commands:
-a
force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n
print the commands but do not run them.
-p n
@ -64,7 +65,7 @@ and test commands:
The default is the number of CPUs available.
-race
enable data race detection.
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-v
print the names of packages as they are compiled.
-work
@ -291,23 +292,26 @@ func runBuild(cmd *Command, args []string) {
}
}
depMode := modeBuild
if buildI {
depMode = modeInstall
}
if *buildO != "" {
if len(pkgs) > 1 {
fatalf("go build: cannot use -o with multiple packages")
} else if len(pkgs) == 0 {
fatalf("no packages to build")
}
p := pkgs[0]
p.target = "" // must build - not up to date
a := b.action(modeInstall, modeBuild, p)
a := b.action(modeInstall, depMode, p)
a.target = *buildO
b.do(a)
return
}
a := &action{}
depMode := modeBuild
if buildI {
depMode = modeInstall
}
for _, p := range packages(args) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
}
@ -438,12 +442,11 @@ const (
)
var (
goroot = filepath.Clean(runtime.GOROOT())
gobin = os.Getenv("GOBIN")
gorootBin = filepath.Join(goroot, "bin")
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
goroot = filepath.Clean(runtime.GOROOT())
gobin = os.Getenv("GOBIN")
gorootBin = filepath.Join(goroot, "bin")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
)
func (b *builder) init() {
@ -510,8 +513,13 @@ func goFilesPackage(gofiles []string) *Package {
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
if !filepath.IsAbs(dir) {
dir = filepath.Join(cwd, dir)
var err error
if dir == "" {
dir = cwd
}
dir, err = filepath.Abs(dir)
if err != nil {
fatalf("%s", err)
}
bp, err := ctxt.ImportDir(dir, 0)
@ -833,12 +841,17 @@ func (b *builder) build(a *action) (err error) {
}
}
var gofiles, cfiles, sfiles, objects, cgoObjects []string
var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
gofiles = append(gofiles, a.p.GoFiles...)
cfiles = append(cfiles, a.p.CFiles...)
sfiles = append(sfiles, a.p.SFiles...)
if a.p.usesCgo() || a.p.usesSwig() {
if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
return
}
}
// Run cgo.
if a.p.usesCgo() {
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
@ -869,7 +882,7 @@ func (b *builder) build(a *action) (err error) {
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
@ -882,9 +895,18 @@ func (b *builder) build(a *action) (err error) {
// In a package using SWIG, any .c or .s files are
// compiled with gcc.
gccfiles := append(cfiles, sfiles...)
cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
cfiles = nil
sfiles = nil
outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
// Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config).
if a.p.usesCgo() {
cxxfiles = nil
gccfiles = nil
mfiles = nil
}
outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles)
if err != nil {
return err
}
@ -893,7 +915,7 @@ func (b *builder) build(a *action) (err error) {
}
if len(gofiles) == 0 {
return &build.NoGoError{a.p.Dir}
return &build.NoGoError{Dir: a.p.Dir}
}
// If we're doing coverage, preprocess the .go files and put them in the work directory
@ -1028,6 +1050,34 @@ func (b *builder) build(a *action) (err error) {
return nil
}
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
var out []byte
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
}
if len(out) > 0 {
cflags = strings.Fields(string(out))
}
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
}
if len(out) > 0 {
ldflags = strings.Fields(string(out))
}
}
return
}
// install is the action for installing a single package or executable.
func (b *builder) install(a *action) (err error) {
defer func() {
@ -1263,7 +1313,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
// the source directory for the package that has failed to build.
// showOutput rewrites mentions of dir with a relative path to dir
// when the relative path is shorter. This is usually more pleasant.
// For example, if fmt doesn't compile and we are in src/pkg/html,
// For example, if fmt doesn't compile and we are in src/html,
// the output is
//
// $ go build
@ -1275,7 +1325,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
//
// $ go build
// # fmt
// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf
// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf
// $
//
// showOutput also replaces references to the work directory with $WORK.
@ -1435,6 +1485,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
continue
}
// err can be something like 'exit status 1'.
// Add information about what program was running.
// Note that if buf.Bytes() is non-empty, the caller usually
// shows buf.Bytes() and does not print err at all, so the
// prefix here does not make most output any more verbose.
if err != nil {
err = errors.New(cmdline[0] + ": " + err.Error())
}
return buf.Bytes(), err
}
}
@ -1597,7 +1655,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "os", "runtime/pprof", "sync", "time":
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
extFiles++
}
}
@ -1621,8 +1679,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
sfile = mkAbs(p.Dir, sfile)
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
@ -1716,7 +1776,7 @@ func packInternal(b *builder, afile string, ofiles []string) error {
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions)
cxx := false
cxx := len(p.CXXFiles) > 0
for _, a := range allactions {
if a.p != nil && len(a.p.CXXFiles) > 0 {
cxx = true
@ -1776,7 +1836,15 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
warn := []string{"-w"}
if p.usesSwig() {
// When using SWIG, this compiler is only used to
// compile the C files generated by SWIG.
// We don't want warnings.
// See issue 9065 for details.
warn = nil
}
args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
return b.run(p.Dir, p.ImportPath, nil, args)
}
@ -1802,7 +1870,7 @@ func (gccgoToolchain) linker() string {
}
func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := p.Name + ".o"
out := "_go_.o"
ofile = obj + out
gcargs := []string{"-g"}
gcargs = append(gcargs, b.gccArchArgs()...)
@ -1828,6 +1896,7 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
defs = append(defs, b.gccArchArgs()...)
return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-c", "-I", obj, "-o", ofile, defs, sfile)
}
@ -1854,8 +1923,8 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
ldflags := b.gccArchArgs()
cgoldflags := []string{}
usesCgo := false
cxx := false
objc := false
cxx := len(p.CXXFiles) > 0
objc := len(p.MFiles) > 0
// Prefer the output of an install action to the output of a build action,
// because the install action will delete the output of the build action.
@ -1917,8 +1986,7 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
// TODO: Support using clang here (during gccgo build)?
return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g",
return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
}
@ -1969,9 +2037,9 @@ func (b *builder) libgcc(p *Package) (string, error) {
return "$LIBGCC", nil
}
// clang might not be able to find libgcc, and in that case,
// The compiler might not be able to find libgcc, and in that case,
// it will simply return "libgcc.a", which is of no use to us.
if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) {
if !filepath.IsAbs(string(f)) {
return "", nil
}
@ -2109,36 +2177,16 @@ var (
cgoLibGccFileOnce sync.Once
)
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
// If we are compiling Objective-C code, then we need to link against libobjc
if len(mfiles) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
}
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...)
}
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...)
}
}
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
@ -2215,6 +2263,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
strings.HasSuffix(f, ".so"),
strings.HasSuffix(f, ".dll"):
continue
// Remove any -fsanitize=foo flags.
// Otherwise the compiler driver thinks that we are doing final link
// and links sanitizer runtime into the object file. But we are not doing
// the final link, we will link the resulting object file again. And
// so the program ends up with two copies of sanitizer runtime.
// See issue 8788 for details.
case strings.HasPrefix(f, "-fsanitize="):
continue
default:
bareLDFLAGS = append(bareLDFLAGS, f)
}
@ -2281,13 +2337,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
linkobj = append(linkobj, p.SysoFiles...)
dynobj := obj + "_cgo_.o"
if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
pie := goarch == "arm" && (goos == "linux" || goos == "android")
if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
}
if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
return nil, nil, err
}
if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
if pie { // but we don't need -pie for normal cgo programs
cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
}
@ -2321,7 +2378,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
nonGccObjs = append(nonGccObjs, f)
}
}
if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), gccObjs); err != nil {
ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
// Some systems, such as Ubuntu, always add --build-id to
// every link, but we don't want a build ID since we are
// producing an object file. On some of those system a plain
// -r (not -Wl,-r) will turn off --build-id, but clang 3.0
// doesn't support a plain -r. I don't know how to turn off
// --build-id when using clang other than passing a trailing
// --build-id=none. So that is what we do, but only on
// systems likely to support it, which is to say, systems that
// normally use gold or the GNU linker.
switch goos {
case "android", "dragonfly", "linux", "netbsd":
ldflags = append(ldflags, "-Wl,--build-id=none")
}
if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
return nil, nil, err
}
@ -2336,7 +2409,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
// Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking.
func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
@ -2377,7 +2450,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri
}
for _, f := range p.SwigFiles {
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize)
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
if err != nil {
return nil, nil, err
}
@ -2392,7 +2465,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri
}
}
for _, f := range p.SwigCXXFiles {
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize)
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
if err != nil {
return nil, nil, err
}
@ -2471,13 +2544,13 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
}
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
} else {
cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
}
n := 5 // length of ".swig"
@ -2503,6 +2576,13 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
"-o", obj + gccBase + gccExt,
"-outdir", obj,
}
for _, f := range cflags {
if len(f) > 3 && f[:2] == "-I" {
args = append(args, f)
}
}
if gccgo {
args = append(args, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
@ -2575,8 +2655,8 @@ func raceInit() {
if !buildRace {
return
}
if goarch != "amd64" || goos != "linux" && goos != "darwin" && goos != "windows" {
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
os.Exit(2)
}
buildGcflags = append(buildGcflags, "-race")

View File

@ -19,6 +19,7 @@ The commands are:
env print Go environment information
fix run go tool fix on packages
fmt run gofmt on package sources
generate generate Go files by processing source
get download and install packages and dependencies
install compile and install packages and dependencies
list list packages
@ -75,6 +76,7 @@ and test commands:
-a
force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n
print the commands but do not run them.
-p n
@ -82,7 +84,7 @@ and test commands:
The default is the number of CPUs available.
-race
enable data race detection.
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-v
print the names of packages as they are compiled.
-work
@ -219,11 +221,110 @@ To run gofmt with specific options, run gofmt itself.
See also: go fix, go vet.
Generate Go files by processing source
Usage:
go generate [-run regexp] [file.go... | packages]
Generate runs commands described by directives within existing
files. Those commands can run any process but the intent is to
create or update Go source files, for instance by running yacc.
Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly.
Go generate scans the file for directives, which are lines of
the form,
//go:generate command argument...
(note: no leading spaces and no space in "//go") where command
is the generator to be run, corresponding to an executable file
that can be run locally. It must either be in the shell path
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.
Note that go generate does not parse the file, so lines that look
like directives in comments or multiline strings will be treated
as directives.
The arguments to the directive are space-separated tokens or
double-quoted strings passed to the generator as individual
arguments when it is run.
Quoted strings use Go syntax and are evaluated before execution; a
quoted string appears as a single argument to the generator.
Go generate sets several variables when it runs the generator:
$GOARCH
The execution architecture (arm, amd64, etc.)
$GOOS
The execution operating system (linux, windows, etc.)
$GOFILE
The base name of the file.
$GOPACKAGE
The name of the package of the file containing the directive.
Other than variable substitution and quoted-string evaluation, no
special processing such as "globbing" is performed on the command
line.
As a last step before running the command, any invocations of any
environment variables with alphanumeric names, such as $GOFILE or
$HOME, are expanded throughout the command line. The syntax for
variable expansion is $NAME on all operating systems. Due to the
order of evaluation, variables are expanded even inside quoted
strings. If the variable NAME is not set, $NAME expands to the
empty string.
A directive of the form,
//go:generate -command xxx args...
specifies, for the remainder of this source file only, that the
string xxx represents the command identified by the arguments. This
can be used to create aliases or to handle multiword generators.
For example,
//go:generate -command yacc go tool yacc
specifies that the command "yacc" represents the generator
"go tool yacc".
Generate processes packages in the order given on the command line,
one at a time. If the command line lists .go files, they are treated
as a single package. Within a package, generate processes the
source files in a package in file name order, one at a time. Within
a source file, generate runs generators in the order they appear
in the file, one at a time.
If any generator returns an error exit status, "go generate" skips
all further processing for that package.
The generator is run in the package's source directory.
Go generate accepts one specific flag:
-run=""
if non-empty, specifies a regular expression to
select directives whose command matches the expression.
It also accepts the standard build flags -v, -n, and -x.
The -v flag prints the names of packages and files as they are
processed.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
For more about specifying packages, see 'go help packages'.
Download and install packages and dependencies
Usage:
go get [-d] [-fix] [-t] [-u] [build flags] [packages]
go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
Get downloads and installs the packages named by the import paths,
along with their dependencies.
@ -231,6 +332,11 @@ along with their dependencies.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
The -f flag, valid only when -u is set, forces get -u not to verify that
each package has been checked out from the source control repository
implied by its import path. This can be useful if the source is a local fork
of the original.
The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.
@ -291,28 +397,29 @@ syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
@ -431,16 +538,23 @@ non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
(Where pkg is the last element of the package's import path.)
-c
Compile the test binary to pkg.test but do not run it
(where pkg is the last element of the package's import path).
The file name can be changed with the -o flag.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
-i
Install packages that are dependencies of the test.
Do not run the test.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
-o file
Compile the test binary to the named file.
The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
@ -488,7 +602,7 @@ Usage:
Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.
@ -681,6 +795,11 @@ A few common code hosting sites have special syntax:
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
IBM DevOps Services (Git)
import "hub.jazz.net/git/user/project"
import "hub.jazz.net/git/user/project/sub/directory"
For code hosted on other servers, import paths may either be qualified
with the version control type, or the go tool can dynamically fetch
the import path over https/http and discover where the code resides
@ -756,7 +875,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
Run 'go help get' for more.
Import path checking
When the custom import path feature described above redirects to a
known code hosting site, each of the resulting packages has two possible
import paths, using the custom domain or the known hosting site.
A package statement is said to have an "import comment" if it is immediately
followed (before the next newline) by a comment of one of these two forms:
package math // import "path"
package math /* import "path" * /
The go command will refuse to install a package with an import comment
unless it is being referred to by that import path. In this way, import comments
let package authors make sure the custom import path is used and not a
direct path to the underlying code hosting site.
See https://golang.org/s/go14customimport for details.
Description of package lists
@ -812,7 +950,8 @@ single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
File names that begin with "." or "_" are ignored by the go tool.
Directory and file names that begin with "." or "_" are ignored
by the go tool, as are directories named "testdata".
Description of testing flags
@ -844,6 +983,7 @@ control the execution of any test:
-blockprofile block.out
Write a goroutine blocking profile to the specified file
when all tests are complete.
Writes test binary as -c would.
-blockprofilerate n
Control the detail provided in goroutine blocking profiles by
@ -875,8 +1015,7 @@ control the execution of any test:
Sets -cover.
-coverprofile cover.out
Write a coverage profile to the specified file after all tests
have passed.
Write a coverage profile to the file after all tests have passed.
Sets -cover.
-cpu 1,2,4
@ -886,10 +1025,11 @@ control the execution of any test:
-cpuprofile cpu.out
Write a CPU profile to the specified file before exiting.
Writes test binary as -c would.
-memprofile mem.out
Write a memory profile to the specified file after all tests
have passed.
Write a memory profile to the file after all tests have passed.
Writes test binary as -c would.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting

398
libgo/go/cmd/go/generate.go Normal file
View File

@ -0,0 +1,398 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
var cmdGenerate = &Command{
Run: runGenerate,
UsageLine: "generate [-run regexp] [file.go... | packages]",
Short: "generate Go files by processing source",
Long: `
Generate runs commands described by directives within existing
files. Those commands can run any process but the intent is to
create or update Go source files, for instance by running yacc.
Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly.
Go generate scans the file for directives, which are lines of
the form,
//go:generate command argument...
(note: no leading spaces and no space in "//go") where command
is the generator to be run, corresponding to an executable file
that can be run locally. It must either be in the shell path
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.
Note that go generate does not parse the file, so lines that look
like directives in comments or multiline strings will be treated
as directives.
The arguments to the directive are space-separated tokens or
double-quoted strings passed to the generator as individual
arguments when it is run.
Quoted strings use Go syntax and are evaluated before execution; a
quoted string appears as a single argument to the generator.
Go generate sets several variables when it runs the generator:
$GOARCH
The execution architecture (arm, amd64, etc.)
$GOOS
The execution operating system (linux, windows, etc.)
$GOFILE
The base name of the file.
$GOPACKAGE
The name of the package of the file containing the directive.
Other than variable substitution and quoted-string evaluation, no
special processing such as "globbing" is performed on the command
line.
As a last step before running the command, any invocations of any
environment variables with alphanumeric names, such as $GOFILE or
$HOME, are expanded throughout the command line. The syntax for
variable expansion is $NAME on all operating systems. Due to the
order of evaluation, variables are expanded even inside quoted
strings. If the variable NAME is not set, $NAME expands to the
empty string.
A directive of the form,
//go:generate -command xxx args...
specifies, for the remainder of this source file only, that the
string xxx represents the command identified by the arguments. This
can be used to create aliases or to handle multiword generators.
For example,
//go:generate -command yacc go tool yacc
specifies that the command "yacc" represents the generator
"go tool yacc".
Generate processes packages in the order given on the command line,
one at a time. If the command line lists .go files, they are treated
as a single package. Within a package, generate processes the
source files in a package in file name order, one at a time. Within
a source file, generate runs generators in the order they appear
in the file, one at a time.
If any generator returns an error exit status, "go generate" skips
all further processing for that package.
The generator is run in the package's source directory.
Go generate accepts one specific flag:
-run=""
if non-empty, specifies a regular expression to
select directives whose command matches the expression.
It also accepts the standard build flags -v, -n, and -x.
The -v flag prints the names of packages and files as they are
processed.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
For more about specifying packages, see 'go help packages'.
`,
}
var generateRunFlag string // generate -run flag
func init() {
addBuildFlags(cmdGenerate)
cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
}
func runGenerate(cmd *Command, args []string) {
// Even if the arguments are .go files, this loop suffices.
for _, pkg := range packages(args) {
for _, file := range pkg.gofiles {
if !generate(pkg.Name, file) {
break
}
}
}
}
// generate runs the generation directives for a single file.
func generate(pkg, absFile string) bool {
fd, err := os.Open(absFile)
if err != nil {
log.Fatalf("generate: %s", err)
}
defer fd.Close()
g := &Generator{
r: fd,
path: absFile,
pkg: pkg,
commands: make(map[string][]string),
}
return g.run()
}
// A Generator represents the state of a single Go source file
// being scanned for generator commands.
type Generator struct {
r io.Reader
path string // full rooted path name.
dir string // full rooted directory of file.
file string // base name of file.
pkg string
commands map[string][]string
lineNum int
}
// run runs the generators in the current file.
func (g *Generator) run() (ok bool) {
// Processing below here calls g.errorf on failure, which does panic(stop).
// If we encounter an error, we abort the package.
defer func() {
e := recover()
if e != nil {
ok = false
if e != stop {
panic(e)
}
setExitStatus(1)
}
}()
g.dir, g.file = filepath.Split(g.path)
g.dir = filepath.Clean(g.dir) // No final separator please.
if buildV {
fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
}
// Scan for lines that start "//go:generate".
// Can't use bufio.Scanner because it can't handle long lines,
// which are likely to appear when using generate.
input := bufio.NewReader(g.r)
var err error
// One line per loop.
for {
g.lineNum++ // 1-indexed.
var buf []byte
buf, err = input.ReadSlice('\n')
if err == bufio.ErrBufferFull {
// Line too long - consume and ignore.
if isGoGenerate(buf) {
g.errorf("directive too long")
}
for err == bufio.ErrBufferFull {
_, err = input.ReadSlice('\n')
}
if err != nil {
break
}
continue
}
if err != nil {
// Check for marker at EOF without final \n.
if err == io.EOF && isGoGenerate(buf) {
err = io.ErrUnexpectedEOF
}
break
}
if !isGoGenerate(buf) {
continue
}
words := g.split(string(buf))
if len(words) == 0 {
g.errorf("no arguments to directive")
}
if words[0] == "-command" {
g.setShorthand(words)
continue
}
// Run the command line.
if buildN || buildX {
fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
}
if buildN {
continue
}
g.exec(words)
}
if err != nil && err != io.EOF {
g.errorf("error reading %s: %s", shortPath(g.path), err)
}
return true
}
func isGoGenerate(buf []byte) bool {
return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
}
// split breaks the line into words, evaluating quoted
// strings and evaluating environment variables.
// The initial //go:generate element is present in line.
func (g *Generator) split(line string) []string {
// Parse line, obeying quoted strings.
var words []string
line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
// One (possibly quoted) word per iteration.
Words:
for {
line = strings.TrimLeft(line, " \t")
if len(line) == 0 {
break
}
if line[0] == '"' {
for i := 1; i < len(line); i++ {
c := line[i] // Only looking for ASCII so this is OK.
switch c {
case '\\':
if i+1 == len(line) {
g.errorf("bad backslash")
}
i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
case '"':
word, err := strconv.Unquote(line[0 : i+1])
if err != nil {
g.errorf("bad quoted string")
}
words = append(words, word)
line = line[i+1:]
// Check the next character is space or end of line.
if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
g.errorf("expect space after quoted argument")
}
continue Words
}
}
g.errorf("mismatched quoted string")
}
i := strings.IndexAny(line, " \t")
if i < 0 {
i = len(line)
}
words = append(words, line[0:i])
line = line[i:]
}
// Substitute command if required.
if len(words) > 0 && g.commands[words[0]] != nil {
// Replace 0th word by command substitution.
words = append(g.commands[words[0]], words[1:]...)
}
// Substitute environment variables.
for i, word := range words {
words[i] = g.expandEnv(word)
}
return words
}
var stop = fmt.Errorf("error in generation")
// errorf logs an error message prefixed with the file and line number.
// It then exits the program (with exit status 1) because generation stops
// at the first error.
func (g *Generator) errorf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
fmt.Sprintf(format, args...))
panic(stop)
}
// expandEnv expands any $XXX invocations in word.
func (g *Generator) expandEnv(word string) string {
if !strings.ContainsRune(word, '$') {
return word
}
var buf bytes.Buffer
var w int
var r rune
for i := 0; i < len(word); i += w {
r, w = utf8.DecodeRuneInString(word[i:])
if r != '$' {
buf.WriteRune(r)
continue
}
w += g.identLength(word[i+w:])
envVar := word[i+1 : i+w]
var sub string
switch envVar {
case "GOARCH":
sub = runtime.GOARCH
case "GOOS":
sub = runtime.GOOS
case "GOFILE":
sub = g.file
case "GOPACKAGE":
sub = g.pkg
default:
sub = os.Getenv(envVar)
}
buf.WriteString(sub)
}
return buf.String()
}
// identLength returns the length of the identifier beginning the string.
func (g *Generator) identLength(word string) int {
for i, r := range word {
if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
continue
}
return i
}
return len(word)
}
// setShorthand installs a new shorthand as defined by a -command directive.
func (g *Generator) setShorthand(words []string) {
// Create command shorthand.
if len(words) == 1 {
g.errorf("no command specified for -command")
}
command := words[1]
if g.commands[command] != nil {
g.errorf("command %q defined multiply defined", command)
}
g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
}
// exec runs the command specified by the argument. The first word is
// the command name itself.
func (g *Generator) exec(words []string) {
cmd := exec.Command(words[0], words[1:]...)
// Standard in and out of generator should be the usual.
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// Run the command in the package directory.
cmd.Dir = g.dir
env := []string{
"GOARCH=" + runtime.GOARCH,
"GOOS=" + runtime.GOOS,
"GOFILE=" + g.file,
"GOPACKAGE=" + g.pkg,
}
cmd.Env = mergeEnvLists(env, os.Environ())
err := cmd.Run()
if err != nil {
g.errorf("running %q: %s", words[0], err)
}
}

View File

@ -0,0 +1,48 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"reflect"
"runtime"
"testing"
)
type splitTest struct {
in string
out []string
}
var splitTests = []splitTest{
{"", nil},
{"x", []string{"x"}},
{" a b\tc ", []string{"a", "b", "c"}},
{` " a " `, []string{" a "}},
{"$GOARCH", []string{runtime.GOARCH}},
{"$GOOS", []string{runtime.GOOS}},
{"$GOFILE", []string{"proc.go"}},
{"$GOPACKAGE", []string{"sys"}},
{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
{"/$XXNOTDEFINED/", []string{"//"}},
{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
}
func TestGenerateCommandParse(t *testing.T) {
g := &Generator{
r: nil, // Unused here.
path: "/usr/ken/sys/proc.go",
dir: "/usr/ken/sys",
file: "proc.go",
pkg: "sys",
commands: make(map[string][]string),
}
g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
for _, test := range splitTests {
got := g.split("//go:generate " + test.in + "\n")
if !reflect.DeepEqual(got, test.out) {
t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
}
}
}

View File

@ -16,7 +16,7 @@ import (
)
var cmdGet = &Command{
UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
Short: "download and install packages and dependencies",
Long: `
Get downloads and installs the packages named by the import paths,
@ -25,6 +25,11 @@ along with their dependencies.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
The -f flag, valid only when -u is set, forces get -u not to verify that
each package has been checked out from the source control repository
implied by its import path. This can be useful if the source is a local fork
of the original.
The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.
@ -53,6 +58,7 @@ See also: go build, go install, go clean.
}
var getD = cmdGet.Flag.Bool("d", false, "")
var getF = cmdGet.Flag.Bool("f", false, "")
var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "")
@ -63,6 +69,10 @@ func init() {
}
func runGet(cmd *Command, args []string) {
if *getF && !*getU {
fatalf("go get: cannot use -f flag without -u")
}
// Phase 1. Download/update.
var stk importStack
for _, arg := range downloadPaths(args) {
@ -151,7 +161,9 @@ func download(arg string, stk *importStack, getTestDeps bool) {
}
// Only process each package once.
if downloadCache[arg] {
// (Unless we're fetching test dependencies for this package,
// in which case we want to process it again.)
if downloadCache[arg] && !getTestDeps {
return
}
downloadCache[arg] = true
@ -264,6 +276,25 @@ func downloadPackage(p *Package) error {
return err
}
repo = "<local>" // should be unused; make distinctive
// Double-check where it came from.
if *getU && vcs.remoteRepo != nil && !*getF {
dir := filepath.Join(p.build.SrcRoot, rootPath)
if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
repo := rr.repo
if rr.vcs.resolveRepo != nil {
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
if err == nil {
repo = resolved
}
}
if remote != repo {
return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
}
}
}
}
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.

View File

@ -0,0 +1,55 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func TestAbsolutePath(t *testing.T) {
tmp, err := ioutil.TempDir("", "TestAbsolutePath")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
file := filepath.Join(tmp, "a.go")
err = ioutil.WriteFile(file, []byte{}, 0644)
if err != nil {
t.Fatal(err)
}
dir := filepath.Join(tmp, "dir")
err = os.Mkdir(dir, 0777)
if err != nil {
t.Fatal(err)
}
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
defer os.Chdir(wd)
// Chdir so current directory and a.go reside on the same drive.
err = os.Chdir(dir)
if err != nil {
t.Fatal(err)
}
noVolume := file[len(filepath.VolumeName(file)):]
wrongPath := filepath.Join(dir, noVolume)
output, err := exec.Command("go", "build", noVolume).CombinedOutput()
if err == nil {
t.Fatal("build should fail")
}
if strings.Contains(string(output), wrongPath) {
t.Fatalf("wrong output found: %v %v", err, string(output))
}
}

View File

@ -81,7 +81,8 @@ single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
File names that begin with "." or "_" are ignored by the go tool.
Directory and file names that begin with "." or "_" are ignored
by the go tool, as are directories named "testdata".
`,
}
@ -154,6 +155,11 @@ A few common code hosting sites have special syntax:
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
IBM DevOps Services (Git)
import "hub.jazz.net/git/user/project"
import "hub.jazz.net/git/user/project/sub/directory"
For code hosted on other servers, import paths may either be qualified
with the version control type, or the go tool can dynamically fetch
the import path over https/http and discover where the code resides
@ -229,7 +235,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
Run 'go help get' for more.
Import path checking
When the custom import path feature described above redirects to a
known code hosting site, each of the resulting packages has two possible
import paths, using the custom domain or the known hosting site.
A package statement is said to have an "import comment" if it is immediately
followed (before the next newline) by a comment of one of these two forms:
package math // import "path"
package math /* import "path" */
The go command will refuse to install a package with an import comment
unless it is being referred to by that import path. In this way, import comments
let package authors make sure the custom import path is used and not a
direct path to the underlying code hosting site.
See https://golang.org/s/go14customimport for details.
`,
}

View File

@ -30,28 +30,29 @@ syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler

View File

@ -79,6 +79,7 @@ var commands = []*Command{
cmdEnv,
cmdFix,
cmdFmt,
cmdGenerate,
cmdGet,
cmdInstall,
cmdList,
@ -536,7 +537,7 @@ func matchPackages(pattern string) []string {
})
for _, src := range buildContext.SrcDirs() {
if pattern == "std" && src != gorootSrcPkg {
if pattern == "std" && src != gorootSrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
@ -618,7 +619,7 @@ func matchPackagesInFS(pattern string) []string {
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)

View File

@ -14,6 +14,7 @@ import (
"os"
pathpkg "path"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
@ -25,16 +26,17 @@ type Package struct {
// Note: These fields are part of the go command's public API.
// See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go
Dir string `json:",omitempty"` // directory containing package sources
ImportPath string `json:",omitempty"` // import path of package in dir
Name string `json:",omitempty"` // package name
Doc string `json:",omitempty"` // package documentation string
Target string `json:",omitempty"` // install path
Goroot bool `json:",omitempty"` // is this package found in the Go root?
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
Root string `json:",omitempty"` // Go root or Go path dir containing this package
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
Dir string `json:",omitempty"` // directory containing package sources
ImportPath string `json:",omitempty"` // import path of package in dir
ImportComment string `json:",omitempty"` // path in import comment on package statement
Name string `json:",omitempty"` // package name
Doc string `json:",omitempty"` // package documentation string
Target string `json:",omitempty"` // install path
Goroot bool `json:",omitempty"` // is this package found in the Go root?
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
Root string `json:",omitempty"` // Go root or Go path dir containing this package
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
// Source files
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@ -103,6 +105,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.Dir = pp.Dir
p.ImportPath = pp.ImportPath
p.ImportComment = pp.ImportComment
p.Name = pp.Name
p.Doc = pp.Doc
p.Root = pp.Root
@ -218,7 +221,7 @@ func dirToImportPath(dir string) string {
}
func makeImportValid(r rune) rune {
// Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
// Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport.
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
return '_'
@ -244,6 +247,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
importPath = dirToImportPath(filepath.Join(srcDir, path))
}
if p := packageCache[importPath]; p != nil {
if perr := disallowInternal(srcDir, p, stk); perr != p {
return perr
}
return reusePackage(p, stk)
}
@ -258,11 +264,14 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
//
// TODO: After Go 1, decide when to pass build.AllowBinary here.
// See issue 3268 for mistakes to avoid.
bp, err := buildContext.Import(path, srcDir, 0)
bp, err := buildContext.Import(path, srcDir, build.ImportComment)
bp.ImportPath = importPath
if gobin != "" {
bp.BinDir = gobin
}
if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
}
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
pos := importPos[0]
@ -270,6 +279,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
p.Error.Pos = pos.String()
}
if perr := disallowInternal(srcDir, p, stk); perr != p {
return perr
}
return p
}
@ -298,12 +311,82 @@ func reusePackage(p *Package, stk *importStack) *Package {
return p
}
// disallowInternal checks that srcDir is allowed to import p.
// If the import is allowed, disallowInternal returns the original package p.
// If not, it returns a new package containing just an appropriate error.
func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
// golang.org/s/go14internal:
// An import of a path containing the element “internal”
// is disallowed if the importing code is outside the tree
// rooted at the parent of the “internal” directory.
//
// ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH.
// Only applies to $GOROOT.
if !p.Standard {
return p
}
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
// import. Anything listed on the command line is fine.
if len(*stk) == 1 {
return p
}
// Check for "internal" element: four cases depending on begin of string and/or end of string.
i, ok := findInternal(p.ImportPath)
if !ok {
return p
}
// Internal is present.
// Map import path back to directory corresponding to parent of internal.
if i > 0 {
i-- // rewind over slash in ".../internal"
}
parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
return p
}
// Internal is present, and srcDir is outside parent's tree. Not allowed.
perr := *p
perr.Error = &PackageError{
ImportStack: stk.copy(),
Err: "use of internal package not allowed",
}
perr.Incomplete = true
return &perr
}
// findInternal looks for the final "internal" path element in the given import path.
// If there isn't one, findInternal returns ok=false.
// Otherwise, findInternal returns ok=true and the index of the "internal".
func findInternal(path string) (index int, ok bool) {
// Four cases, depending on internal at start/end of string or not.
// The order matters: we must return the index of the final element,
// because the final one produces the most restrictive requirement
// on the importer.
switch {
case strings.HasSuffix(path, "/internal"):
return len(path) - len("internal"), true
case strings.Contains(path, "/internal/"):
return strings.LastIndex(path, "/internal/") + 1, true
case path == "internal", strings.HasPrefix(path, "internal/"):
return 0, true
}
return 0, false
}
type targetDir int
const (
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
toBin // GOROOT/bin
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
toBin // GOROOT/bin
stalePath // the old import path; fail to build
)
// goTools is a map of Go program import path to install target directory.
@ -316,10 +399,14 @@ var goTools = map[string]targetDir{
"cmd/nm": toTool,
"cmd/objdump": toTool,
"cmd/pack": toTool,
"cmd/pprof": toTool,
"cmd/yacc": toTool,
"code.google.com/p/go.tools/cmd/cover": toTool,
"code.google.com/p/go.tools/cmd/godoc": toBin,
"code.google.com/p/go.tools/cmd/vet": toTool,
"golang.org/x/tools/cmd/cover": toTool,
"golang.org/x/tools/cmd/godoc": toBin,
"golang.org/x/tools/cmd/vet": toTool,
"code.google.com/p/go.tools/cmd/cover": stalePath,
"code.google.com/p/go.tools/cmd/godoc": stalePath,
"code.google.com/p/go.tools/cmd/vet": stalePath,
}
// expandScanner expands a scanner.List error into all the errors in the list.
@ -380,6 +467,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
if p.Name == "main" {
// Report an error when the old code.google.com/p/go.tools paths are used.
if goTools[p.ImportPath] == stalePath {
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
p.Error = &PackageError{Err: e}
return p
}
_, elem := filepath.Split(p.Dir)
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
@ -482,7 +576,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]bool)
deps := make(map[string]*Package)
for i, path := range importPaths {
if path == "C" {
continue
@ -505,10 +599,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
path = p1.ImportPath
importPaths[i] = path
}
deps[path] = true
deps[path] = p1
imports = append(imports, p1)
for _, dep := range p1.Deps {
deps[dep] = true
for _, dep := range p1.deps {
deps[dep.ImportPath] = dep
}
if p1.Incomplete {
p.Incomplete = true
@ -522,7 +616,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
sort.Strings(p.Deps)
for _, dep := range p.Deps {
p1 := packageCache[dep]
p1 := deps[dep]
if p1 == nil {
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
}
@ -538,6 +632,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
p.Target = p.target
// Check for C code compiled with Plan 9 C compiler.
// No longer allowed except in runtime and runtime/cgo, for now.
if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")),
}
return p
}
// In the absence of errors lower in the dependency tree,
// check for case-insensitive collisions of import paths.
if len(p.DepsErrors) == 0 {
@ -599,6 +703,12 @@ func computeStale(pkgs ...*Package) {
}
}
// The runtime version string takes one of two forms:
// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
// Determine whether we are in a released copy by
// inspecting the version.
var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
// isStale reports whether package p needs to be rebuilt.
func isStale(p *Package, topRoot map[string]bool) bool {
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
@ -619,7 +729,16 @@ func isStale(p *Package, topRoot map[string]bool) bool {
return false
}
if buildA || p.target == "" || p.Stale {
// If we are running a release copy of Go, do not rebuild the standard packages.
// They may not be writable anyway, but they are certainly not changing.
// This makes 'go build -a' skip the standard packages when using an official release.
// See issue 4106 and issue 8290.
pkgBuildA := buildA
if p.Standard && isGoRelease {
pkgBuildA = false
}
if pkgBuildA || p.target == "" || p.Stale {
return true
}
@ -707,24 +826,13 @@ func loadPackage(arg string, stk *importStack) *Package {
arg = sub
}
}
if strings.HasPrefix(arg, "cmd/") {
if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
if p := cmdCache[arg]; p != nil {
return p
}
stk.push(arg)
defer stk.pop()
if strings.Contains(arg[4:], "/") {
p := &Package{
Error: &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
hard: true,
},
}
return p
}
bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true

View File

@ -6,6 +6,7 @@ package main
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/build"
@ -48,7 +49,7 @@ It prints a summary of the test results in the format:
followed by detailed output for each failed package.
'Go test' recompiles each package along with any files with names matching
the file pattern "*_test.go".
the file pattern "*_test.go".
Files whose names begin with "_" (including "_test.go") or "." are ignored.
These additional files can contain test functions, benchmark functions, and
example functions. See 'go help testfunc' for more.
@ -65,16 +66,23 @@ non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
(Where pkg is the last element of the package's import path.)
-c
Compile the test binary to pkg.test but do not run it
(where pkg is the last element of the package's import path).
The file name can be changed with the -o flag.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
-i
Install packages that are dependencies of the test.
Do not run the test.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
-o file
Compile the test binary to the named file.
The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
@ -122,6 +130,7 @@ control the execution of any test:
-blockprofile block.out
Write a goroutine blocking profile to the specified file
when all tests are complete.
Writes test binary as -c would.
-blockprofilerate n
Control the detail provided in goroutine blocking profiles by
@ -153,8 +162,7 @@ control the execution of any test:
Sets -cover.
-coverprofile cover.out
Write a coverage profile to the specified file after all tests
have passed.
Write a coverage profile to the file after all tests have passed.
Sets -cover.
-cpu 1,2,4
@ -164,10 +172,11 @@ control the execution of any test:
-cpuprofile cpu.out
Write a CPU profile to the specified file before exiting.
Writes test binary as -c would.
-memprofile mem.out
Write a memory profile to the specified file after all tests
have passed.
Write a memory profile to the file after all tests have passed.
Writes test binary as -c would.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting
@ -274,10 +283,10 @@ var (
testCoverMode string // -covermode flag
testCoverPaths []string // -coverpkg flag
testCoverPkgs []*Package // -coverpkg flag
testO string // -o flag
testProfile bool // some profiling flag
testNeedBinary bool // profile needs to keep binary around
testV bool // -v flag
testFiles []string // -file flag(s) TODO: not respected
testTimeout string // -timeout flag
testArgs []string
testBench bool
@ -291,6 +300,7 @@ var testMainDeps = map[string]bool{
// Dependencies for testmain.
"testing": true,
"regexp": true,
"os": true,
}
func runTest(cmd *Command, args []string) {
@ -308,6 +318,9 @@ func runTest(cmd *Command, args []string) {
if testC && len(pkgs) != 1 {
fatalf("cannot use -c flag with multiple packages")
}
if testO != "" && len(pkgs) != 1 {
fatalf("cannot use -o flag with multiple packages")
}
if testProfile && len(pkgs) != 1 {
fatalf("cannot use test profile flag with multiple packages")
}
@ -524,6 +537,13 @@ func contains(x []string, s string) bool {
return false
}
var windowsBadWords = []string{
"install",
"patch",
"setup",
"update",
}
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := b.action(modeBuild, modeBuild, p)
@ -695,7 +715,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
omitDWARF: !testC && !testNeedBinary,
}
// The generated main also imports testing and regexp.
// The generated main also imports testing, regexp, and os.
stk.push("testmain")
for dep := range testMainDeps {
if dep == ptest.ImportPath {
@ -734,11 +754,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if err != nil {
return nil, nil, nil, err
}
if t.NeedTest || ptest.coverMode != "" {
if len(ptest.GoFiles) > 0 {
pmain.imports = append(pmain.imports, ptest)
t.ImportTest = true
}
if t.NeedXtest {
if pxtest != nil {
pmain.imports = append(pmain.imports, pxtest)
t.ImportXtest = true
}
if ptest != p && localCover {
@ -790,17 +812,54 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
a.objdir = testDir + string(filepath.Separator)
a.objpkg = filepath.Join(testDir, "main.a")
a.target = filepath.Join(testDir, testBinary) + exeSuffix
pmainAction := a
if goos == "windows" {
// There are many reserved words on Windows that,
// if used in the name of an executable, cause Windows
// to try to ask for extra permissions.
// The word list includes setup, install, update, and patch,
// but it does not appear to be defined anywhere.
// We have run into this trying to run the
// go.codereview/patch tests.
// For package names containing those words, use test.test.exe
// instead of pkgname.test.exe.
// Note that this file name is only used in the Go command's
// temporary directory. If the -c or other flags are
// given, the code below will still use pkgname.test.exe.
// There are two user-visible effects of this change.
// First, you can actually run 'go test' in directories that
// have names that Windows thinks are installer-like,
// without getting a dialog box asking for more permissions.
// Second, in the Windows process listing during go test,
// the test shows up as test.test.exe, not pkgname.test.exe.
// That second one is a drawback, but it seems a small
// price to pay for the test running at all.
// If maintaining the list of bad words is too onerous,
// we could just do this always on Windows.
for _, bad := range windowsBadWords {
if strings.Contains(testBinary, bad) {
a.target = filepath.Join(testDir, "test.test") + exeSuffix
break
}
}
}
buildAction = a
if testC || testNeedBinary {
// -c or profiling flag: create action to copy binary to ./test.out.
runAction = &action{
f: (*builder).install,
deps: []*action{pmainAction},
p: pmain,
target: filepath.Join(cwd, testBinary+exeSuffix),
target := filepath.Join(cwd, testBinary+exeSuffix)
if testO != "" {
target = testO
if !filepath.IsAbs(target) {
target = filepath.Join(cwd, target)
}
}
pmainAction = runAction // in case we are running the test
buildAction = &action{
f: (*builder).install,
deps: []*action{buildAction},
p: pmain,
target: target,
}
runAction = buildAction // make sure runAction != nil even if not running test
}
if testC {
printAction = &action{p: p, deps: []*action{runAction}} // nop
@ -808,7 +867,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// run test
runAction = &action{
f: (*builder).runTest,
deps: []*action{pmainAction},
deps: []*action{buildAction},
p: p,
ignoreFail: true,
}
@ -824,7 +883,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
}
}
return pmainAction, runAction, printAction, nil
return buildAction, runAction, printAction, nil
}
func testImportStack(top string, p *Package, target string) []string {
@ -1068,6 +1127,31 @@ func (b *builder) notest(a *action) error {
return nil
}
// isTestMain tells whether fn is a TestMain(m *testing.M) function.
func isTestMain(fn *ast.FuncDecl) bool {
if fn.Name.String() != "TestMain" ||
fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
fn.Type.Params == nil ||
len(fn.Type.Params.List) != 1 ||
len(fn.Type.Params.List[0].Names) > 1 {
return false
}
ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
if !ok {
return false
}
// We can't easily check that the type is *testing.M
// because we don't know how testing has been imported,
// but at least check that it's *M or *something.M.
if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
return true
}
if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
return true
}
return false
}
// isTest tells whether name looks like a test (or benchmark, according to prefix).
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
// We don't want TesticularCancer.
@ -1093,12 +1177,12 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {
Package: ptest,
}
for _, file := range ptest.TestGoFiles {
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
return nil, err
}
}
for _, file := range ptest.XTestGoFiles {
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
return nil, err
}
}
@ -1121,13 +1205,16 @@ func writeTestmain(out string, t *testFuncs) error {
}
type testFuncs struct {
Tests []testFunc
Benchmarks []testFunc
Examples []testFunc
Package *Package
NeedTest bool
NeedXtest bool
Cover []coverInfo
Tests []testFunc
Benchmarks []testFunc
Examples []testFunc
TestMain *testFunc
Package *Package
ImportTest bool
NeedTest bool
ImportXtest bool
NeedXtest bool
Cover []coverInfo
}
func (t *testFuncs) CoverMode() string {
@ -1162,7 +1249,7 @@ type testFunc struct {
var testFileSet = token.NewFileSet()
func (t *testFuncs) load(filename, pkg string, seen *bool) error {
func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil {
return expandScanner(err)
@ -1177,17 +1264,24 @@ func (t *testFuncs) load(filename, pkg string, seen *bool) error {
}
name := n.Name.String()
switch {
case isTestMain(n):
if t.TestMain != nil {
return errors.New("multiple definitions of TestMain")
}
t.TestMain = &testFunc{pkg, name, ""}
*doImport, *seen = true, true
case isTest(name, "Test"):
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
*seen = true
*doImport, *seen = true, true
case isTest(name, "Benchmark"):
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
*seen = true
*doImport, *seen = true, true
}
}
ex := doc.Examples(f)
sort.Sort(byOrder(ex))
for _, e := range ex {
*doImport = true // import test file whether executed or not
if e.Output == "" && !e.EmptyOutput {
// Don't run examples with no output.
continue
@ -1208,14 +1302,17 @@ var testmainTmpl = template.Must(template.New("main").Parse(`
package main
import (
{{if not .TestMain}}
"os"
{{end}}
"regexp"
"testing"
{{if .NeedTest}}
_test {{.Package.ImportPath | printf "%q"}}
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
{{end}}
{{if .NeedXtest}}
_xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{if .ImportXtest}}
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{end}}
{{range $i, $p := .Cover}}
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
@ -1302,7 +1399,12 @@ func main() {
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
testing.Main(matchString, tests, benchmarks, examples)
m := testing.MainStart(matchString, tests, benchmarks, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
{{else}}
os.Exit(m.Run())
{{end}}
}
`))

View File

@ -0,0 +1,13 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Simple test for go generate.
// We include a build tag that go generate should ignore.
// +build ignore
//go:generate echo Success
package p

View File

@ -0,0 +1,10 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that go generate handles command aliases.
//go:generate -command run echo Now is the time
//go:generate run for all good men
package p

View File

@ -0,0 +1,9 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test go generate variable substitution.
//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
package p

View File

@ -0,0 +1,3 @@
package p
import "bad"

View File

@ -0,0 +1,3 @@
package p
import "conflict"

View File

@ -0,0 +1 @@
package bad // import

View File

@ -0,0 +1 @@
package conflict // import "a"

View File

@ -0,0 +1 @@
package conflict /* import "b" */

View File

@ -0,0 +1 @@
package x // import "works/x"

View File

@ -0,0 +1 @@
package x // important! not an import comment

View File

@ -0,0 +1 @@
package x // import "my/x"

View File

@ -0,0 +1,3 @@
package p
import _ "works/x"

View File

@ -0,0 +1,3 @@
package p
import "wrongplace"

View File

@ -0,0 +1,11 @@
package pkg_test
import "os"
func init() {
os.Stdout.Write([]byte("File with non-runnable example was built.\n"))
}
func Example_test() {
// This test will not be run, it has no "Output:" comment.
}

View File

@ -0,0 +1,10 @@
package pkg
import (
"os"
"testing"
)
func TestBuilt(t *testing.T) {
os.Stdout.Write([]byte("A normal test was executed.\n"))
}

View File

@ -0,0 +1 @@
package badc

View File

@ -0,0 +1,5 @@
package badexec
func init() {
panic("badexec")
}

View File

@ -0,0 +1 @@
package badsyntax

View File

@ -0,0 +1,3 @@
package badsyntax
func func func func func!

View File

@ -0,0 +1 @@
package badvar

View File

@ -0,0 +1,5 @@
package badvar_test
func f() {
_ = notdefined
}

View File

@ -0,0 +1 @@
package p_test

View File

@ -0,0 +1,7 @@
package p
import "fmt"
func f() {
fmt.Printf("%d")
}

View File

@ -0,0 +1,3 @@
package p
import _ "net/http/internal"

View File

@ -0,0 +1,3 @@
package p
import _ "./x/y/z/internal/w"

View File

@ -0,0 +1 @@
package w

View File

@ -65,9 +65,9 @@ type testFlagSpec struct {
var testFlagDefn = []*testFlagSpec{
// local.
{name: "c", boolVar: &testC},
{name: "file", multiOK: true},
{name: "cover", boolVar: &testCover},
{name: "coverpkg"},
{name: "o"},
// build flags.
{name: "a", boolVar: &buildA},
@ -153,6 +153,9 @@ func testFlags(args []string) (packageNames, passToTest []string) {
// bool flags.
case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
setBoolFlag(f.boolVar, value)
case "o":
testO = value
testNeedBinary = true
case "p":
setIntFlag(&buildP, value)
case "exec":
@ -184,8 +187,6 @@ func testFlags(args []string) (packageNames, passToTest []string) {
buildContext.BuildTags = strings.Fields(value)
case "compiler":
buildCompiler{}.Set(value)
case "file":
testFiles = append(testFiles, value)
case "bench":
// record that we saw the flag; don't care about the value
testBench = true

21
libgo/go/cmd/go/testgo.go Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains extra hooks for testing the go command.
// It is compiled into the Go binary only when building the
// test copy; it does not get compiled into the standard go
// command, so these testing hooks are not present in the
// go command that everyone uses.
// +build testgo
package main
import "os"
func init() {
if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" {
isGoRelease = v == "1"
}
}

View File

@ -47,13 +47,13 @@ const toolWindowsExtension = ".exe"
func tool(toolName string) string {
toolPath := filepath.Join(toolDir, toolName)
if toolIsWindows && toolName != "pprof" {
if toolIsWindows {
toolPath += toolWindowsExtension
}
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
if isInGoToolsRepo(toolName) {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName)
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) {
if toolPath == "" {
return
}
if toolIsWindows && toolName == "pprof" {
args = append([]string{"perl", toolPath}, args[1:]...)
var err error
toolPath, err = exec.LookPath("perl")
if err != nil {
fmt.Fprintf(os.Stderr, "go tool: perl not found\n")
setExitStatus(3)
return
}
}
if toolN {
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
return

View File

@ -33,6 +33,9 @@ type vcsCmd struct {
scheme []string
pingCmd string
remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
}
// A tagCmd describes a command to list available tags
@ -81,8 +84,17 @@ var vcsHg = &vcsCmd{
tagSyncCmd: "update -r {tag}",
tagSyncDefault: "update default",
scheme: []string{"https", "http", "ssh"},
pingCmd: "identify {scheme}://{repo}",
scheme: []string{"https", "http", "ssh"},
pingCmd: "identify {scheme}://{repo}",
remoteRepo: hgRemoteRepo,
}
func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) {
out, err := vcsHg.runOutput(rootDir, "paths default")
if err != nil {
return "", err
}
return strings.TrimSpace(string(out)), nil
}
// vcsGit describes how to use Git.
@ -104,8 +116,38 @@ var vcsGit = &vcsCmd{
tagSyncCmd: "checkout {tag}",
tagSyncDefault: "checkout master",
scheme: []string{"git", "https", "http", "git+ssh"},
pingCmd: "ls-remote {scheme}://{repo}",
scheme: []string{"git", "https", "http", "git+ssh"},
pingCmd: "ls-remote {scheme}://{repo}",
remoteRepo: gitRemoteRepo,
}
func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
outb, err := vcsGit.runOutput(rootDir, "remote -v")
if err != nil {
return "", err
}
out := string(outb)
// Expect:
// origin https://github.com/rsc/pdf (fetch)
// origin https://github.com/rsc/pdf (push)
// use first line only.
if !strings.HasPrefix(out, "origin\t") {
return "", fmt.Errorf("unable to parse output of git remote -v")
}
out = strings.TrimPrefix(out, "origin\t")
i := strings.Index(out, "\n")
if i < 0 {
return "", fmt.Errorf("unable to parse output of git remote -v")
}
out = out[:i]
i = strings.LastIndex(out, " ")
if i < 0 {
return "", fmt.Errorf("unable to parse output of git remote -v")
}
out = out[:i]
return strings.TrimSpace(string(out)), nil
}
// vcsBzr describes how to use Bazaar.
@ -123,8 +165,51 @@ var vcsBzr = &vcsCmd{
tagSyncCmd: "update -r {tag}",
tagSyncDefault: "update -r revno:-1",
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
pingCmd: "info {scheme}://{repo}",
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
pingCmd: "info {scheme}://{repo}",
remoteRepo: bzrRemoteRepo,
resolveRepo: bzrResolveRepo,
}
func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
if err != nil {
return "", err
}
return strings.TrimSpace(string(outb)), nil
}
func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
if err != nil {
return "", err
}
out := string(outb)
// Expect:
// ...
// (branch root|repository branch): <URL>
// ...
found := false
for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} {
i := strings.Index(out, prefix)
if i >= 0 {
out = out[i+len(prefix):]
found = true
break
}
}
if !found {
return "", fmt.Errorf("unable to parse output of bzr info")
}
i := strings.Index(out, "\n")
if i < 0 {
return "", fmt.Errorf("unable to parse output of bzr info")
}
out = out[:i]
return strings.TrimSpace(string(out)), nil
}
// vcsSvn describes how to use Subversion.
@ -138,8 +223,34 @@ var vcsSvn = &vcsCmd{
// There is no tag command in subversion.
// The branch information is all in the path names.
scheme: []string{"https", "http", "svn", "svn+ssh"},
pingCmd: "info {scheme}://{repo}",
scheme: []string{"https", "http", "svn", "svn+ssh"},
pingCmd: "info {scheme}://{repo}",
remoteRepo: svnRemoteRepo,
}
func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) {
outb, err := vcsSvn.runOutput(rootDir, "info")
if err != nil {
return "", err
}
out := string(outb)
// Expect:
// ...
// Repository Root: <URL>
// ...
i := strings.Index(out, "\nRepository Root: ")
if i < 0 {
return "", fmt.Errorf("unable to parse output of svn info")
}
out = out[i+len("\nRepository Root: "):]
i = strings.Index(out, "\n")
if i < 0 {
return "", fmt.Errorf("unable to parse output of svn info")
}
out = out[:i]
return strings.TrimSpace(string(out)), nil
}
func (v *vcsCmd) String() string {
@ -361,7 +472,14 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`)
func repoRootForImportPath(importPath string) (*repoRoot, error) {
rr, err := repoRootForImportPathStatic(importPath, "")
if err == errUnknownSite {
rr, err = repoRootForImportDynamic(importPath)
// If there are wildcards, look up the thing before the wildcard,
// hoping it applies to the wildcarded parts too.
// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
lookup := strings.TrimSuffix(importPath, "/...")
if i := strings.Index(lookup, "/.../"); i >= 0 {
lookup = lookup[:i]
}
rr, err = repoRootForImportDynamic(lookup)
// repoRootForImportDynamic returns error detail
// that is irrelevant if the user didn't intend to use a
@ -465,11 +583,11 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
slash := strings.Index(importPath, "/")
if slash < 0 {
return nil, errors.New("import path doesn't contain a slash")
return nil, errors.New("import path does not contain a slash")
}
host := importPath[:slash]
if !strings.Contains(host, ".") {
return nil, errors.New("import path doesn't contain a hostname")
return nil, errors.New("import path does not begin with hostname")
}
urlStr, body, err := httpsOrHTTP(importPath)
if err != nil {
@ -613,6 +731,15 @@ var vcsPaths = []*vcsPath{
check: launchpadVCS,
},
// IBM DevOps Services (JazzHub)
{
prefix: "hub.jazz.net/git",
re: `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
check: noVCSSuffix,
},
// General syntax for any server.
{
re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,

124
libgo/go/cmd/go/vcs_test.go Normal file
View File

@ -0,0 +1,124 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"runtime"
"testing"
)
// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
// TODO(cmang): Add tests for SVN and BZR.
func TestRepoRootForImportPath(t *testing.T) {
if testing.Short() {
t.Skip("skipping test to avoid external network")
}
switch runtime.GOOS {
case "nacl", "android":
t.Skipf("no networking available on %s", runtime.GOOS)
}
tests := []struct {
path string
want *repoRoot
}{
{
"code.google.com/p/go",
&repoRoot{
vcs: vcsHg,
repo: "https://code.google.com/p/go",
},
},
/*{
"code.google.com/r/go",
&repoRoot{
vcs: vcsHg,
repo: "https://code.google.com/r/go",
},
},*/
{
"github.com/golang/groupcache",
&repoRoot{
vcs: vcsGit,
repo: "https://github.com/golang/groupcache",
},
},
// IBM DevOps Services tests
{
"hub.jazz.net/git/user1/pkgname",
&repoRoot{
vcs: vcsGit,
repo: "https://hub.jazz.net/git/user1/pkgname",
},
},
{
"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
&repoRoot{
vcs: vcsGit,
repo: "https://hub.jazz.net/git/user1/pkgname",
},
},
{
"hub.jazz.net",
nil,
},
{
"hub2.jazz.net",
nil,
},
{
"hub.jazz.net/someotherprefix",
nil,
},
{
"hub.jazz.net/someotherprefix/user1/pkgname",
nil,
},
// Spaces are not valid in user names or package names
{
"hub.jazz.net/git/User 1/pkgname",
nil,
},
{
"hub.jazz.net/git/user1/pkg name",
nil,
},
// Dots are not valid in user names
{
"hub.jazz.net/git/user.1/pkgname",
nil,
},
{
"hub.jazz.net/git/user/pkg.name",
&repoRoot{
vcs: vcsGit,
repo: "https://hub.jazz.net/git/user/pkg.name",
},
},
// User names cannot have uppercase letters
{
"hub.jazz.net/git/USER/pkgname",
nil,
},
}
for _, test := range tests {
got, err := repoRootForImportPath(test.path)
want := test.want
if want == nil {
if err == nil {
t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path)
}
continue
}
if err != nil {
t.Errorf("RepoRootForImport(%q): %v", test.path, err)
continue
}
if got.vcs.name != want.vcs.name || got.repo != want.repo {
t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
}
}
}

View File

@ -4,6 +4,8 @@
package main
import "path/filepath"
func init() {
addBuildFlagsNX(cmdVet)
}
@ -15,7 +17,7 @@ var cmdVet = &Command{
Long: `
Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.
@ -28,10 +30,21 @@ See also: go fmt, go fix.
}
func runVet(cmd *Command, args []string) {
for _, pkg := range packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
for _, p := range packages(args) {
// Vet expects to be given a set of files all from the same package.
// Run once for package p and once for package p_test.
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
}
if len(p.XTestGoFiles) > 0 {
runVetFiles(p, stringList(p.XTestGoFiles))
}
}
}
func runVetFiles(p *Package, files []string) {
for i := range files {
files[i] = filepath.Join(p.Dir, files[i])
}
run(tool("vet"), relPaths(files))
}

View File

@ -67,7 +67,7 @@ To remove the parentheses:
To convert the package tree from explicit slice upper bounds to implicit ones:
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src
The simplify command

View File

@ -87,13 +87,13 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
return err
}
file, adjust, err := parse(fileSet, filename, src, stdin)
file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
if err != nil {
return err
}
if rewrite != nil {
if adjust == nil {
if sourceAdj == nil {
file = rewrite(file)
} else {
fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
@ -106,15 +106,10 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
simplify(file)
}
var buf bytes.Buffer
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
if err != nil {
return err
}
res := buf.Bytes()
if adjust != nil {
res = adjust(src, res)
}
if !bytes.Equal(src, res) {
// formatting has changed
@ -122,7 +117,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
fmt.Fprintln(out, filename)
}
if *write {
err = ioutil.WriteFile(filename, res, 0)
err = ioutil.WriteFile(filename, res, 0644)
if err != nil {
return err
}
@ -186,6 +181,11 @@ func gofmtMain() {
initRewrite()
if flag.NArg() == 0 {
if *write {
fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
exitCode = 2
return
}
if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
report(err)
}
@ -235,19 +235,29 @@ func diff(b1, b2 []byte) (data []byte, err error) {
}
// parse parses src, which was read from filename,
// as a Go source file or statement list.
func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
// ----------------------------------------------------------------------------
// Support functions
//
// The functions parse, format, and isSpace below are identical to the
// respective functions in src/go/format/format.go - keep them in sync!
//
// TODO(gri) Factor out this functionality, eventually.
// parse parses src, which was read from the named file,
// as a Go source file, declaration, or statement list.
func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
file *ast.File,
sourceAdj func(src []byte, indent int) []byte,
indentAdj int,
err error,
) {
// Try as whole source file.
file, err := parser.ParseFile(fset, filename, src, parserMode)
if err == nil {
return file, nil, nil
}
// If the error is that the source file didn't begin with a
// package line and this is standard input, fall through to
file, err = parser.ParseFile(fset, filename, src, parserMode)
// If there's no error, return. If the error is that the source file didn't begin with a
// package line and source fragments are ok, fall through to
// try as a source fragment. Stop and return on any other error.
if !stdin || !strings.Contains(err.Error(), "expected 'package'") {
return nil, nil, err
if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
return
}
// If this is a declaration list, make it a source file
@ -257,19 +267,19 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F
psrc := append([]byte("package p;"), src...)
file, err = parser.ParseFile(fset, filename, psrc, parserMode)
if err == nil {
adjust := func(orig, src []byte) []byte {
sourceAdj = func(src []byte, indent int) []byte {
// Remove the package clause.
// Gofmt has turned the ; into a \n.
src = src[len("package p\n"):]
return matchSpace(orig, src)
src = src[indent+len("package p\n"):]
return bytes.TrimSpace(src)
}
return file, adjust, nil
return
}
// If the error is that the source file didn't begin with a
// declaration, fall through to try as a statement list.
// Stop and return on any other error.
if !strings.Contains(err.Error(), "expected declaration") {
return nil, nil, err
return
}
// If this is a statement list, make it a source file
@ -277,68 +287,101 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F
// into a function body. This handles expressions too.
// Insert using a ;, not a newline, so that the line numbers
// in fsrc match the ones in src.
fsrc := append(append([]byte("package p; func _() {"), src...), '}')
fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
if err == nil {
adjust := func(orig, src []byte) []byte {
sourceAdj = func(src []byte, indent int) []byte {
// Cap adjusted indent to zero.
if indent < 0 {
indent = 0
}
// Remove the wrapping.
// Gofmt has turned the ; into a \n\n.
src = src[len("package p\n\nfunc _() {"):]
src = src[:len(src)-len("}\n")]
// Gofmt has also indented the function body one level.
// Remove that indent.
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
return matchSpace(orig, src)
// There will be two non-blank lines with indent, hence 2*indent.
src = src[2*indent+len("package p\n\nfunc _() {"):]
src = src[:len(src)-(indent+len("\n}\n"))]
return bytes.TrimSpace(src)
}
return file, adjust, nil
// Gofmt has also indented the function body one level.
// Adjust that with indentAdj.
indentAdj = -1
}
// Failed, and out of options.
return nil, nil, err
// Succeeded, or out of options.
return
}
func cutSpace(b []byte) (before, middle, after []byte) {
i := 0
for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
i++
// format formats the given package file originally obtained from src
// and adjusts the result based on the original source via sourceAdj
// and indentAdj.
func format(
fset *token.FileSet,
file *ast.File,
sourceAdj func(src []byte, indent int) []byte,
indentAdj int,
src []byte,
cfg printer.Config,
) ([]byte, error) {
if sourceAdj == nil {
// Complete source file.
var buf bytes.Buffer
err := cfg.Fprint(&buf, fset, file)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
j := len(b)
for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') {
j--
// Partial source file.
// Determine and prepend leading space.
i, j := 0, 0
for j < len(src) && isSpace(src[j]) {
if src[j] == '\n' {
i = j + 1 // byte offset of last line in leading space
}
j++
}
if i <= j {
return b[:i], b[i:j], b[j:]
var res []byte
res = append(res, src[:i]...)
// Determine and prepend indentation of first code line.
// Spaces are ignored unless there are no tabs,
// in which case spaces count as one tab.
indent := 0
hasSpace := false
for _, b := range src[i:j] {
switch b {
case ' ':
hasSpace = true
case '\t':
indent++
}
}
return nil, nil, b[j:]
if indent == 0 && hasSpace {
indent = 1
}
for i := 0; i < indent; i++ {
res = append(res, '\t')
}
// Format the source.
// Write it without any leading and trailing space.
cfg.Indent = indent + indentAdj
var buf bytes.Buffer
err := cfg.Fprint(&buf, fset, file)
if err != nil {
return nil, err
}
res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
// Determine and append trailing space.
i = len(src)
for i > 0 && isSpace(src[i-1]) {
i--
}
return append(res, src[i:]...), nil
}
// matchSpace reformats src to use the same space context as orig.
// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
// 2) matchSpace copies the indentation of the first non-blank line in orig
// to every non-blank line in src.
// 3) matchSpace copies the trailing space from orig and uses it in place
// of src's trailing space.
func matchSpace(orig []byte, src []byte) []byte {
before, _, after := cutSpace(orig)
i := bytes.LastIndex(before, []byte{'\n'})
before, indent := before[:i+1], before[i+1:]
_, src, _ = cutSpace(src)
var b bytes.Buffer
b.Write(before)
for len(src) > 0 {
line := src
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, src = line[:i+1], line[i+1:]
} else {
src = nil
}
if len(line) > 0 && line[0] != '\n' { // not blank
b.Write(indent)
}
b.Write(line)
}
b.Write(after)
return b.Bytes()
func isSpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}

View File

@ -6,18 +6,60 @@ package main
import (
"bytes"
"flag"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"text/scanner"
)
func runTest(t *testing.T, in, out, flags string) {
var update = flag.Bool("update", false, "update .golden files")
// gofmtFlags looks for a comment of the form
//
// //gofmt flags
//
// within the first maxLines lines of the given file,
// and returns the flags string, if any. Otherwise it
// returns the empty string.
func gofmtFlags(filename string, maxLines int) string {
f, err := os.Open(filename)
if err != nil {
return "" // ignore errors - they will be found later
}
defer f.Close()
// initialize scanner
var s scanner.Scanner
s.Init(f)
s.Error = func(*scanner.Scanner, string) {} // ignore errors
s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
// look for //gofmt comment
for s.Line <= maxLines {
switch s.Scan() {
case scanner.Comment:
const prefix = "//gofmt "
if t := s.TokenText(); strings.HasPrefix(t, prefix) {
return strings.TrimSpace(t[len(prefix):])
}
case scanner.EOF:
return ""
}
}
return ""
}
func runTest(t *testing.T, in, out string) {
// process flags
*simplifyAST = false
*rewriteRule = ""
stdin := false
for _, flag := range strings.Split(flags, " ") {
for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
elts := strings.SplitN(flag, "=", 2)
name := elts[0]
value := ""
@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) {
}
if got := buf.Bytes(); !bytes.Equal(got, expected) {
if *update {
if in != out {
if err := ioutil.WriteFile(out, got, 0666); err != nil {
t.Error(err)
}
return
}
// in == out: don't accidentally destroy input
t.Errorf("WARNING: -update did not rewrite input file %s", in)
}
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
d, err := diff(expected, got)
if err == nil {
@ -67,51 +120,37 @@ func runTest(t *testing.T, in, out, flags string) {
}
}
var tests = []struct {
in, flags string
}{
{"gofmt.go", ""},
{"gofmt_test.go", ""},
{"testdata/composites.input", "-s"},
{"testdata/slices1.input", "-s"},
{"testdata/slices2.input", "-s"},
{"testdata/old.input", ""},
{"testdata/rewrite1.input", "-r=Foo->Bar"},
{"testdata/rewrite2.input", "-r=int->bool"},
{"testdata/rewrite3.input", "-r=x->x"},
{"testdata/rewrite4.input", "-r=(x)->x"},
{"testdata/rewrite5.input", "-r=x+x->2*x"},
{"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
{"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
{"testdata/rewrite8.input", "-r=interface{}->int"},
{"testdata/stdin*.input", "-stdin"},
{"testdata/comments.input", ""},
{"testdata/import.input", ""},
{"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF
{"testdata/typeswitch.input", ""}, // test case for issue 4470
}
// TestRewrite processes testdata/*.input files and compares them to the
// corresponding testdata/*.golden files. The gofmt flags used to process
// a file must be provided via a comment of the form
//
// //gofmt flags
//
// in the processed file within the first 20 lines, if any.
func TestRewrite(t *testing.T) {
for _, test := range tests {
match, err := filepath.Glob(test.in)
if err != nil {
t.Error(err)
continue
// determine input files
match, err := filepath.Glob("testdata/*.input")
if err != nil {
t.Fatal(err)
}
// add larger examples
match = append(match, "gofmt.go", "gofmt_test.go")
for _, in := range match {
out := in // for files where input and output are identical
if strings.HasSuffix(in, ".input") {
out = in[:len(in)-len(".input")] + ".golden"
}
for _, in := range match {
out := in
if strings.HasSuffix(in, ".input") {
out = in[:len(in)-len(".input")] + ".golden"
}
runTest(t, in, out, test.flags)
if in != out {
// Check idempotence.
runTest(t, out, out, test.flags)
}
runTest(t, in, out)
if in != out {
// Check idempotence.
runTest(t, out, out)
}
}
}
// Test case for issue 3961.
func TestCRLF(t *testing.T) {
const input = "testdata/crlf.input" // must contain CR/LF's
const golden = "testdata/crlf.golden" // must not contain any CR's

View File

@ -32,7 +32,7 @@ var (
)
func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
f, _, err := parse(fset, filename, src.Bytes(), false)
f, _, _, err := parse(fset, filename, src.Bytes(), false)
if err != nil {
return err
}
@ -60,7 +60,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
// exclude files w/ syntax errors (typically test cases)
fset := token.NewFileSet()
if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
if *verbose {
fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
}

View File

@ -226,9 +226,6 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
return true
case reflect.Struct:
if p.NumField() != v.NumField() {
return false
}
for i := 0; i < p.NumField(); i++ {
if !match(m, p.Field(i), v.Field(i)) {
return false

View File

@ -68,9 +68,10 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
// a slice expression of the form: s[a:len(s)]
// can be simplified to: s[a:]
// if s is "simple enough" (for now we only accept identifiers)
if s.hasDotImport {
// if dot imports are present, we cannot be certain that an
// unresolved "len" identifier refers to the predefined len()
if n.Max != nil || s.hasDotImport {
// - 3-index slices always require the 2nd and 3rd index
// - if dot imports are present, we cannot be certain that an
// unresolved "len" identifier refers to the predefined len()
break
}
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
@ -96,16 +97,26 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
// x, y := b[:n], b[n:]
case *ast.RangeStmt:
// a range of the form: for x, _ = range v {...}
// - a range of the form: for x, _ = range v {...}
// can be simplified to: for x = range v {...}
if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" {
// - a range of the form: for _ = range v {...}
// can be simplified to: for range v {...}
if isBlank(n.Value) {
n.Value = nil
}
if isBlank(n.Key) && n.Value == nil {
n.Key = nil
}
}
return s
}
func isBlank(x ast.Expr) bool {
ident, ok := x.(*ast.Ident)
return ok && ident.Name == "_"
}
func simplify(f *ast.File) {
var s simplifier
@ -117,5 +128,34 @@ func simplify(f *ast.File) {
}
}
// remove empty declarations such as "const ()", etc
removeEmptyDeclGroups(f)
ast.Walk(&s, f)
}
func removeEmptyDeclGroups(f *ast.File) {
i := 0
for _, d := range f.Decls {
if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
f.Decls[i] = d
i++
}
}
f.Decls = f.Decls[:i]
}
func isEmpty(f *ast.File, g *ast.GenDecl) bool {
if g.Doc != nil || g.Specs != nil {
return false
}
for _, c := range f.Comments {
// if there is a comment in the declaration, it is not considered empty
if g.Pos() <= c.Pos() && c.End() <= g.End() {
return false
}
}
return true
}

View File

@ -1,3 +1,5 @@
//gofmt -s
package P
type T struct {

View File

@ -1,3 +1,5 @@
//gofmt -s
package P
type T struct {

View File

@ -2,6 +2,7 @@
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
Test case for issue 3961.
*/
package main

View File

@ -2,6 +2,7 @@
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
Test case for issue 3961.
*/
package main

View File

@ -1,3 +1,5 @@
//gofmt -r=Foo->Bar
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=Foo->Bar
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=int->bool
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=int->bool
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=x->x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=x->x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=(x)->x
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=(x)->x
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=x+x->2*x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=x+x->2*x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=fun(x)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=fun(x)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=fun(x...)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=fun(x...)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=interface{}->int
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -r=interface{}->int
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

View File

@ -1,3 +1,5 @@
//gofmt -s
// Test cases for slice expression simplification.
package p
@ -15,6 +17,7 @@ var (
_ = a[3:(len(a))]
_ = a[len(a) : len(a)-1]
_ = a[0:len(b)]
_ = a[2:len(a):len(a)]
_ = a[:]
_ = a[:10]
@ -22,6 +25,7 @@ var (
_ = a[:(len(a))]
_ = a[:len(a)-1]
_ = a[:len(b)]
_ = a[:len(a):len(a)]
_ = s[0:]
_ = s[1:10]
@ -29,6 +33,7 @@ var (
_ = s[3:(len(s))]
_ = s[len(a) : len(s)-1]
_ = s[0:len(b)]
_ = s[2:len(s):len(s)]
_ = s[:]
_ = s[:10]
@ -36,6 +41,7 @@ var (
_ = s[:(len(s))]
_ = s[:len(s)-1]
_ = s[:len(b)]
_ = s[:len(s):len(s)]
_ = t.s[0:]
_ = t.s[1:10]
@ -43,6 +49,7 @@ var (
_ = t.s[3:(len(t.s))]
_ = t.s[len(a) : len(t.s)-1]
_ = t.s[0:len(b)]
_ = t.s[2:len(t.s):len(t.s)]
_ = t.s[:]
_ = t.s[:10]
@ -50,6 +57,7 @@ var (
_ = t.s[:(len(t.s))]
_ = t.s[:len(t.s)-1]
_ = t.s[:len(b)]
_ = t.s[:len(t.s):len(t.s)]
)
func _() {

View File

@ -1,3 +1,5 @@
//gofmt -s
// Test cases for slice expression simplification.
package p
@ -15,6 +17,7 @@ var (
_ = a[3:(len(a))]
_ = a[len(a) : len(a)-1]
_ = a[0:len(b)]
_ = a[2:len(a):len(a)]
_ = a[:]
_ = a[:10]
@ -22,6 +25,7 @@ var (
_ = a[:(len(a))]
_ = a[:len(a)-1]
_ = a[:len(b)]
_ = a[:len(a):len(a)]
_ = s[0:]
_ = s[1:10]
@ -29,6 +33,7 @@ var (
_ = s[3:(len(s))]
_ = s[len(a) : len(s)-1]
_ = s[0:len(b)]
_ = s[2:len(s):len(s)]
_ = s[:]
_ = s[:10]
@ -36,6 +41,7 @@ var (
_ = s[:(len(s))]
_ = s[:len(s)-1]
_ = s[:len(b)]
_ = s[:len(s):len(s)]
_ = t.s[0:]
_ = t.s[1:10]
@ -43,6 +49,7 @@ var (
_ = t.s[3:(len(t.s))]
_ = t.s[len(a) : len(t.s)-1]
_ = t.s[0:len(b)]
_ = t.s[2:len(t.s):len(t.s)]
_ = t.s[:]
_ = t.s[:10]
@ -50,6 +57,7 @@ var (
_ = t.s[:(len(t.s))]
_ = t.s[:len(t.s)-1]
_ = t.s[:len(b)]
_ = t.s[:len(t.s):len(t.s)]
)
func _() {

Some files were not shown because too many files have changed in this diff Show More