diff --git a/LICENSE b/LICENSE index 7448756763..6a66aea5ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/api/go1.7.txt b/api/go1.7.txt new file mode 100644 index 0000000000..35afa91136 --- /dev/null +++ b/api/go1.7.txt @@ -0,0 +1,276 @@ +pkg bytes, func ContainsAny([]uint8, string) bool +pkg bytes, func ContainsRune([]uint8, int32) bool +pkg bytes, method (*Reader) Reset([]uint8) +pkg compress/flate, const HuffmanOnly = -2 +pkg compress/flate, const HuffmanOnly ideal-int +pkg context, func Background() Context +pkg context, func TODO() Context +pkg context, func WithCancel(Context) (Context, CancelFunc) +pkg context, func WithDeadline(Context, time.Time) (Context, CancelFunc) +pkg context, func WithTimeout(Context, time.Duration) (Context, CancelFunc) +pkg context, func WithValue(Context, interface{}, interface{}) Context +pkg context, type CancelFunc func() +pkg context, type Context interface { Deadline, Done, Err, Value } +pkg context, type Context interface, Deadline() (time.Time, bool) +pkg context, type Context interface, Done() <-chan struct +pkg context, type Context interface, Err() error +pkg context, type Context interface, Value(interface{}) interface{} +pkg context, var Canceled error +pkg context, var DeadlineExceeded error +pkg crypto/tls, const RenegotiateFreelyAsClient = 2 +pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport +pkg crypto/tls, const RenegotiateNever = 0 +pkg crypto/tls, const RenegotiateNever RenegotiationSupport +pkg crypto/tls, const RenegotiateOnceAsClient = 1 +pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport +pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool +pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport +pkg crypto/tls, type RenegotiationSupport int +pkg crypto/x509, func SystemCertPool() (*CertPool, error) +pkg crypto/x509, type SystemRootsError struct, Err error +pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error) +pkg debug/dwarf, method (*Reader) SeekPC(uint64) (*Entry, error) +pkg debug/elf, const R_390_12 = 2 +pkg debug/elf, const R_390_12 R_390 +pkg debug/elf, const R_390_16 = 3 +pkg debug/elf, const R_390_16 R_390 +pkg debug/elf, const R_390_20 = 57 +pkg debug/elf, const R_390_20 R_390 +pkg debug/elf, const R_390_32 = 4 +pkg debug/elf, const R_390_32 R_390 +pkg debug/elf, const R_390_64 = 22 +pkg debug/elf, const R_390_64 R_390 +pkg debug/elf, const R_390_8 = 1 +pkg debug/elf, const R_390_8 R_390 +pkg debug/elf, const R_390_COPY = 9 +pkg debug/elf, const R_390_COPY R_390 +pkg debug/elf, const R_390_GLOB_DAT = 10 +pkg debug/elf, const R_390_GLOB_DAT R_390 +pkg debug/elf, const R_390_GOT12 = 6 +pkg debug/elf, const R_390_GOT12 R_390 +pkg debug/elf, const R_390_GOT16 = 15 +pkg debug/elf, const R_390_GOT16 R_390 +pkg debug/elf, const R_390_GOT20 = 58 +pkg debug/elf, const R_390_GOT20 R_390 +pkg debug/elf, const R_390_GOT32 = 7 +pkg debug/elf, const R_390_GOT32 R_390 +pkg debug/elf, const R_390_GOT64 = 24 +pkg debug/elf, const R_390_GOT64 R_390 +pkg debug/elf, const R_390_GOTENT = 26 +pkg debug/elf, const R_390_GOTENT R_390 +pkg debug/elf, const R_390_GOTOFF = 13 +pkg debug/elf, const R_390_GOTOFF R_390 +pkg debug/elf, const R_390_GOTOFF16 = 27 +pkg debug/elf, const R_390_GOTOFF16 R_390 +pkg debug/elf, const R_390_GOTOFF64 = 28 +pkg debug/elf, const R_390_GOTOFF64 R_390 +pkg debug/elf, const R_390_GOTPC = 14 +pkg debug/elf, const R_390_GOTPC R_390 +pkg debug/elf, const R_390_GOTPCDBL = 21 +pkg debug/elf, const R_390_GOTPCDBL R_390 +pkg debug/elf, const R_390_GOTPLT12 = 29 +pkg debug/elf, const R_390_GOTPLT12 R_390 +pkg debug/elf, const R_390_GOTPLT16 = 30 +pkg debug/elf, const R_390_GOTPLT16 R_390 +pkg debug/elf, const R_390_GOTPLT20 = 59 +pkg debug/elf, const R_390_GOTPLT20 R_390 +pkg debug/elf, const R_390_GOTPLT32 = 31 +pkg debug/elf, const R_390_GOTPLT32 R_390 +pkg debug/elf, const R_390_GOTPLT64 = 32 +pkg debug/elf, const R_390_GOTPLT64 R_390 +pkg debug/elf, const R_390_GOTPLTENT = 33 +pkg debug/elf, const R_390_GOTPLTENT R_390 +pkg debug/elf, const R_390_GOTPLTOFF16 = 34 +pkg debug/elf, const R_390_GOTPLTOFF16 R_390 +pkg debug/elf, const R_390_GOTPLTOFF32 = 35 +pkg debug/elf, const R_390_GOTPLTOFF32 R_390 +pkg debug/elf, const R_390_GOTPLTOFF64 = 36 +pkg debug/elf, const R_390_GOTPLTOFF64 R_390 +pkg debug/elf, const R_390_JMP_SLOT = 11 +pkg debug/elf, const R_390_JMP_SLOT R_390 +pkg debug/elf, const R_390_NONE = 0 +pkg debug/elf, const R_390_NONE R_390 +pkg debug/elf, const R_390_PC16 = 16 +pkg debug/elf, const R_390_PC16 R_390 +pkg debug/elf, const R_390_PC16DBL = 17 +pkg debug/elf, const R_390_PC16DBL R_390 +pkg debug/elf, const R_390_PC32 = 5 +pkg debug/elf, const R_390_PC32 R_390 +pkg debug/elf, const R_390_PC32DBL = 19 +pkg debug/elf, const R_390_PC32DBL R_390 +pkg debug/elf, const R_390_PC64 = 23 +pkg debug/elf, const R_390_PC64 R_390 +pkg debug/elf, const R_390_PLT16DBL = 18 +pkg debug/elf, const R_390_PLT16DBL R_390 +pkg debug/elf, const R_390_PLT32 = 8 +pkg debug/elf, const R_390_PLT32 R_390 +pkg debug/elf, const R_390_PLT32DBL = 20 +pkg debug/elf, const R_390_PLT32DBL R_390 +pkg debug/elf, const R_390_PLT64 = 25 +pkg debug/elf, const R_390_PLT64 R_390 +pkg debug/elf, const R_390_RELATIVE = 12 +pkg debug/elf, const R_390_RELATIVE R_390 +pkg debug/elf, const R_390_TLS_DTPMOD = 54 +pkg debug/elf, const R_390_TLS_DTPMOD R_390 +pkg debug/elf, const R_390_TLS_DTPOFF = 55 +pkg debug/elf, const R_390_TLS_DTPOFF R_390 +pkg debug/elf, const R_390_TLS_GD32 = 40 +pkg debug/elf, const R_390_TLS_GD32 R_390 +pkg debug/elf, const R_390_TLS_GD64 = 41 +pkg debug/elf, const R_390_TLS_GD64 R_390 +pkg debug/elf, const R_390_TLS_GDCALL = 38 +pkg debug/elf, const R_390_TLS_GDCALL R_390 +pkg debug/elf, const R_390_TLS_GOTIE12 = 42 +pkg debug/elf, const R_390_TLS_GOTIE12 R_390 +pkg debug/elf, const R_390_TLS_GOTIE20 = 60 +pkg debug/elf, const R_390_TLS_GOTIE20 R_390 +pkg debug/elf, const R_390_TLS_GOTIE32 = 43 +pkg debug/elf, const R_390_TLS_GOTIE32 R_390 +pkg debug/elf, const R_390_TLS_GOTIE64 = 44 +pkg debug/elf, const R_390_TLS_GOTIE64 R_390 +pkg debug/elf, const R_390_TLS_IE32 = 47 +pkg debug/elf, const R_390_TLS_IE32 R_390 +pkg debug/elf, const R_390_TLS_IE64 = 48 +pkg debug/elf, const R_390_TLS_IE64 R_390 +pkg debug/elf, const R_390_TLS_IEENT = 49 +pkg debug/elf, const R_390_TLS_IEENT R_390 +pkg debug/elf, const R_390_TLS_LDCALL = 39 +pkg debug/elf, const R_390_TLS_LDCALL R_390 +pkg debug/elf, const R_390_TLS_LDM32 = 45 +pkg debug/elf, const R_390_TLS_LDM32 R_390 +pkg debug/elf, const R_390_TLS_LDM64 = 46 +pkg debug/elf, const R_390_TLS_LDM64 R_390 +pkg debug/elf, const R_390_TLS_LDO32 = 52 +pkg debug/elf, const R_390_TLS_LDO32 R_390 +pkg debug/elf, const R_390_TLS_LDO64 = 53 +pkg debug/elf, const R_390_TLS_LDO64 R_390 +pkg debug/elf, const R_390_TLS_LE32 = 50 +pkg debug/elf, const R_390_TLS_LE32 R_390 +pkg debug/elf, const R_390_TLS_LE64 = 51 +pkg debug/elf, const R_390_TLS_LE64 R_390 +pkg debug/elf, const R_390_TLS_LOAD = 37 +pkg debug/elf, const R_390_TLS_LOAD R_390 +pkg debug/elf, const R_390_TLS_TPOFF = 56 +pkg debug/elf, const R_390_TLS_TPOFF R_390 +pkg debug/elf, method (R_390) GoString() string +pkg debug/elf, method (R_390) String() string +pkg debug/elf, type R_390 int +pkg encoding/json, method (*Encoder) SetEscapeHTML(bool) +pkg encoding/json, method (*Encoder) SetIndent(string, string) +pkg go/build, type Package struct, BinaryOnly bool +pkg go/build, type Package struct, CgoFFLAGS []string +pkg go/build, type Package struct, FFiles []string +pkg go/doc, type Example struct, Unordered bool +pkg io, const SeekCurrent = 1 +pkg io, const SeekCurrent ideal-int +pkg io, const SeekEnd = 2 +pkg io, const SeekEnd ideal-int +pkg io, const SeekStart = 0 +pkg io, const SeekStart ideal-int +pkg math/big, method (*Float) GobDecode([]uint8) error +pkg math/big, method (*Float) GobEncode() ([]uint8, error) +pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error) +pkg net/http, const StatusAlreadyReported = 208 +pkg net/http, const StatusAlreadyReported ideal-int +pkg net/http, const StatusFailedDependency = 424 +pkg net/http, const StatusFailedDependency ideal-int +pkg net/http, const StatusIMUsed = 226 +pkg net/http, const StatusIMUsed ideal-int +pkg net/http, const StatusInsufficientStorage = 507 +pkg net/http, const StatusInsufficientStorage ideal-int +pkg net/http, const StatusLocked = 423 +pkg net/http, const StatusLocked ideal-int +pkg net/http, const StatusLoopDetected = 508 +pkg net/http, const StatusLoopDetected ideal-int +pkg net/http, const StatusMultiStatus = 207 +pkg net/http, const StatusMultiStatus ideal-int +pkg net/http, const StatusNotExtended = 510 +pkg net/http, const StatusNotExtended ideal-int +pkg net/http, const StatusPermanentRedirect = 308 +pkg net/http, const StatusPermanentRedirect ideal-int +pkg net/http, const StatusProcessing = 102 +pkg net/http, const StatusProcessing ideal-int +pkg net/http, const StatusUnprocessableEntity = 422 +pkg net/http, const StatusUnprocessableEntity ideal-int +pkg net/http, const StatusUpgradeRequired = 426 +pkg net/http, const StatusUpgradeRequired ideal-int +pkg net/http, const StatusVariantAlsoNegotiates = 506 +pkg net/http, const StatusVariantAlsoNegotiates ideal-int +pkg net/http, method (*Request) Context() context.Context +pkg net/http, method (*Request) WithContext(context.Context) *Request +pkg net/http, type Request struct, Response *Response +pkg net/http, type Response struct, Uncompressed bool +pkg net/http, type Transport struct, DialContext func(context.Context, string, string) (net.Conn, error) +pkg net/http, type Transport struct, IdleConnTimeout time.Duration +pkg net/http, type Transport struct, MaxIdleConns int +pkg net/http, type Transport struct, MaxResponseHeaderBytes int64 +pkg net/http, var ErrUseLastResponse error +pkg net/http, var LocalAddrContextKey *contextKey +pkg net/http, var ServerContextKey *contextKey +pkg net/http/cgi, type Handler struct, Stderr io.Writer +pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request +pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response +pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace +pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context +pkg net/http/httptrace, type ClientTrace struct +pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error) +pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string) +pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo) +pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo) +pkg net/http/httptrace, type ClientTrace struct, GetConn func(string) +pkg net/http/httptrace, type ClientTrace struct, Got100Continue func() +pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo) +pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func() +pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error) +pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func() +pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func() +pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo) +pkg net/http/httptrace, type DNSDoneInfo struct +pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr +pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool +pkg net/http/httptrace, type DNSDoneInfo struct, Err error +pkg net/http/httptrace, type DNSStartInfo struct +pkg net/http/httptrace, type DNSStartInfo struct, Host string +pkg net/http/httptrace, type GotConnInfo struct +pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn +pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration +pkg net/http/httptrace, type GotConnInfo struct, Reused bool +pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool +pkg net/http/httptrace, type WroteRequestInfo struct +pkg net/http/httptrace, type WroteRequestInfo struct, Err error +pkg net/url, type URL struct, ForceQuery bool +pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd +pkg os/user, func LookupGroup(string) (*Group, error) +pkg os/user, func LookupGroupId(string) (*Group, error) +pkg os/user, method (*User) GroupIds() ([]string, error) +pkg os/user, method (UnknownGroupError) Error() string +pkg os/user, method (UnknownGroupIdError) Error() string +pkg os/user, type Group struct +pkg os/user, type Group struct, Gid string +pkg os/user, type Group struct, Name string +pkg os/user, type UnknownGroupError string +pkg os/user, type UnknownGroupIdError string +pkg reflect, func StructOf([]StructField) Type +pkg reflect, method (StructTag) Lookup(string) (string, bool) +pkg runtime, func CallersFrames([]uintptr) *Frames +pkg runtime, func KeepAlive(interface{}) +pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) +pkg runtime, method (*Frames) Next() (Frame, bool) +pkg runtime, type Frame struct +pkg runtime, type Frame struct, Entry uintptr +pkg runtime, type Frame struct, File string +pkg runtime, type Frame struct, Func *Func +pkg runtime, type Frame struct, Function string +pkg runtime, type Frame struct, Line int +pkg runtime, type Frame struct, PC uintptr +pkg runtime, type Frames struct +pkg strings, method (*Reader) Reset(string) +pkg syscall (linux-386), type SysProcAttr struct, Unshareflags uintptr +pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshareflags uintptr +pkg syscall (linux-amd64), type SysProcAttr struct, Unshareflags uintptr +pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshareflags uintptr +pkg syscall (linux-arm), type SysProcAttr struct, Unshareflags uintptr +pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshareflags uintptr +pkg testing, method (*B) Run(string, func(*B)) bool +pkg testing, method (*T) Run(string, func(*T)) bool +pkg testing, type InternalExample struct, Unordered bool diff --git a/api/next.txt b/api/next.txt index 5ae56c126a..e69de29bb2 100644 --- a/api/next.txt +++ b/api/next.txt @@ -1,251 +0,0 @@ -pkg bytes, func ContainsAny([]uint8, string) bool -pkg bytes, func ContainsRune([]uint8, int32) bool -pkg bytes, method (*Reader) Reset([]uint8) -pkg compress/flate, const HuffmanOnly = -2 -pkg compress/flate, const HuffmanOnly ideal-int -pkg context, func Background() Context -pkg context, func TODO() Context -pkg context, func WithCancel(Context) (Context, CancelFunc) -pkg context, func WithDeadline(Context, time.Time) (Context, CancelFunc) -pkg context, func WithTimeout(Context, time.Duration) (Context, CancelFunc) -pkg context, func WithValue(Context, interface{}, interface{}) Context -pkg context, type CancelFunc func() -pkg context, type Context interface { Deadline, Done, Err, Value } -pkg context, type Context interface, Deadline() (time.Time, bool) -pkg context, type Context interface, Done() <-chan struct -pkg context, type Context interface, Err() error -pkg context, type Context interface, Value(interface{}) interface{} -pkg context, var Canceled error -pkg context, var DeadlineExceeded error -pkg crypto/tls, const RenegotiateFreelyAsClient = 2 -pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport -pkg crypto/tls, const RenegotiateNever = 0 -pkg crypto/tls, const RenegotiateNever RenegotiationSupport -pkg crypto/tls, const RenegotiateOnceAsClient = 1 -pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport -pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool -pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport -pkg crypto/tls, type RenegotiationSupport int -pkg crypto/x509, func SystemCertPool() (*CertPool, error) -pkg crypto/x509, type SystemRootsError struct, Err error -pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error) -pkg debug/dwarf, method (*Reader) SeekPC(uint64) (*Entry, error) -pkg debug/elf, const R_390_12 = 2 -pkg debug/elf, const R_390_12 R_390 -pkg debug/elf, const R_390_16 = 3 -pkg debug/elf, const R_390_16 R_390 -pkg debug/elf, const R_390_20 = 57 -pkg debug/elf, const R_390_20 R_390 -pkg debug/elf, const R_390_32 = 4 -pkg debug/elf, const R_390_32 R_390 -pkg debug/elf, const R_390_64 = 22 -pkg debug/elf, const R_390_64 R_390 -pkg debug/elf, const R_390_8 = 1 -pkg debug/elf, const R_390_8 R_390 -pkg debug/elf, const R_390_COPY = 9 -pkg debug/elf, const R_390_COPY R_390 -pkg debug/elf, const R_390_GLOB_DAT = 10 -pkg debug/elf, const R_390_GLOB_DAT R_390 -pkg debug/elf, const R_390_GOT12 = 6 -pkg debug/elf, const R_390_GOT12 R_390 -pkg debug/elf, const R_390_GOT16 = 15 -pkg debug/elf, const R_390_GOT16 R_390 -pkg debug/elf, const R_390_GOT20 = 58 -pkg debug/elf, const R_390_GOT20 R_390 -pkg debug/elf, const R_390_GOT32 = 7 -pkg debug/elf, const R_390_GOT32 R_390 -pkg debug/elf, const R_390_GOT64 = 24 -pkg debug/elf, const R_390_GOT64 R_390 -pkg debug/elf, const R_390_GOTENT = 26 -pkg debug/elf, const R_390_GOTENT R_390 -pkg debug/elf, const R_390_GOTOFF = 13 -pkg debug/elf, const R_390_GOTOFF R_390 -pkg debug/elf, const R_390_GOTOFF16 = 27 -pkg debug/elf, const R_390_GOTOFF16 R_390 -pkg debug/elf, const R_390_GOTOFF64 = 28 -pkg debug/elf, const R_390_GOTOFF64 R_390 -pkg debug/elf, const R_390_GOTPC = 14 -pkg debug/elf, const R_390_GOTPC R_390 -pkg debug/elf, const R_390_GOTPCDBL = 21 -pkg debug/elf, const R_390_GOTPCDBL R_390 -pkg debug/elf, const R_390_GOTPLT12 = 29 -pkg debug/elf, const R_390_GOTPLT12 R_390 -pkg debug/elf, const R_390_GOTPLT16 = 30 -pkg debug/elf, const R_390_GOTPLT16 R_390 -pkg debug/elf, const R_390_GOTPLT20 = 59 -pkg debug/elf, const R_390_GOTPLT20 R_390 -pkg debug/elf, const R_390_GOTPLT32 = 31 -pkg debug/elf, const R_390_GOTPLT32 R_390 -pkg debug/elf, const R_390_GOTPLT64 = 32 -pkg debug/elf, const R_390_GOTPLT64 R_390 -pkg debug/elf, const R_390_GOTPLTENT = 33 -pkg debug/elf, const R_390_GOTPLTENT R_390 -pkg debug/elf, const R_390_GOTPLTOFF16 = 34 -pkg debug/elf, const R_390_GOTPLTOFF16 R_390 -pkg debug/elf, const R_390_GOTPLTOFF32 = 35 -pkg debug/elf, const R_390_GOTPLTOFF32 R_390 -pkg debug/elf, const R_390_GOTPLTOFF64 = 36 -pkg debug/elf, const R_390_GOTPLTOFF64 R_390 -pkg debug/elf, const R_390_JMP_SLOT = 11 -pkg debug/elf, const R_390_JMP_SLOT R_390 -pkg debug/elf, const R_390_NONE = 0 -pkg debug/elf, const R_390_NONE R_390 -pkg debug/elf, const R_390_PC16 = 16 -pkg debug/elf, const R_390_PC16 R_390 -pkg debug/elf, const R_390_PC16DBL = 17 -pkg debug/elf, const R_390_PC16DBL R_390 -pkg debug/elf, const R_390_PC32 = 5 -pkg debug/elf, const R_390_PC32 R_390 -pkg debug/elf, const R_390_PC32DBL = 19 -pkg debug/elf, const R_390_PC32DBL R_390 -pkg debug/elf, const R_390_PC64 = 23 -pkg debug/elf, const R_390_PC64 R_390 -pkg debug/elf, const R_390_PLT16DBL = 18 -pkg debug/elf, const R_390_PLT16DBL R_390 -pkg debug/elf, const R_390_PLT32 = 8 -pkg debug/elf, const R_390_PLT32 R_390 -pkg debug/elf, const R_390_PLT32DBL = 20 -pkg debug/elf, const R_390_PLT32DBL R_390 -pkg debug/elf, const R_390_PLT64 = 25 -pkg debug/elf, const R_390_PLT64 R_390 -pkg debug/elf, const R_390_RELATIVE = 12 -pkg debug/elf, const R_390_RELATIVE R_390 -pkg debug/elf, const R_390_TLS_DTPMOD = 54 -pkg debug/elf, const R_390_TLS_DTPMOD R_390 -pkg debug/elf, const R_390_TLS_DTPOFF = 55 -pkg debug/elf, const R_390_TLS_DTPOFF R_390 -pkg debug/elf, const R_390_TLS_GD32 = 40 -pkg debug/elf, const R_390_TLS_GD32 R_390 -pkg debug/elf, const R_390_TLS_GD64 = 41 -pkg debug/elf, const R_390_TLS_GD64 R_390 -pkg debug/elf, const R_390_TLS_GDCALL = 38 -pkg debug/elf, const R_390_TLS_GDCALL R_390 -pkg debug/elf, const R_390_TLS_GOTIE12 = 42 -pkg debug/elf, const R_390_TLS_GOTIE12 R_390 -pkg debug/elf, const R_390_TLS_GOTIE20 = 60 -pkg debug/elf, const R_390_TLS_GOTIE20 R_390 -pkg debug/elf, const R_390_TLS_GOTIE32 = 43 -pkg debug/elf, const R_390_TLS_GOTIE32 R_390 -pkg debug/elf, const R_390_TLS_GOTIE64 = 44 -pkg debug/elf, const R_390_TLS_GOTIE64 R_390 -pkg debug/elf, const R_390_TLS_IE32 = 47 -pkg debug/elf, const R_390_TLS_IE32 R_390 -pkg debug/elf, const R_390_TLS_IE64 = 48 -pkg debug/elf, const R_390_TLS_IE64 R_390 -pkg debug/elf, const R_390_TLS_IEENT = 49 -pkg debug/elf, const R_390_TLS_IEENT R_390 -pkg debug/elf, const R_390_TLS_LDCALL = 39 -pkg debug/elf, const R_390_TLS_LDCALL R_390 -pkg debug/elf, const R_390_TLS_LDM32 = 45 -pkg debug/elf, const R_390_TLS_LDM32 R_390 -pkg debug/elf, const R_390_TLS_LDM64 = 46 -pkg debug/elf, const R_390_TLS_LDM64 R_390 -pkg debug/elf, const R_390_TLS_LDO32 = 52 -pkg debug/elf, const R_390_TLS_LDO32 R_390 -pkg debug/elf, const R_390_TLS_LDO64 = 53 -pkg debug/elf, const R_390_TLS_LDO64 R_390 -pkg debug/elf, const R_390_TLS_LE32 = 50 -pkg debug/elf, const R_390_TLS_LE32 R_390 -pkg debug/elf, const R_390_TLS_LE64 = 51 -pkg debug/elf, const R_390_TLS_LE64 R_390 -pkg debug/elf, const R_390_TLS_LOAD = 37 -pkg debug/elf, const R_390_TLS_LOAD R_390 -pkg debug/elf, const R_390_TLS_TPOFF = 56 -pkg debug/elf, const R_390_TLS_TPOFF R_390 -pkg debug/elf, method (R_390) GoString() string -pkg debug/elf, method (R_390) String() string -pkg debug/elf, type R_390 int -pkg encoding/json, method (*Encoder) SetEscapeHTML(bool) -pkg encoding/json, method (*Encoder) SetIndent(string, string) -pkg go/build, type Package struct, BinaryOnly bool -pkg go/build, type Package struct, CgoFFLAGS []string -pkg go/build, type Package struct, FFiles []string -pkg go/doc, type Example struct, Unordered bool -pkg io, const SeekCurrent = 1 -pkg io, const SeekCurrent ideal-int -pkg io, const SeekEnd = 2 -pkg io, const SeekEnd ideal-int -pkg io, const SeekStart = 0 -pkg io, const SeekStart ideal-int -pkg math/big, method (*Float) GobDecode([]uint8) error -pkg math/big, method (*Float) GobEncode() ([]uint8, error) -pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error) -pkg net/http, method (*Request) Context() context.Context -pkg net/http, method (*Request) WithContext(context.Context) *Request -pkg net/http, type Request struct, Response *Response -pkg net/http, type Response struct, Uncompressed bool -pkg net/http, type Transport struct, Dialer *net.Dialer -pkg net/http, type Transport struct, IdleConnTimeout time.Duration -pkg net/http, type Transport struct, MaxIdleConns int -pkg net/http, type Transport struct, MaxResponseHeaderBytes int64 -pkg net/http, var ErrUseLastResponse error -pkg net/http, var LocalAddrContextKey *contextKey -pkg net/http, var ServerContextKey *contextKey -pkg net/http/cgi, type Handler struct, Stderr io.Writer -pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request -pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response -pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace -pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context -pkg net/http/httptrace, type ClientTrace struct -pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error) -pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string) -pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo) -pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo) -pkg net/http/httptrace, type ClientTrace struct, GetConn func(string) -pkg net/http/httptrace, type ClientTrace struct, Got100Continue func() -pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo) -pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func() -pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error) -pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func() -pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func() -pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo) -pkg net/http/httptrace, type DNSDoneInfo struct -pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr -pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool -pkg net/http/httptrace, type DNSDoneInfo struct, Err error -pkg net/http/httptrace, type DNSStartInfo struct -pkg net/http/httptrace, type DNSStartInfo struct, Host string -pkg net/http/httptrace, type GotConnInfo struct -pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn -pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration -pkg net/http/httptrace, type GotConnInfo struct, Reused bool -pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool -pkg net/http/httptrace, type WroteRequestInfo struct -pkg net/http/httptrace, type WroteRequestInfo struct, Err error -pkg net/url, type URL struct, ForceQuery bool -pkg os, method (*File) Size() (int64, error) -pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd -pkg os/user, func LookupGroup(string) (*Group, error) -pkg os/user, func LookupGroupId(string) (*Group, error) -pkg os/user, method (*User) GroupIds() ([]string, error) -pkg os/user, method (UnknownGroupError) Error() string -pkg os/user, method (UnknownGroupIdError) Error() string -pkg os/user, type Group struct -pkg os/user, type Group struct, Gid string -pkg os/user, type Group struct, Name string -pkg os/user, type UnknownGroupError string -pkg os/user, type UnknownGroupIdError string -pkg reflect, func StructOf([]StructField) Type -pkg reflect, method (StructTag) Lookup(string) (string, bool) -pkg runtime, func CallersFrames([]uintptr) *Frames -pkg runtime, func KeepAlive(interface{}) -pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) -pkg runtime, method (*Frames) Next() (Frame, bool) -pkg runtime, type Frame struct -pkg runtime, type Frame struct, Entry uintptr -pkg runtime, type Frame struct, File string -pkg runtime, type Frame struct, Func *Func -pkg runtime, type Frame struct, Function string -pkg runtime, type Frame struct, Line int -pkg runtime, type Frame struct, PC uintptr -pkg runtime, type Frames struct -pkg strings, method (*Reader) Reset(string) -pkg syscall (linux-386), type SysProcAttr struct, Unshare uintptr -pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshare uintptr -pkg syscall (linux-amd64), type SysProcAttr struct, Unshare uintptr -pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshare uintptr -pkg syscall (linux-arm), type SysProcAttr struct, Unshare uintptr -pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshare uintptr -pkg testing, method (*B) Run(string, func(*B)) bool -pkg testing, method (*T) Run(string, func(*T)) bool -pkg testing, type InternalExample struct, Unordered bool diff --git a/doc/go1.7.html b/doc/go1.7.html index 46c575452f..0acfb6c8fc 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -33,7 +33,7 @@ Go 1.7 has NOT yet been released. By our regular schedule, it is expected some time in August 2016.

- +

Introduction to Go 1.7

@@ -95,7 +95,7 @@ The OpenBSD port now requires OpenBSD 5.6 or later, for access to the Tools -

Assembler

+

Assembler

For 64-bit ARM systems, the vector register names have been @@ -185,7 +185,18 @@ built with Go 1.6, sometimes by as much as 20-30%.

-

Cgo

+

+On x86-64 systems, Go programs now maintain stack frame pointers +as expected by profiling tools like Linux's perf and Intel's VTune, +making it easier to analyze and optimize Go programs using these tools. +The frame pointer maintenance has a small run-time overhead that varies +but averages around 2%. We hope to reduce this cost in future releases. +To build a toolchain that does not use frame pointers, set +GOEXPERIMENT=noframepointer when running +make.bash, make.bat, or make.rc. +

+ +

Cgo

Packages using cgo may now include @@ -219,7 +230,7 @@ GCC release 6 contains the Go 1.6.1 version of gccgo. The next release, GCC 7, will likely have the Go 1.8 version of gccgo.

-

Go command

+

Go command

The go command's basic operation @@ -259,7 +270,7 @@ will not work with such packages, and there are no plans to support such packages in the “go get” command.

-

Go doc

+

Go doc

The “go doc” command @@ -267,7 +278,7 @@ now groups constructors with the type they construct, following godoc.

-

Go vet

+

Go vet

The “go vet” command @@ -277,14 +288,14 @@ To avoid confusion with the new -tests check, the old, unadvertised -test option has been removed; it was equivalent to -all -shadow.

-

Go tool dist

+

Go tool dist

The new subcommand “go tool dist list” prints all supported operating system/architecture pairs.

-

Go tool trace

+

Go tool trace

The “go tool trace” command, @@ -324,7 +335,7 @@ the code generation changes alone typically reduce program CPU time by 5-35%.

- + There have been significant optimizations bringing more than 10% improvements to implementations in the crypto/sha1, @@ -351,7 +362,7 @@ packages.

Go 1.7 moves the golang.org/x/net/context package into the standard library as context. -This allows the use of contexts for cancellation, timeouts, and passing +This allows the use of contexts for cancelation, timeouts, and passing request-scoped data in other standard library packages, including net, @@ -368,6 +379,13 @@ and the Go blog post “Go Concurrent Patterns: Context.”

+

HTTP Tracing

+ +

+Go 1.7 introduces net/http/httptrace, +a package that provides mechanisms for tracing events within HTTP requests. +

+

Testing

@@ -383,7 +401,8 @@ See the package document

All panics started by the runtime now use panic values -that implement both the builtin error, +that implement both the +builtin error, and runtime.Error, as @@ -451,7 +470,7 @@ made with the Go 1 promise of compatibility in mind.

-
bufio
+
bufio

@@ -463,8 +482,9 @@ it would return an empty slice and the error ErrBufferFull. Now it returns the entire underlying buffer, still accompanied by the error ErrBufferFull.

+
-
bytes
+
bytes

@@ -482,7 +502,7 @@ In previous releases of Go, if were asked for zero bytes with no data remaining, it would return a count of 0 and no error. Now it returns a count of 0 and the error -io.EOF . +io.EOF.

@@ -491,8 +511,9 @@ The Reset to allow reuse of a Reader.

+
-
compress/flate
+
compress/flate

@@ -521,9 +542,26 @@ that applies Huffman but not Lempel-Ziv encoding. but at the cost of producing compressed outputs that are 20-40% larger than those generated by the new BestSpeed.

-
-
crypto/tls
+

+It is important to note that both +BestSpeed and HuffmanOnly produce a compressed output that is +RFC 1951 compliant. +In other words, any valid DEFLATE decompressor will continue to be able to decompress these outputs. +

+ +

+Lastly, there is a minor change to the decompressor's implementation of +io.Reader. In previous versions, +the decompressor deferred reporting +io.EOF until exactly no more bytes could be read. +Now, it reports +io.EOF more eagerly when reading the last set of bytes. +

+ +
+ +
crypto/tls

@@ -559,8 +597,9 @@ When generating self-signed certificates, the package no longer sets the “Authority Key Identifier” field by default.

+
-
crypto/x509
+
crypto/x509

@@ -571,8 +610,9 @@ There is also a new associated error type SystemRootsError.

+
-
debug/dwarf
+
debug/dwarf

@@ -586,8 +626,9 @@ help to find the compilation unit to pass to a and to identify the specific function for a given program counter.

+
-
debug/elf
+
debug/elf

@@ -597,8 +638,9 @@ and its many predefined constants support the S390 port.

+
-
encoding/asn1
+
encoding/asn1

@@ -606,8 +648,9 @@ The ASN.1 decoder now rejects non-minimal integer encodings. This may cause the package to reject some invalid but formerly accepted ASN.1 data.

+
-
encoding/json
+
encoding/json

@@ -638,23 +681,15 @@ maps using keys with string types. Go 1.7 adds support for maps using keys with integer types: the encoding uses a quoted decimal representation as the JSON key. Go 1.7 also adds support for encoding maps using non-string keys that implement -MarshalJSON -(see -Marshaler) -or -MarshalText +the MarshalText (see encoding.TextMarshaler) -methods, +method, as well as support for decoding maps using non-string keys that implement -UnmarshalJSON -(see -Unmarshaler) -or -UnmarshalText +the UnmarshalText (see encoding.TextUnmarshaler) -methods. +method. These methods are ignored for keys with string types in order to preserve the encoding and decoding used in earlier versions of Go.

@@ -679,8 +714,9 @@ so this change should be semantically backwards compatible with earlier versions even though it does change the chosen encoding.

+
-
go/build
+
go/build

@@ -691,8 +727,9 @@ the adds new fields BinaryOnly, CgoFFLAGS, and FFiles.

+
-
go/doc
+
go/doc

@@ -701,8 +738,9 @@ To support the corresponding change in go test describ indicating whether the example may generate its output lines in any order.

+
-
io
+
io

@@ -715,8 +753,9 @@ These constants are preferred over os.SEEK_SET, os.SEEK_CUR

+
-
math/big
+
math/big

@@ -729,8 +768,9 @@ so that values of type Float can now be encoded and decoded using t package.

+
-
mime/multipart
+
mime/multipart

@@ -741,8 +781,9 @@ Previously, iteration over a map caused the section header to use a non-deterministic order.

+
-
net
+
net

@@ -769,13 +810,14 @@ Go 1.7 adds the hexadecimal encoding of the bytes, as in "?12ab".

The pure Go name resolution -implementation now respects nsswtch.conf's +implementation now respects nsswitch.conf's stated preference for the priority of DNS lookups compared to local file (that is, /etc/hosts) lookups.

+
-
net/http
+
net/http

@@ -847,13 +889,13 @@ as req.Response. Since Go 1, the default behavior of the HTTP client is to request server-side compression using the Accept-Encoding request header -and then to uncompress the response body transparently, +and then to decompress the response body transparently, and this behavior is adjustable using the Transport's DisableCompression field. In Go 1.7, to aid the implementation of HTTP proxies, the Response's new Uncompressed field reports whether -this transparent uncompression took place. +this transparent decompression took place.

@@ -861,8 +903,9 @@ this transparent uncompression took place. adds support for a few new audio and video content types.

+
-
net/http/cgi
+
net/http/cgi

@@ -875,8 +918,9 @@ standard error away from the host process's standard error.

+
-
net/http/httptest
+
net/http/httptest

@@ -900,8 +944,9 @@ instead of accessing ResponseRecorder's HeaderMap directly.

+
-
net/http/httputil
+
net/http/httputil

@@ -924,8 +969,9 @@ and instead.

+
-
net/http/pprof
+
net/http/pprof

@@ -935,8 +981,9 @@ allowing collection of traces for intervals smaller than one second. This is especially useful on busy servers.

+
-
net/mail
+
net/mail

@@ -947,11 +994,21 @@ For compatibility with older mail parsers, the address encoder, namely Address's String method, -continues to escape all UTF-8 text following RFC 5322, +continues to escape all UTF-8 text following RFC 5322. +

+ +

+The ParseAddress +function and +the AddressParser.Parse +method are stricter. +They used to ignore any characters following an e-mail address, but +will now return an error for anything other than whitespace.

+
-
net/url
+
net/url

@@ -963,19 +1020,11 @@ in order to distinguish URLs without query strings (like /search) from URLs with empty query strings (like /search?).

+
-
os
+
os
-

-The -File -type adds a new -Size -method, so that File implements the new -SizedReaderAt method. -

-

IsExists now returns true for syscall.ENOTEMPTY, on systems where that error exists. @@ -988,8 +1037,9 @@ making the implementation behave as on non-Windows systems.

+
-
os/exec
+
os/exec

@@ -1000,8 +1050,9 @@ is like Command but includes a context that can be used to cancel the command execution.

+
-
os/user
+
os/user

@@ -1020,8 +1071,9 @@ and the new field GroupIds in the User struct, provides access to system-specific user group information.

+
-
reflect
+
reflect

@@ -1068,8 +1120,9 @@ methods of no longer return or count unexported methods.

+
-
strings
+
strings

@@ -1079,7 +1132,7 @@ In previous releases of Go, if were asked for zero bytes with no data remaining, it would return a count of 0 and no error. Now it returns a count of 0 and the error -io.EOF . +io.EOF.

@@ -1088,8 +1141,9 @@ The Reset to allow reuse of a Reader.

+
-
time
+
time

@@ -1112,8 +1166,9 @@ cannot be found, for example on Windows. The Windows time zone abbreviation list has also been updated.

+
-
syscall
+
syscall

@@ -1121,7 +1176,7 @@ On Linux, the SysProcAttr struct (as used in os/exec.Cmd's SysProcAttr field) -has a new Unshare field. +has a new Unshareflags field. If the field is nonzero, the child process created by ForkExec (as used in exec.Cmd's Run method) @@ -1130,3 +1185,4 @@ will call the system call before executing the new program.

+
diff --git a/doc/go_spec.html b/doc/go_spec.html index 13dae09420..731186e66b 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -4672,6 +4672,8 @@ Cases then match actual types T against the dynamic type of the expression x. As with type assertions, x must be of interface type, and each non-interface type T listed in a case must implement the type of x. +The types listed in the cases of a type switch must all be +different.

@@ -4696,6 +4698,7 @@ in the TypeSwitchGuard.
 The type in a case may be nil;
 that case is used when the expression in the TypeSwitchGuard
 is a nil interface value.
+There may be at most one nil case.
 

diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go index 6db38c2cc5..ebff845154 100644 --- a/misc/android/go_android_exec.go +++ b/misc/android/go_android_exec.go @@ -91,11 +91,11 @@ func main() { run("shell", "rm", "-rf", deviceGotmp) // Clean up. - output = output[strings.LastIndex(output, "\n")+1:] - if !strings.HasPrefix(output, exitstr) { + exitIdx := strings.LastIndex(output, exitstr) + if exitIdx == -1 { log.Fatalf("no exit code: %q", output) } - code, err := strconv.Atoi(output[len(exitstr):]) + code, err := strconv.Atoi(output[exitIdx+len(exitstr):]) if err != nil { log.Fatalf("bad exit code: %v", err) } diff --git a/misc/cgo/errors/issue13830.go b/misc/cgo/errors/issue13830.go new file mode 100644 index 0000000000..ac20c82b81 --- /dev/null +++ b/misc/cgo/errors/issue13830.go @@ -0,0 +1,26 @@ +// Copyright 2016 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. + +// cgo converts C void* to Go unsafe.Pointer, so despite appearances C +// void** is Go *unsafe.Pointer. This test verifies that we detect the +// problem at build time. + +package main + +// typedef void v; +// void F(v** p) {} +import "C" + +import "unsafe" + +type v [0]byte + +func f(p **v) { + C.F((**C.v)(unsafe.Pointer(p))) // ERROR HERE +} + +func main() { + var p *v + f(&p) +} diff --git a/misc/cgo/errors/ptr.go b/misc/cgo/errors/ptr.go index 27eb78e36c..e39f0413e4 100644 --- a/misc/cgo/errors/ptr.go +++ b/misc/cgo/errors/ptr.go @@ -314,6 +314,14 @@ var ptrTests = []ptrTest{ body: `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`, fail: false, }, + { + // Check deferred pointers when they are used, not + // when the defer statement is run. + name: "defer", + c: `typedef struct s { int *p; } s; void f(s *ps) {}`, + body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`, + fail: true, + }, } func main() { diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash index 643d038205..429cec7627 100755 --- a/misc/cgo/errors/test.bash +++ b/misc/cgo/errors/test.bash @@ -18,16 +18,16 @@ expect() { file=$1 shift if go build $file >errs 2>&1; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded + echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded exit 1 fi if ! test -s errs; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none + echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file but saw none exit 1 fi for error; do if ! fgrep $error errs >/dev/null 2>&1; then - echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output to contain \"$error\" but saw: + echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file to contain \"$error\" but saw: cat 1>&2 errs exit 1 fi @@ -44,6 +44,7 @@ check issue11097b.go expect issue13129.go C.ushort check issue13423.go expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble +check issue13830.go if ! go build issue14669.go; then exit 1 diff --git a/misc/cgo/test/cgo_stubs_android_test.go b/misc/cgo/test/cgo_stubs_android_test.go new file mode 100644 index 0000000000..710e094cf7 --- /dev/null +++ b/misc/cgo/test/cgo_stubs_android_test.go @@ -0,0 +1,13 @@ +// 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. + +package cgotest + +import "testing" + +// Stubs for tests that fails to build on Android +func test6997(t *testing.T) {} +func test3775(t *testing.T) {} +func test8694(t *testing.T) {} +func testSigaltstack(t *testing.T) {} diff --git a/misc/cgo/test/cthread.go b/misc/cgo/test/cthread.go index 1ca182c75e..af44911756 100644 --- a/misc/cgo/test/cthread.go +++ b/misc/cgo/test/cthread.go @@ -8,6 +8,7 @@ package cgotest import "C" import ( + "runtime" "sync" "testing" ) @@ -30,6 +31,9 @@ func Add(x int) { } func testCthread(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add") + } sum.i = 0 C.doAdd(10, 6) diff --git a/misc/cgo/test/issue3775.go b/misc/cgo/test/issue3775.go index 8f81854195..5aca7602c0 100644 --- a/misc/cgo/test/issue3775.go +++ b/misc/cgo/test/issue3775.go @@ -1,3 +1,5 @@ +// +build !android + package cgotest /* diff --git a/misc/cgo/test/issue6997_linux.c b/misc/cgo/test/issue6997_linux.c index 1d5fb2ac7e..de803d296e 100644 --- a/misc/cgo/test/issue6997_linux.c +++ b/misc/cgo/test/issue6997_linux.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !android + #include #include #include diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go index aaa51dcbf8..0c98ea0794 100644 --- a/misc/cgo/test/issue6997_linux.go +++ b/misc/cgo/test/issue6997_linux.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !android + // Test that pthread_cancel works as expected // (NPTL uses SIGRTMIN to implement thread cancelation) // See https://golang.org/issue/6997 diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go index 94ea0b6fa3..e4cbf1d926 100644 --- a/misc/cgo/test/issue7978.go +++ b/misc/cgo/test/issue7978.go @@ -103,6 +103,9 @@ func test7978(t *testing.T) { if C.HAS_SYNC_FETCH_AND_ADD == 0 { t.Skip("clang required for __sync_fetch_and_add support on darwin/arm") } + if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("GOTRACEBACK is not passed on to the exec wrapper") + } if os.Getenv("GOTRACEBACK") != "2" { t.Fatalf("GOTRACEBACK must be 2") } diff --git a/misc/cgo/test/issue8694.go b/misc/cgo/test/issue8694.go index 00ab7d5202..89be7ea090 100644 --- a/misc/cgo/test/issue8694.go +++ b/misc/cgo/test/issue8694.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !android + package cgotest /* diff --git a/misc/cgo/test/issue9400/asm_386.s b/misc/cgo/test/issue9400/asm_386.s index 83ca38531a..7f158b5c39 100644 --- a/misc/cgo/test/issue9400/asm_386.s +++ b/misc/cgo/test/issue9400/asm_386.s @@ -7,17 +7,18 @@ #include "textflag.h" TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0 + MOVL $·Baton(SB), BX // Rewind stack pointer so anything that happens on the stack // will clobber the test pattern created by the caller ADDL $(1024 * 8), SP // Ask signaller to setgid - MOVL $1, ·Baton(SB) + MOVL $1, (BX) // Wait for setgid completion loop: PAUSE - MOVL ·Baton(SB), AX + MOVL (BX), AX CMPL AX, $0 JNE loop diff --git a/misc/cgo/test/sigaltstack.go b/misc/cgo/test/sigaltstack.go index b641ff6037..b16adc7d88 100644 --- a/misc/cgo/test/sigaltstack.go +++ b/misc/cgo/test/sigaltstack.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows +// +build !windows,!android // Test that the Go runtime still works if C code changes the signal stack. diff --git a/misc/cgo/testsanitizers/test.bash b/misc/cgo/testsanitizers/test.bash index c30df3b6c2..78747d141a 100755 --- a/misc/cgo/testsanitizers/test.bash +++ b/misc/cgo/testsanitizers/test.bash @@ -111,50 +111,52 @@ if test "$tsan" = "yes"; then rm -f ${TMPDIR}/testsanitizers$$* fi -if test "$tsan" = "yes"; then +# Run a TSAN test. +# $1 test name +# $2 environment variables +# $3 go run args +testtsan() { err=${TMPDIR}/tsanerr$$.out - - if ! go run tsan.go 2>$err; then + if ! env $2 go run $3 $1 2>$err; then cat $err - echo "FAIL: tsan" + echo "FAIL: $1" status=1 elif grep -i warning $err >/dev/null 2>&1; then cat $err - echo "FAIL: tsan" + echo "FAIL: $1" status=1 fi - - if ! go run tsan2.go 2>$err; then - cat $err - echo "FAIL: tsan2" - status=1 - elif grep -i warning $err >/dev/null 2>&1; then - cat $err - echo "FAIL: tsan2" - status=1 - fi - - if ! go run tsan3.go 2>$err; then - cat $err - echo "FAIL: tsan3" - status=1 - elif grep -i warning $err >/dev/null 2>&1; then - cat $err - echo "FAIL: tsan3" - status=1 - fi - - if ! go run tsan4.go 2>$err; then - cat $err - echo "FAIL: tsan4" - status=1 - elif grep -i warning $err >/dev/null 2>&1; then - cat $err - echo "FAIL: tsan4" - status=1 - fi - rm -f $err +} + +if test "$tsan" = "yes"; then + testtsan tsan.go + testtsan tsan2.go + testtsan tsan3.go + testtsan tsan4.go + + # These tests are only reliable using clang or GCC version 7 or later. + # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use. + ok=false + if ${CC} --version | grep clang >/dev/null 2>&1; then + ok=true + else + ver=$($CC -dumpversion) + major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') + if test "$major" -lt 7; then + echo "skipping remaining TSAN tests: GCC version $major (older than 7)" + else + ok=true + fi + fi + + if test "$ok" = "true"; then + # This test requires rebuilding os/user with -fsanitize=thread. + testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + + # This test requires rebuilding runtime/cgo with -fsanitize=thread. + testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + fi fi exit $status diff --git a/misc/cgo/testsanitizers/tsan5.go b/misc/cgo/testsanitizers/tsan5.go new file mode 100644 index 0000000000..1214a7743b --- /dev/null +++ b/misc/cgo/testsanitizers/tsan5.go @@ -0,0 +1,51 @@ +// Copyright 2016 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 + +// Check that calls to C.malloc/C.free do not collide with the calls +// made by the os/user package. + +// #cgo CFLAGS: -fsanitize=thread +// #cgo LDFLAGS: -fsanitize=thread +// #include +import "C" + +import ( + "fmt" + "os" + "os/user" + "runtime" + "sync" +) + +func main() { + u, err := user.Current() + if err != nil { + fmt.Fprintln(os.Stderr, err) + // Let the test pass. + os.Exit(0) + } + + var wg sync.WaitGroup + for i := 0; i < 20; i++ { + wg.Add(2) + go func() { + defer wg.Done() + for i := 0; i < 1000; i++ { + user.Lookup(u.Username) + runtime.Gosched() + } + }() + go func() { + defer wg.Done() + for i := 0; i < 1000; i++ { + p := C.malloc(C.size_t(len(u.Username) + 1)) + runtime.Gosched() + C.free(p) + } + }() + } + wg.Wait() +} diff --git a/misc/cgo/testsanitizers/tsan6.go b/misc/cgo/testsanitizers/tsan6.go new file mode 100644 index 0000000000..c96f08d2f3 --- /dev/null +++ b/misc/cgo/testsanitizers/tsan6.go @@ -0,0 +1,49 @@ +// Copyright 2016 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 + +// Check that writes to Go allocated memory, with Go synchronization, +// do not look like a race. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +void f(char *p) { + *p = 1; +} +*/ +import "C" + +import ( + "runtime" + "sync" +) + +func main() { + var wg sync.WaitGroup + var mu sync.Mutex + c := make(chan []C.char, 100) + for i := 0; i < 10; i++ { + wg.Add(2) + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + c <- make([]C.char, 4096) + runtime.Gosched() + } + }() + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + p := &(<-c)[0] + mu.Lock() + C.f(p) + mu.Unlock() + } + }() + } + wg.Wait() +} diff --git a/misc/cgo/testshared/src/depBase/dep.go b/misc/cgo/testshared/src/depBase/dep.go index f9d3d7ce3a..c3ae96fe98 100644 --- a/misc/cgo/testshared/src/depBase/dep.go +++ b/misc/cgo/testshared/src/depBase/dep.go @@ -12,6 +12,11 @@ type Dep struct { X int } +func (d *Dep) Method() int { + return 10 +} + func F() int { + defer func() {}() return V } diff --git a/misc/cgo/testshared/src/exe2/exe2.go b/misc/cgo/testshared/src/exe2/exe2.go index acdb4ddcc5..675fd1f365 100644 --- a/misc/cgo/testshared/src/exe2/exe2.go +++ b/misc/cgo/testshared/src/exe2/exe2.go @@ -3,5 +3,6 @@ package main import "dep2" func main() { - dep2.W = dep2.G() + 1 + d := &dep2.Dep2{} + dep2.W = dep2.G() + 1 + d.Method() } diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go index 620cfd1bce..c48f662e10 100644 --- a/src/bytes/bytes_test.go +++ b/src/bytes/bytes_test.go @@ -6,6 +6,7 @@ package bytes_test import ( . "bytes" + "fmt" "math/rand" "reflect" "testing" @@ -357,167 +358,152 @@ func TestIndexRune(t *testing.T) { var bmbuf []byte -func BenchmarkIndexByte10(b *testing.B) { bmIndexByte(b, IndexByte, 10) } -func BenchmarkIndexByte32(b *testing.B) { bmIndexByte(b, IndexByte, 32) } -func BenchmarkIndexByte4K(b *testing.B) { bmIndexByte(b, IndexByte, 4<<10) } -func BenchmarkIndexByte4M(b *testing.B) { bmIndexByte(b, IndexByte, 4<<20) } -func BenchmarkIndexByte64M(b *testing.B) { bmIndexByte(b, IndexByte, 64<<20) } -func BenchmarkIndexBytePortable10(b *testing.B) { bmIndexByte(b, IndexBytePortable, 10) } -func BenchmarkIndexBytePortable32(b *testing.B) { bmIndexByte(b, IndexBytePortable, 32) } -func BenchmarkIndexBytePortable4K(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<10) } -func BenchmarkIndexBytePortable4M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<20) } -func BenchmarkIndexBytePortable64M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 64<<20) } - -func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) { - if len(bmbuf) < n { - bmbuf = make([]byte, n) +func valName(x int) string { + if s := x >> 20; s<<20 == x { + return fmt.Sprintf("%dM", s) } - b.SetBytes(int64(n)) - buf := bmbuf[0:n] - buf[n-1] = 'x' - for i := 0; i < b.N; i++ { - j := index(buf, 'x') - if j != n-1 { - b.Fatal("bad index", j) - } + if s := x >> 10; s<<10 == x { + return fmt.Sprintf("%dK", s) } - buf[n-1] = '\x00' + return fmt.Sprint(x) } -func BenchmarkEqual0(b *testing.B) { - var buf [4]byte - buf1 := buf[0:0] - buf2 := buf[1:1] - for i := 0; i < b.N; i++ { - eq := Equal(buf1, buf2) - if !eq { - b.Fatal("bad equal") - } +func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) { + for _, n := range sizes { + b.Run(valName(n), func(b *testing.B) { + if len(bmbuf) < n { + bmbuf = make([]byte, n) + } + b.SetBytes(int64(n)) + f(b, n) + }) } } -func BenchmarkEqual1(b *testing.B) { bmEqual(b, Equal, 1) } -func BenchmarkEqual6(b *testing.B) { bmEqual(b, Equal, 6) } -func BenchmarkEqual9(b *testing.B) { bmEqual(b, Equal, 9) } -func BenchmarkEqual15(b *testing.B) { bmEqual(b, Equal, 15) } -func BenchmarkEqual16(b *testing.B) { bmEqual(b, Equal, 16) } -func BenchmarkEqual20(b *testing.B) { bmEqual(b, Equal, 20) } -func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) } -func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) } -func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) } -func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) } -func BenchmarkEqualPort1(b *testing.B) { bmEqual(b, EqualPortable, 1) } -func BenchmarkEqualPort6(b *testing.B) { bmEqual(b, EqualPortable, 6) } -func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) } -func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) } -func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) } -func BenchmarkEqualPortable64M(b *testing.B) { bmEqual(b, EqualPortable, 64<<20) } +var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20} -func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) { - if len(bmbuf) < 2*n { - bmbuf = make([]byte, 2*n) - } - b.SetBytes(int64(n)) - buf1 := bmbuf[0:n] - buf2 := bmbuf[n : 2*n] - buf1[n-1] = 'x' - buf2[n-1] = 'x' - for i := 0; i < b.N; i++ { - eq := equal(buf1, buf2) - if !eq { - b.Fatal("bad equal") - } - } - buf1[n-1] = '\x00' - buf2[n-1] = '\x00' +func BenchmarkIndexByte(b *testing.B) { + benchBytes(b, indexSizes, bmIndexByte(IndexByte)) } -func BenchmarkIndex32(b *testing.B) { bmIndex(b, Index, 32) } -func BenchmarkIndex4K(b *testing.B) { bmIndex(b, Index, 4<<10) } -func BenchmarkIndex4M(b *testing.B) { bmIndex(b, Index, 4<<20) } -func BenchmarkIndex64M(b *testing.B) { bmIndex(b, Index, 64<<20) } - -func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) { - if len(bmbuf) < n { - bmbuf = make([]byte, n) - } - b.SetBytes(int64(n)) - buf := bmbuf[0:n] - buf[n-1] = 'x' - for i := 0; i < b.N; i++ { - j := index(buf, buf[n-7:]) - if j != n-7 { - b.Fatal("bad index", j) - } - } - buf[n-1] = '\x00' +func BenchmarkIndexBytePortable(b *testing.B) { + benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable)) } -func BenchmarkIndexEasy32(b *testing.B) { bmIndexEasy(b, Index, 32) } -func BenchmarkIndexEasy4K(b *testing.B) { bmIndexEasy(b, Index, 4<<10) } -func BenchmarkIndexEasy4M(b *testing.B) { bmIndexEasy(b, Index, 4<<20) } -func BenchmarkIndexEasy64M(b *testing.B) { bmIndexEasy(b, Index, 64<<20) } - -func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) { - if len(bmbuf) < n { - bmbuf = make([]byte, n) - } - b.SetBytes(int64(n)) - buf := bmbuf[0:n] - buf[n-1] = 'x' - buf[n-7] = 'x' - for i := 0; i < b.N; i++ { - j := index(buf, buf[n-7:]) - if j != n-7 { - b.Fatal("bad index", j) +func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) { + return func(b *testing.B, n int) { + buf := bmbuf[0:n] + buf[n-1] = 'x' + for i := 0; i < b.N; i++ { + j := index(buf, 'x') + if j != n-1 { + b.Fatal("bad index", j) + } } + buf[n-1] = '\x00' } - buf[n-1] = '\x00' - buf[n-7] = '\x00' } -func BenchmarkCount32(b *testing.B) { bmCount(b, Count, 32) } -func BenchmarkCount4K(b *testing.B) { bmCount(b, Count, 4<<10) } -func BenchmarkCount4M(b *testing.B) { bmCount(b, Count, 4<<20) } -func BenchmarkCount64M(b *testing.B) { bmCount(b, Count, 64<<20) } - -func bmCount(b *testing.B, count func([]byte, []byte) int, n int) { - if len(bmbuf) < n { - bmbuf = make([]byte, n) - } - b.SetBytes(int64(n)) - buf := bmbuf[0:n] - buf[n-1] = 'x' - for i := 0; i < b.N; i++ { - j := count(buf, buf[n-7:]) - if j != 1 { - b.Fatal("bad count", j) +func BenchmarkEqual(b *testing.B) { + b.Run("0", func(b *testing.B) { + var buf [4]byte + buf1 := buf[0:0] + buf2 := buf[1:1] + for i := 0; i < b.N; i++ { + eq := Equal(buf1, buf2) + if !eq { + b.Fatal("bad equal") + } } - } - buf[n-1] = '\x00' + }) + + sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20} + benchBytes(b, sizes, bmEqual(Equal)) } -func BenchmarkCountEasy32(b *testing.B) { bmCountEasy(b, Count, 32) } -func BenchmarkCountEasy4K(b *testing.B) { bmCountEasy(b, Count, 4<<10) } -func BenchmarkCountEasy4M(b *testing.B) { bmCountEasy(b, Count, 4<<20) } -func BenchmarkCountEasy64M(b *testing.B) { bmCountEasy(b, Count, 64<<20) } +func BenchmarkEqualPort(b *testing.B) { + sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20} + benchBytes(b, sizes, bmEqual(EqualPortable)) +} -func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) { - if len(bmbuf) < n { - bmbuf = make([]byte, n) - } - b.SetBytes(int64(n)) - buf := bmbuf[0:n] - buf[n-1] = 'x' - buf[n-7] = 'x' - for i := 0; i < b.N; i++ { - j := count(buf, buf[n-7:]) - if j != 1 { - b.Fatal("bad count", j) +func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) { + return func(b *testing.B, n int) { + if len(bmbuf) < 2*n { + bmbuf = make([]byte, 2*n) } + buf1 := bmbuf[0:n] + buf2 := bmbuf[n : 2*n] + buf1[n-1] = 'x' + buf2[n-1] = 'x' + for i := 0; i < b.N; i++ { + eq := equal(buf1, buf2) + if !eq { + b.Fatal("bad equal") + } + } + buf1[n-1] = '\x00' + buf2[n-1] = '\x00' } - buf[n-1] = '\x00' - buf[n-7] = '\x00' +} + +func BenchmarkIndex(b *testing.B) { + benchBytes(b, indexSizes, func(b *testing.B, n int) { + buf := bmbuf[0:n] + buf[n-1] = 'x' + for i := 0; i < b.N; i++ { + j := Index(buf, buf[n-7:]) + if j != n-7 { + b.Fatal("bad index", j) + } + } + buf[n-1] = '\x00' + }) +} + +func BenchmarkIndexEasy(b *testing.B) { + benchBytes(b, indexSizes, func(b *testing.B, n int) { + buf := bmbuf[0:n] + buf[n-1] = 'x' + buf[n-7] = 'x' + for i := 0; i < b.N; i++ { + j := Index(buf, buf[n-7:]) + if j != n-7 { + b.Fatal("bad index", j) + } + } + buf[n-1] = '\x00' + buf[n-7] = '\x00' + }) +} + +func BenchmarkCount(b *testing.B) { + benchBytes(b, indexSizes, func(b *testing.B, n int) { + buf := bmbuf[0:n] + buf[n-1] = 'x' + for i := 0; i < b.N; i++ { + j := Count(buf, buf[n-7:]) + if j != 1 { + b.Fatal("bad count", j) + } + } + buf[n-1] = '\x00' + }) +} + +func BenchmarkCountEasy(b *testing.B) { + benchBytes(b, indexSizes, func(b *testing.B, n int) { + buf := bmbuf[0:n] + buf[n-1] = 'x' + buf[n-7] = 'x' + for i := 0; i < b.N; i++ { + j := Count(buf, buf[n-7:]) + if j != 1 { + b.Fatal("bad count", j) + } + } + buf[n-1] = '\x00' + buf[n-7] = '\x00' + }) } type ExplodeTest struct { @@ -1318,33 +1304,24 @@ func BenchmarkRepeat(b *testing.B) { } } -func benchmarkBytesCompare(b *testing.B, n int) { - var x = make([]byte, n) - var y = make([]byte, n) +func BenchmarkBytesCompare(b *testing.B) { + for n := 1; n <= 2048; n <<= 1 { + b.Run(fmt.Sprint(n), func(b *testing.B) { + var x = make([]byte, n) + var y = make([]byte, n) - for i := 0; i < n; i++ { - x[i] = 'a' - } + for i := 0; i < n; i++ { + x[i] = 'a' + } - for i := 0; i < n; i++ { - y[i] = 'a' - } + for i := 0; i < n; i++ { + y[i] = 'a' + } - b.ResetTimer() - for i := 0; i < b.N; i++ { - Compare(x, y) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Compare(x, y) + } + }) } } - -func BenchmarkBytesCompare1(b *testing.B) { benchmarkBytesCompare(b, 1) } -func BenchmarkBytesCompare2(b *testing.B) { benchmarkBytesCompare(b, 2) } -func BenchmarkBytesCompare4(b *testing.B) { benchmarkBytesCompare(b, 4) } -func BenchmarkBytesCompare8(b *testing.B) { benchmarkBytesCompare(b, 8) } -func BenchmarkBytesCompare16(b *testing.B) { benchmarkBytesCompare(b, 16) } -func BenchmarkBytesCompare32(b *testing.B) { benchmarkBytesCompare(b, 32) } -func BenchmarkBytesCompare64(b *testing.B) { benchmarkBytesCompare(b, 64) } -func BenchmarkBytesCompare128(b *testing.B) { benchmarkBytesCompare(b, 128) } -func BenchmarkBytesCompare256(b *testing.B) { benchmarkBytesCompare(b, 256) } -func BenchmarkBytesCompare512(b *testing.B) { benchmarkBytesCompare(b, 512) } -func BenchmarkBytesCompare1024(b *testing.B) { benchmarkBytesCompare(b, 1024) } -func BenchmarkBytesCompare2048(b *testing.B) { benchmarkBytesCompare(b, 2048) } diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index bd49dfaf37..c8433c5d3f 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -26,7 +26,7 @@ func main() { } out, err := exec.Command("go", "tool", "api", - "-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"), + "-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7"), "-next", file("next"), "-except", file("except")).CombinedOutput() if err != nil { diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 823da43c1d..000ecd4468 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -172,7 +172,7 @@ func (f *File) saveExprs(x interface{}, context string) { f.saveRef(x, context) } case *ast.CallExpr: - f.saveCall(x) + f.saveCall(x, context) } } @@ -220,7 +220,7 @@ func (f *File) saveRef(n *ast.Expr, context string) { } // Save calls to C.xxx for later processing. -func (f *File) saveCall(call *ast.CallExpr) { +func (f *File) saveCall(call *ast.CallExpr, context string) { sel, ok := call.Fun.(*ast.SelectorExpr) if !ok { return @@ -228,7 +228,8 @@ func (f *File) saveCall(call *ast.CallExpr) { if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" { return } - f.Calls = append(f.Calls, call) + c := &Call{Call: call, Deferred: context == "defer"} + f.Calls = append(f.Calls, c) } // If a function should be exported add it to ExpFunc. @@ -401,7 +402,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} case *ast.GoStmt: f.walk(n.Call, "expr", visit) case *ast.DeferStmt: - f.walk(n.Call, "expr", visit) + f.walk(n.Call, "defer", visit) case *ast.ReturnStmt: f.walk(n.Results, "expr", visit) case *ast.BranchStmt: diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 451798244f..3766ff27f0 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -581,7 +581,7 @@ func (p *Package) mangleName(n *Name) { func (p *Package) rewriteCalls(f *File) { for _, call := range f.Calls { // This is a call to C.xxx; set goname to "xxx". - goname := call.Fun.(*ast.SelectorExpr).Sel.Name + goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name if goname == "malloc" { continue } @@ -596,37 +596,58 @@ func (p *Package) rewriteCalls(f *File) { // rewriteCall rewrites one call to add pointer checks. We replace // each pointer argument x with _cgoCheckPointer(x).(T). -func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) { +func (p *Package) rewriteCall(f *File, call *Call, name *Name) { + any := false for i, param := range name.FuncType.Params { - if len(call.Args) <= i { + if len(call.Call.Args) <= i { // Avoid a crash; this will be caught when the // generated file is compiled. return } + if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) { + any = true + break + } + } + if !any { + return + } - // An untyped nil does not need a pointer check, and - // when _cgoCheckPointer returns the untyped nil the - // type assertion we are going to insert will fail. - // Easier to just skip nil arguments. - // TODO: Note that this fails if nil is shadowed. - if id, ok := call.Args[i].(*ast.Ident); ok && id.Name == "nil" { - continue + // We need to rewrite this call. + // + // We are going to rewrite C.f(p) to C.f(_cgoCheckPointer(p)). + // If the call to C.f is deferred, that will check p at the + // point of the defer statement, not when the function is called, so + // rewrite to func(_cgo0 ptype) { C.f(_cgoCheckPointer(_cgo0)) }(p) + + var dargs []ast.Expr + if call.Deferred { + dargs = make([]ast.Expr, len(name.FuncType.Params)) + } + for i, param := range name.FuncType.Params { + origArg := call.Call.Args[i] + darg := origArg + + if call.Deferred { + dargs[i] = darg + darg = ast.NewIdent(fmt.Sprintf("_cgo%d", i)) + call.Call.Args[i] = darg } - if !p.needsPointerCheck(f, param.Go) { + if !p.needsPointerCheck(f, param.Go, origArg) { continue } c := &ast.CallExpr{ Fun: ast.NewIdent("_cgoCheckPointer"), Args: []ast.Expr{ - call.Args[i], + darg, }, } // Add optional additional arguments for an address // expression. - c.Args = p.checkAddrArgs(f, c.Args, call.Args[i]) + c.Args = p.checkAddrArgs(f, c.Args, origArg) // _cgoCheckPointer returns interface{}. // We need to type assert that to the type we want. @@ -636,7 +657,7 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) { // Instead we use a local variant of _cgoCheckPointer. var arg ast.Expr - if n := p.unsafeCheckPointerName(param.Go); n != "" { + if n := p.unsafeCheckPointerName(param.Go, call.Deferred); n != "" { c.Fun = ast.NewIdent(n) arg = c } else { @@ -664,14 +685,73 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) { } } - call.Args[i] = arg + call.Call.Args[i] = arg + } + + if call.Deferred { + params := make([]*ast.Field, len(name.FuncType.Params)) + for i, param := range name.FuncType.Params { + ptype := param.Go + if p.hasUnsafePointer(ptype) { + // Avoid generating unsafe.Pointer by using + // interface{}. This works because we are + // going to call a _cgoCheckPointer function + // anyhow. + ptype = &ast.InterfaceType{ + Methods: &ast.FieldList{}, + } + } + params[i] = &ast.Field{ + Names: []*ast.Ident{ + ast.NewIdent(fmt.Sprintf("_cgo%d", i)), + }, + Type: ptype, + } + } + + dbody := &ast.CallExpr{ + Fun: call.Call.Fun, + Args: call.Call.Args, + } + call.Call.Fun = &ast.FuncLit{ + Type: &ast.FuncType{ + Params: &ast.FieldList{ + List: params, + }, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + X: dbody, + }, + }, + }, + } + call.Call.Args = dargs + call.Call.Lparen = token.NoPos + call.Call.Rparen = token.NoPos + + // There is a Ref pointing to the old call.Call.Fun. + for _, ref := range f.Ref { + if ref.Expr == &call.Call.Fun { + ref.Expr = &dbody.Fun + } + } } } // needsPointerCheck returns whether the type t needs a pointer check. // This is true if t is a pointer and if the value to which it points // might contain a pointer. -func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool { +func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool { + // An untyped nil does not need a pointer check, and when + // _cgoCheckPointer returns the untyped nil the type assertion we + // are going to insert will fail. Easier to just skip nil arguments. + // TODO: Note that this fails if nil is shadowed. + if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" { + return false + } + return p.hasPointer(f, t, true) } @@ -859,20 +939,31 @@ func (p *Package) isType(t ast.Expr) bool { // assertion to unsafe.Pointer in our copy of user code. We return // the name of the _cgoCheckPointer function we are going to build, or // the empty string if the type does not use unsafe.Pointer. -func (p *Package) unsafeCheckPointerName(t ast.Expr) string { +// +// The deferred parameter is true if this check is for the argument of +// a deferred function. In that case we need to use an empty interface +// as the argument type, because the deferred function we introduce in +// rewriteCall will use an empty interface type, and we can't add a +// type assertion. This is handled by keeping a separate list, and +// writing out the lists separately in writeDefs. +func (p *Package) unsafeCheckPointerName(t ast.Expr, deferred bool) string { if !p.hasUnsafePointer(t) { return "" } var buf bytes.Buffer conf.Fprint(&buf, fset, t) s := buf.String() - for i, t := range p.CgoChecks { + checks := &p.CgoChecks + if deferred { + checks = &p.DeferredCgoChecks + } + for i, t := range *checks { if s == t { - return p.unsafeCheckPointerNameIndex(i) + return p.unsafeCheckPointerNameIndex(i, deferred) } } - p.CgoChecks = append(p.CgoChecks, s) - return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1) + *checks = append(*checks, s) + return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred) } // hasUnsafePointer returns whether the Go type t uses unsafe.Pointer. @@ -900,7 +991,10 @@ func (p *Package) hasUnsafePointer(t ast.Expr) bool { // unsafeCheckPointerNameIndex returns the name to use for a // _cgoCheckPointer variant based on the index in the CgoChecks slice. -func (p *Package) unsafeCheckPointerNameIndex(i int) string { +func (p *Package) unsafeCheckPointerNameIndex(i int, deferred bool) string { + if deferred { + return fmt.Sprintf("_cgoCheckPointerInDefer%d", i) + } return fmt.Sprintf("_cgoCheckPointer%d", i) } diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index cbdeb0f9ca..72ac19ad39 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -42,7 +42,10 @@ type Package struct { GoFiles []string // list of Go files GccFiles []string // list of gcc output files Preamble string // collected preamble for _cgo_export.h - CgoChecks []string // see unsafeCheckPointerName + + // See unsafeCheckPointerName. + CgoChecks []string + DeferredCgoChecks []string } // A File collects information about a single Go input file. @@ -52,7 +55,7 @@ type File struct { Package string // Package name Preamble string // C preamble (doc comment on import "C") Ref []*Ref // all references to C.xxx in AST - Calls []*ast.CallExpr // all calls to C.xxx in AST + Calls []*Call // all calls to C.xxx in AST ExpFunc []*ExpFunc // exported functions for this file Name map[string]*Name // map from Go name to Name } @@ -66,6 +69,12 @@ func nameKeys(m map[string]*Name) []string { return ks } +// A Call refers to a call of a C.xxx function in the AST. +type Call struct { + Call *ast.CallExpr + Deferred bool +} + // A Ref refers to an expression of the form C.xxx in the AST. type Ref struct { Name *Name diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 5d6930d3ea..842b1c5ef8 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -112,7 +112,13 @@ func (p *Package) writeDefs() { } for i, t := range p.CgoChecks { - n := p.unsafeCheckPointerNameIndex(i) + n := p.unsafeCheckPointerNameIndex(i, false) + fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t) + fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t) + fmt.Fprintf(fgo2, "}\n") + } + for i, t := range p.DeferredCgoChecks { + n := p.unsafeCheckPointerNameIndex(i, true) fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t) fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t) fmt.Fprintf(fgo2, "}\n") @@ -1324,6 +1330,7 @@ const noTsanProlog = ` #define _cgo_tsan_release() ` +// This must match the TSAN code in runtime/cgo/libcgo.h. const yesTsanProlog = ` #define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread)) @@ -1332,10 +1339,12 @@ long long _cgo_sync __attribute__ ((common)); extern void __tsan_acquire(void*); extern void __tsan_release(void*); +__attribute__ ((unused)) static void _cgo_tsan_acquire() { __tsan_acquire(&_cgo_sync); } +__attribute__ ((unused)) static void _cgo_tsan_release() { __tsan_release(&_cgo_sync); } diff --git a/src/cmd/compile/internal/arm/ggen.go b/src/cmd/compile/internal/arm/ggen.go index d241357d62..4a45e589eb 100644 --- a/src/cmd/compile/internal/arm/ggen.go +++ b/src/cmd/compile/internal/arm/ggen.go @@ -341,6 +341,11 @@ func clearfat(nl *gc.Node) { c := w % 4 // bytes q := w / 4 // quads + if nl.Type.Align < 4 { + q = 0 + c = w + } + var r0 gc.Node r0.Op = gc.OREGISTER @@ -395,6 +400,27 @@ func clearfat(nl *gc.Node) { } } + if c > 4 { + // Loop to zero unaligned memory. + var end gc.Node + gc.Regalloc(&end, gc.Types[gc.Tptr], nil) + p := gins(arm.AMOVW, &dst, &end) + p.From.Type = obj.TYPE_ADDR + p.From.Offset = int64(c) + + p = gins(arm.AMOVB, &nz, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = 1 + p.Scond |= arm.C_PBIT + pl := p + + p = gins(arm.ACMP, &dst, nil) + raddr(&end, p) + gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl) + + gc.Regfree(&end) + c = 0 + } var p *obj.Prog for c > 0 { p = gins(arm.AMOVB, &nz, &dst) diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go index 469f0864d5..b44bf77c5d 100644 --- a/src/cmd/compile/internal/gc/asm_test.go +++ b/src/cmd/compile/internal/gc/asm_test.go @@ -61,7 +61,7 @@ func compileToAsm(dir, arch, pkg string) string { var stdout, stderr bytes.Buffer cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) - cmd.Env = append(cmd.Env, "GOARCH="+arch) + cmd.Env = mergeEnvLists([]string{"GOARCH=" + arch}, os.Environ()) cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { @@ -103,3 +103,22 @@ func f(x int) int { []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, }, } + +// mergeEnvLists merges the two environment lists such that +// variables with the same name in "in" replace those in "out". +// This always returns a newly allocated slice. +func mergeEnvLists(in, out []string) []string { + out = append([]string(nil), out...) +NextVar: + for _, inkv := range in { + k := strings.SplitAfterN(inkv, "=", 2)[0] + for i, outkv := range out { + if strings.HasPrefix(outkv, k) { + out[i] = inkv + continue NextVar + } + } + out = append(out, inkv) + } + return out +} diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index f533053cd7..c7be2deaa2 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -622,6 +622,8 @@ func isInlineable(n *Node) bool { return false } +var errorInterface *Type // lazily initialized + func (p *exporter) typ(t *Type) { if t == nil { Fatalf("exporter: nil type") @@ -673,7 +675,19 @@ func (p *exporter) typ(t *Type) { p.qualifiedName(tsym) // write underlying type - p.typ(t.Orig) + orig := t.Orig + if orig == errortype { + // The error type is the only predeclared type which has + // a composite underlying type. When we encode that type, + // make sure to encode the underlying interface rather than + // the named type again. See also the comment in universe.go + // regarding the errortype and issue #15920. + if errorInterface == nil { + errorInterface = makeErrorInterface() + } + orig = errorInterface + } + p.typ(orig) // interfaces don't have associated methods if t.Orig.IsInterface() { diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go index dbefcc7a0b..74fe463dae 100644 --- a/src/cmd/compile/internal/gc/cgen.go +++ b/src/cmd/compile/internal/gc/cgen.go @@ -2855,11 +2855,6 @@ func cgen_append(n, res *Node) { Dump("cgen_append-n", n) Dump("cgen_append-res", res) } - if res.Op != ONAME && !samesafeexpr(res, n.List.First()) { - Dump("cgen_append-n", n) - Dump("cgen_append-res", res) - Fatalf("append not lowered") - } for _, n1 := range n.List.Slice() { if n1.Ullman >= UINF { Fatalf("append with function call arguments") diff --git a/src/cmd/compile/internal/gc/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go index 118183dd2f..ef6a3c115d 100644 --- a/src/cmd/compile/internal/gc/constFold_test.go +++ b/src/cmd/compile/internal/gc/constFold_test.go @@ -12414,3 +12414,5695 @@ func TestConstFoldint8uint8rsh(t *testing.T) { t.Errorf("127 >> 255 = %d, want 0", r) } } +func TestConstFoldCompareuint64(t *testing.T) { + { + var x uint64 = 0 + var y uint64 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 0 + var y uint64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint64 = 0 + var y uint64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint64 = 0 + var y uint64 = 18446744073709551615 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint64 = 1 + var y uint64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 1 + var y uint64 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 1 + var y uint64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint64 = 1 + var y uint64 = 18446744073709551615 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint64 = 4294967296 + var y uint64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 4294967296 + var y uint64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 4294967296 + var y uint64 = 4294967296 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 4294967296 + var y uint64 = 18446744073709551615 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint64 = 18446744073709551615 + var y uint64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 18446744073709551615 + var y uint64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 18446744073709551615 + var y uint64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint64 = 18446744073709551615 + var y uint64 = 18446744073709551615 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareint64(t *testing.T) { + { + var x int64 = -9223372036854775808 + var y int64 = -9223372036854775808 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775808 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = -9223372036854775807 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -9223372036854775807 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = -4294967296 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -4294967296 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -1 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -1 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -1 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -1 + var y int64 = -1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = -1 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -1 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -1 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -1 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = -1 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 0 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 0 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 0 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 0 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 0 + var y int64 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 0 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 0 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 0 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 0 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 1 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 1 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 1 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 1 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 1 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 1 + var y int64 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 1 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 1 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 1 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = 4294967296 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 4294967296 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = 9223372036854775806 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775806 + var y int64 = 9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = -9223372036854775808 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = -9223372036854775807 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = -4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = 4294967296 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = 9223372036854775806 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int64 = 9223372036854775807 + var y int64 = 9223372036854775807 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareuint32(t *testing.T) { + { + var x uint32 = 0 + var y uint32 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint32 = 0 + var y uint32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint32 = 0 + var y uint32 = 4294967295 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint32 = 1 + var y uint32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint32 = 1 + var y uint32 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint32 = 1 + var y uint32 = 4294967295 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint32 = 4294967295 + var y uint32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint32 = 4294967295 + var y uint32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint32 = 4294967295 + var y uint32 = 4294967295 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareint32(t *testing.T) { + { + var x int32 = -2147483648 + var y int32 = -2147483648 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = -2147483648 + var y int32 = -2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483648 + var y int32 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483648 + var y int32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483648 + var y int32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483648 + var y int32 = 2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483647 + var y int32 = -2147483648 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = -2147483647 + var y int32 = -2147483647 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = -2147483647 + var y int32 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483647 + var y int32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483647 + var y int32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -2147483647 + var y int32 = 2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -1 + var y int32 = -2147483648 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = -1 + var y int32 = -2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = -1 + var y int32 = -1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = -1 + var y int32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -1 + var y int32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = -1 + var y int32 = 2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = 0 + var y int32 = -2147483648 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 0 + var y int32 = -2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 0 + var y int32 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 0 + var y int32 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 0 + var y int32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = 0 + var y int32 = 2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = 1 + var y int32 = -2147483648 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 1 + var y int32 = -2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 1 + var y int32 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 1 + var y int32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 1 + var y int32 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 1 + var y int32 = 2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int32 = 2147483647 + var y int32 = -2147483648 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 2147483647 + var y int32 = -2147483647 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 2147483647 + var y int32 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 2147483647 + var y int32 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 2147483647 + var y int32 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int32 = 2147483647 + var y int32 = 2147483647 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareuint16(t *testing.T) { + { + var x uint16 = 0 + var y uint16 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint16 = 0 + var y uint16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint16 = 0 + var y uint16 = 65535 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint16 = 1 + var y uint16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint16 = 1 + var y uint16 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint16 = 1 + var y uint16 = 65535 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint16 = 65535 + var y uint16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint16 = 65535 + var y uint16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint16 = 65535 + var y uint16 = 65535 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareint16(t *testing.T) { + { + var x int16 = -32768 + var y int16 = -32768 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = -32768 + var y int16 = -32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32768 + var y int16 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32768 + var y int16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32768 + var y int16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32768 + var y int16 = 32766 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32768 + var y int16 = 32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32767 + var y int16 = -32768 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = -32767 + var y int16 = -32767 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = -32767 + var y int16 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32767 + var y int16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32767 + var y int16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32767 + var y int16 = 32766 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -32767 + var y int16 = 32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -1 + var y int16 = -32768 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = -1 + var y int16 = -32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = -1 + var y int16 = -1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = -1 + var y int16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -1 + var y int16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -1 + var y int16 = 32766 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = -1 + var y int16 = 32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 0 + var y int16 = -32768 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 0 + var y int16 = -32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 0 + var y int16 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 0 + var y int16 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 0 + var y int16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 0 + var y int16 = 32766 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 0 + var y int16 = 32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 1 + var y int16 = -32768 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 1 + var y int16 = -32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 1 + var y int16 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 1 + var y int16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 1 + var y int16 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 1 + var y int16 = 32766 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 1 + var y int16 = 32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 32766 + var y int16 = -32768 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32766 + var y int16 = -32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32766 + var y int16 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32766 + var y int16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32766 + var y int16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32766 + var y int16 = 32766 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32766 + var y int16 = 32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int16 = 32767 + var y int16 = -32768 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32767 + var y int16 = -32767 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32767 + var y int16 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32767 + var y int16 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32767 + var y int16 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32767 + var y int16 = 32766 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int16 = 32767 + var y int16 = 32767 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareuint8(t *testing.T) { + { + var x uint8 = 0 + var y uint8 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint8 = 0 + var y uint8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint8 = 0 + var y uint8 = 255 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint8 = 1 + var y uint8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint8 = 1 + var y uint8 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint8 = 1 + var y uint8 = 255 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x uint8 = 255 + var y uint8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint8 = 255 + var y uint8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x uint8 = 255 + var y uint8 = 255 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} +func TestConstFoldCompareint8(t *testing.T) { + { + var x int8 = -128 + var y int8 = -128 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = -128 + var y int8 = -127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -128 + var y int8 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -128 + var y int8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -128 + var y int8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -128 + var y int8 = 126 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -128 + var y int8 = 127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -127 + var y int8 = -128 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = -127 + var y int8 = -127 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = -127 + var y int8 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -127 + var y int8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -127 + var y int8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -127 + var y int8 = 126 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -127 + var y int8 = 127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -1 + var y int8 = -128 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = -1 + var y int8 = -127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = -1 + var y int8 = -1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = -1 + var y int8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -1 + var y int8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -1 + var y int8 = 126 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = -1 + var y int8 = 127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 0 + var y int8 = -128 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 0 + var y int8 = -127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 0 + var y int8 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 0 + var y int8 = 0 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 0 + var y int8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 0 + var y int8 = 126 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 0 + var y int8 = 127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 1 + var y int8 = -128 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 1 + var y int8 = -127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 1 + var y int8 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 1 + var y int8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 1 + var y int8 = 1 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 1 + var y int8 = 126 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 1 + var y int8 = 127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 126 + var y int8 = -128 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 126 + var y int8 = -127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 126 + var y int8 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 126 + var y int8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 126 + var y int8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 126 + var y int8 = 126 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 126 + var y int8 = 127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if !(x < y) { + t.Errorf("!(%d < %d)", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if x >= y { + t.Errorf("%d >= %d", x, y) + } + } + { + var x int8 = 127 + var y int8 = -128 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 127 + var y int8 = -127 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 127 + var y int8 = -1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 127 + var y int8 = 0 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 127 + var y int8 = 1 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 127 + var y int8 = 126 + if x == y { + t.Errorf("%d == %d", x, y) + } + if !(x != y) { + t.Errorf("!(%d != %d)", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if !(x > y) { + t.Errorf("!(%d > %d)", x, y) + } + if x <= y { + t.Errorf("%d <= %d", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } + { + var x int8 = 127 + var y int8 = 127 + if !(x == y) { + t.Errorf("!(%d == %d)", x, y) + } + if x != y { + t.Errorf("%d != %d", x, y) + } + if x < y { + t.Errorf("%d < %d", x, y) + } + if x > y { + t.Errorf("%d > %d", x, y) + } + if !(x <= y) { + t.Errorf("!(%d <= %d)", x, y) + } + if !(x >= y) { + t.Errorf("!(%d >= %d)", x, y) + } + } +} diff --git a/src/cmd/compile/internal/gc/fixedbugs_test.go b/src/cmd/compile/internal/gc/fixedbugs_test.go new file mode 100644 index 0000000000..19b1d9adf6 --- /dev/null +++ b/src/cmd/compile/internal/gc/fixedbugs_test.go @@ -0,0 +1,50 @@ +// Copyright 2016 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 gc + +import "testing" + +type T struct { + x [2]int64 // field that will be clobbered. Also makes type not SSAable. + p *byte // has a pointer +} + +//go:noinline +func makeT() T { + return T{} +} + +var g T + +var sink []byte + +func TestIssue15854(t *testing.T) { + for i := 0; i < 10000; i++ { + if g.x[0] != 0 { + t.Fatalf("g.x[0] clobbered with %x\n", g.x[0]) + } + // The bug was in the following assignment. The return + // value of makeT() is not copied out of the args area of + // stack frame in a timely fashion. So when write barriers + // are enabled, the marshaling of the args for the write + // barrier call clobbers the result of makeT() before it is + // read by the write barrier code. + g = makeT() + sink = make([]byte, 1000) // force write barriers to eventually happen + } +} +func TestIssue15854b(t *testing.T) { + const N = 10000 + a := make([]T, N) + for i := 0; i < N; i++ { + a = append(a, makeT()) + sink = make([]byte, 1000) // force write barriers to eventually happen + } + for i, v := range a { + if v.x[0] != 0 { + t.Fatalf("a[%d].x[0] clobbered with %x\n", i, v.x[0]) + } + } +} diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index b6b858c0d9..2e4caca155 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -156,6 +156,8 @@ var Debug_typeassert int var localpkg *Pkg // package being compiled +var autopkg *Pkg // fake package for allocating auto variables + var importpkg *Pkg // package being imported var itabpkg *Pkg // fake pkg for itab entries diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 8ad3300dbe..b4df7ed20f 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -108,6 +108,8 @@ func Main() { localpkg = mkpkg("") localpkg.Prefix = "\"\"" + autopkg = mkpkg("") + autopkg.Prefix = "\"\"" // pseudo-package, for scoping builtinpkg = mkpkg("go.builtin") diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 85138c9fcd..7d0d2dd894 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -577,6 +577,15 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini return } + if prog.As == obj.AJMP && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN { + // This is a tail call. Ensure the arguments are still alive. + // See issue 16016. + for i, node := range vars { + if node.Class == PPARAM { + bvset(uevar, int32(i)) + } + } + } if prog.As == obj.ATEXT { // A text instruction marks the entry point to a function and diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 4a658b1976..ad2bba9714 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -164,7 +164,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) { var outn Nodes outn.Set(out) instrumentnode(&ls[i], &outn, 0, 0) - if ls[i].Op != OAS || ls[i].Ninit.Len() == 0 { + if ls[i].Op != OAS && ls[i].Op != OASWB && ls[i].Op != OAS2FUNC || ls[i].Ninit.Len() == 0 { out = append(outn.Slice(), ls[i]) } else { // Splice outn onto end of ls[i].Ninit diff --git a/src/cmd/compile/internal/gc/shift_test.go b/src/cmd/compile/internal/gc/shift_test.go new file mode 100644 index 0000000000..ce2eedf152 --- /dev/null +++ b/src/cmd/compile/internal/gc/shift_test.go @@ -0,0 +1,1031 @@ +// Copyright 2016 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 gc + +import ( + "reflect" + "testing" +) + +// Tests shifts of zero. + +//go:noinline +func ofz64l64(n uint64) int64 { + var x int64 + return x << n +} + +//go:noinline +func ofz64l32(n uint32) int64 { + var x int64 + return x << n +} + +//go:noinline +func ofz64l16(n uint16) int64 { + var x int64 + return x << n +} + +//go:noinline +func ofz64l8(n uint8) int64 { + var x int64 + return x << n +} + +//go:noinline +func ofz64r64(n uint64) int64 { + var x int64 + return x >> n +} + +//go:noinline +func ofz64r32(n uint32) int64 { + var x int64 + return x >> n +} + +//go:noinline +func ofz64r16(n uint16) int64 { + var x int64 + return x >> n +} + +//go:noinline +func ofz64r8(n uint8) int64 { + var x int64 + return x >> n +} + +//go:noinline +func ofz64ur64(n uint64) uint64 { + var x uint64 + return x >> n +} + +//go:noinline +func ofz64ur32(n uint32) uint64 { + var x uint64 + return x >> n +} + +//go:noinline +func ofz64ur16(n uint16) uint64 { + var x uint64 + return x >> n +} + +//go:noinline +func ofz64ur8(n uint8) uint64 { + var x uint64 + return x >> n +} + +//go:noinline +func ofz32l64(n uint64) int32 { + var x int32 + return x << n +} + +//go:noinline +func ofz32l32(n uint32) int32 { + var x int32 + return x << n +} + +//go:noinline +func ofz32l16(n uint16) int32 { + var x int32 + return x << n +} + +//go:noinline +func ofz32l8(n uint8) int32 { + var x int32 + return x << n +} + +//go:noinline +func ofz32r64(n uint64) int32 { + var x int32 + return x >> n +} + +//go:noinline +func ofz32r32(n uint32) int32 { + var x int32 + return x >> n +} + +//go:noinline +func ofz32r16(n uint16) int32 { + var x int32 + return x >> n +} + +//go:noinline +func ofz32r8(n uint8) int32 { + var x int32 + return x >> n +} + +//go:noinline +func ofz32ur64(n uint64) uint32 { + var x uint32 + return x >> n +} + +//go:noinline +func ofz32ur32(n uint32) uint32 { + var x uint32 + return x >> n +} + +//go:noinline +func ofz32ur16(n uint16) uint32 { + var x uint32 + return x >> n +} + +//go:noinline +func ofz32ur8(n uint8) uint32 { + var x uint32 + return x >> n +} + +//go:noinline +func ofz16l64(n uint64) int16 { + var x int16 + return x << n +} + +//go:noinline +func ofz16l32(n uint32) int16 { + var x int16 + return x << n +} + +//go:noinline +func ofz16l16(n uint16) int16 { + var x int16 + return x << n +} + +//go:noinline +func ofz16l8(n uint8) int16 { + var x int16 + return x << n +} + +//go:noinline +func ofz16r64(n uint64) int16 { + var x int16 + return x >> n +} + +//go:noinline +func ofz16r32(n uint32) int16 { + var x int16 + return x >> n +} + +//go:noinline +func ofz16r16(n uint16) int16 { + var x int16 + return x >> n +} + +//go:noinline +func ofz16r8(n uint8) int16 { + var x int16 + return x >> n +} + +//go:noinline +func ofz16ur64(n uint64) uint16 { + var x uint16 + return x >> n +} + +//go:noinline +func ofz16ur32(n uint32) uint16 { + var x uint16 + return x >> n +} + +//go:noinline +func ofz16ur16(n uint16) uint16 { + var x uint16 + return x >> n +} + +//go:noinline +func ofz16ur8(n uint8) uint16 { + var x uint16 + return x >> n +} + +//go:noinline +func ofz8l64(n uint64) int8 { + var x int8 + return x << n +} + +//go:noinline +func ofz8l32(n uint32) int8 { + var x int8 + return x << n +} + +//go:noinline +func ofz8l16(n uint16) int8 { + var x int8 + return x << n +} + +//go:noinline +func ofz8l8(n uint8) int8 { + var x int8 + return x << n +} + +//go:noinline +func ofz8r64(n uint64) int8 { + var x int8 + return x >> n +} + +//go:noinline +func ofz8r32(n uint32) int8 { + var x int8 + return x >> n +} + +//go:noinline +func ofz8r16(n uint16) int8 { + var x int8 + return x >> n +} + +//go:noinline +func ofz8r8(n uint8) int8 { + var x int8 + return x >> n +} + +//go:noinline +func ofz8ur64(n uint64) uint8 { + var x uint8 + return x >> n +} + +//go:noinline +func ofz8ur32(n uint32) uint8 { + var x uint8 + return x >> n +} + +//go:noinline +func ofz8ur16(n uint16) uint8 { + var x uint8 + return x >> n +} + +//go:noinline +func ofz8ur8(n uint8) uint8 { + var x uint8 + return x >> n +} + +func TestShiftOfZero(t *testing.T) { + if got := ofz64l64(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz64l32(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz64l16(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz64l8(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz64r64(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz64r32(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz64r16(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz64r8(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz64ur64(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz64ur32(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz64ur16(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz64ur8(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + + if got := ofz32l64(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz32l32(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz32l16(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz32l8(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz32r64(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz32r32(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz32r16(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz32r8(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz32ur64(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz32ur32(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz32ur16(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz32ur8(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + + if got := ofz16l64(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz16l32(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz16l16(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz16l8(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz16r64(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz16r32(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz16r16(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz16r8(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz16ur64(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz16ur32(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz16ur16(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz16ur8(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + + if got := ofz8l64(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz8l32(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz8l16(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz8l8(5); got != 0 { + t.Errorf("0<<5 == %d, want 0", got) + } + if got := ofz8r64(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz8r32(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz8r16(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz8r8(5); got != 0 { + t.Errorf("0>>5 == %d, want 0", got) + } + if got := ofz8ur64(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz8ur32(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz8ur16(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } + if got := ofz8ur8(5); got != 0 { + t.Errorf("0>>>5 == %d, want 0", got) + } +} + +//go:noinline +func byz64l(n int64) int64 { + return n << 0 +} + +//go:noinline +func byz64r(n int64) int64 { + return n >> 0 +} + +//go:noinline +func byz64ur(n uint64) uint64 { + return n >> 0 +} + +//go:noinline +func byz32l(n int32) int32 { + return n << 0 +} + +//go:noinline +func byz32r(n int32) int32 { + return n >> 0 +} + +//go:noinline +func byz32ur(n uint32) uint32 { + return n >> 0 +} + +//go:noinline +func byz16l(n int16) int16 { + return n << 0 +} + +//go:noinline +func byz16r(n int16) int16 { + return n >> 0 +} + +//go:noinline +func byz16ur(n uint16) uint16 { + return n >> 0 +} + +//go:noinline +func byz8l(n int8) int8 { + return n << 0 +} + +//go:noinline +func byz8r(n int8) int8 { + return n >> 0 +} + +//go:noinline +func byz8ur(n uint8) uint8 { + return n >> 0 +} + +func TestShiftByZero(t *testing.T) { + { + var n int64 = 0x5555555555555555 + if got := byz64l(n); got != n { + t.Errorf("%x<<0 == %x, want %x", n, got, n) + } + if got := byz64r(n); got != n { + t.Errorf("%x>>0 == %x, want %x", n, got, n) + } + } + { + var n uint64 = 0xaaaaaaaaaaaaaaaa + if got := byz64ur(n); got != n { + t.Errorf("%x>>>0 == %x, want %x", n, got, n) + } + } + + { + var n int32 = 0x55555555 + if got := byz32l(n); got != n { + t.Errorf("%x<<0 == %x, want %x", n, got, n) + } + if got := byz32r(n); got != n { + t.Errorf("%x>>0 == %x, want %x", n, got, n) + } + } + { + var n uint32 = 0xaaaaaaaa + if got := byz32ur(n); got != n { + t.Errorf("%x>>>0 == %x, want %x", n, got, n) + } + } + + { + var n int16 = 0x5555 + if got := byz16l(n); got != n { + t.Errorf("%x<<0 == %x, want %x", n, got, n) + } + if got := byz16r(n); got != n { + t.Errorf("%x>>0 == %x, want %x", n, got, n) + } + } + { + var n uint16 = 0xaaaa + if got := byz16ur(n); got != n { + t.Errorf("%x>>>0 == %x, want %x", n, got, n) + } + } + + { + var n int8 = 0x55 + if got := byz8l(n); got != n { + t.Errorf("%x<<0 == %x, want %x", n, got, n) + } + if got := byz8r(n); got != n { + t.Errorf("%x>>0 == %x, want %x", n, got, n) + } + } + { + var n uint8 = 0x55 + if got := byz8ur(n); got != n { + t.Errorf("%x>>>0 == %x, want %x", n, got, n) + } + } +} + +//go:noinline +func two64l(x int64) int64 { + return x << 1 << 1 +} + +//go:noinline +func two64r(x int64) int64 { + return x >> 1 >> 1 +} + +//go:noinline +func two64ur(x uint64) uint64 { + return x >> 1 >> 1 +} + +//go:noinline +func two32l(x int32) int32 { + return x << 1 << 1 +} + +//go:noinline +func two32r(x int32) int32 { + return x >> 1 >> 1 +} + +//go:noinline +func two32ur(x uint32) uint32 { + return x >> 1 >> 1 +} + +//go:noinline +func two16l(x int16) int16 { + return x << 1 << 1 +} + +//go:noinline +func two16r(x int16) int16 { + return x >> 1 >> 1 +} + +//go:noinline +func two16ur(x uint16) uint16 { + return x >> 1 >> 1 +} + +//go:noinline +func two8l(x int8) int8 { + return x << 1 << 1 +} + +//go:noinline +func two8r(x int8) int8 { + return x >> 1 >> 1 +} + +//go:noinline +func two8ur(x uint8) uint8 { + return x >> 1 >> 1 +} + +func TestShiftCombine(t *testing.T) { + if got, want := two64l(4), int64(16); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := two64r(64), int64(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two64ur(64), uint64(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two32l(4), int32(16); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := two32r(64), int32(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two32ur(64), uint32(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two16l(4), int16(16); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := two16r(64), int16(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two16ur(64), uint16(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two8l(4), int8(16); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := two8r(64), int8(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := two8ur(64), uint8(16); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + +} + +//go:noinline +func three64l(x int64) int64 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three64ul(x uint64) uint64 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three64r(x int64) int64 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three64ur(x uint64) uint64 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three32l(x int32) int32 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three32ul(x uint32) uint32 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three32r(x int32) int32 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three32ur(x uint32) uint32 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three16l(x int16) int16 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three16ul(x uint16) uint16 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three16r(x int16) int16 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three16ur(x uint16) uint16 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three8l(x int8) int8 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three8ul(x uint8) uint8 { + return x << 3 >> 1 << 2 +} + +//go:noinline +func three8r(x int8) int8 { + return x >> 3 << 1 >> 2 +} + +//go:noinline +func three8ur(x uint8) uint8 { + return x >> 3 << 1 >> 2 +} + +func TestShiftCombine3(t *testing.T) { + if got, want := three64l(4), int64(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three64ul(4), uint64(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three64r(64), int64(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three64ur(64), uint64(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three32l(4), int32(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three32ul(4), uint32(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three32r(64), int32(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three32ur(64), uint32(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three16l(4), int16(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three16ul(4), uint16(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three16r(64), int16(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three16ur(64), uint16(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three8l(4), int8(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three8ul(4), uint8(64); want != got { + t.Errorf("4<<1<<1 == %d, want %d", got, want) + } + if got, want := three8r(64), int8(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } + if got, want := three8ur(64), uint8(4); want != got { + t.Errorf("64>>1>>1 == %d, want %d", got, want) + } +} + +var ( + one64 int64 = 1 + one64u uint64 = 1 + one32 int32 = 1 + one32u uint32 = 1 + one16 int16 = 1 + one16u uint16 = 1 + one8 int8 = 1 + one8u uint8 = 1 +) + +func TestShiftLargeCombine(t *testing.T) { + var N uint64 = 0x8000000000000000 + if one64<>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one64u>>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one32<>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one32u>>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one16<>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one16u>>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one8<>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one8u>>N>>N == 1 { + t.Errorf("shift overflow mishandled") + } +} + +func TestShiftLargeCombine3(t *testing.T) { + var N uint64 = 0x8000000000000001 + if one64<>2<>2<>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one64u>>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one32<>2<>2<>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one32u>>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one16<>2<>2<>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one16u>>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one8<>2<>2<>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } + if one8u>>N<<2>>N == 1 { + t.Errorf("shift overflow mishandled") + } +} + +func TestShiftGeneric(t *testing.T) { + for _, test := range [...]struct { + valueWidth int + signed bool + shiftWidth int + left bool + f interface{} + }{ + {64, true, 64, true, func(n int64, s uint64) int64 { return n << s }}, + {64, true, 64, false, func(n int64, s uint64) int64 { return n >> s }}, + {64, false, 64, false, func(n uint64, s uint64) uint64 { return n >> s }}, + {64, true, 32, true, func(n int64, s uint32) int64 { return n << s }}, + {64, true, 32, false, func(n int64, s uint32) int64 { return n >> s }}, + {64, false, 32, false, func(n uint64, s uint32) uint64 { return n >> s }}, + {64, true, 16, true, func(n int64, s uint16) int64 { return n << s }}, + {64, true, 16, false, func(n int64, s uint16) int64 { return n >> s }}, + {64, false, 16, false, func(n uint64, s uint16) uint64 { return n >> s }}, + {64, true, 8, true, func(n int64, s uint8) int64 { return n << s }}, + {64, true, 8, false, func(n int64, s uint8) int64 { return n >> s }}, + {64, false, 8, false, func(n uint64, s uint8) uint64 { return n >> s }}, + + {32, true, 64, true, func(n int32, s uint64) int32 { return n << s }}, + {32, true, 64, false, func(n int32, s uint64) int32 { return n >> s }}, + {32, false, 64, false, func(n uint32, s uint64) uint32 { return n >> s }}, + {32, true, 32, true, func(n int32, s uint32) int32 { return n << s }}, + {32, true, 32, false, func(n int32, s uint32) int32 { return n >> s }}, + {32, false, 32, false, func(n uint32, s uint32) uint32 { return n >> s }}, + {32, true, 16, true, func(n int32, s uint16) int32 { return n << s }}, + {32, true, 16, false, func(n int32, s uint16) int32 { return n >> s }}, + {32, false, 16, false, func(n uint32, s uint16) uint32 { return n >> s }}, + {32, true, 8, true, func(n int32, s uint8) int32 { return n << s }}, + {32, true, 8, false, func(n int32, s uint8) int32 { return n >> s }}, + {32, false, 8, false, func(n uint32, s uint8) uint32 { return n >> s }}, + + {16, true, 64, true, func(n int16, s uint64) int16 { return n << s }}, + {16, true, 64, false, func(n int16, s uint64) int16 { return n >> s }}, + {16, false, 64, false, func(n uint16, s uint64) uint16 { return n >> s }}, + {16, true, 32, true, func(n int16, s uint32) int16 { return n << s }}, + {16, true, 32, false, func(n int16, s uint32) int16 { return n >> s }}, + {16, false, 32, false, func(n uint16, s uint32) uint16 { return n >> s }}, + {16, true, 16, true, func(n int16, s uint16) int16 { return n << s }}, + {16, true, 16, false, func(n int16, s uint16) int16 { return n >> s }}, + {16, false, 16, false, func(n uint16, s uint16) uint16 { return n >> s }}, + {16, true, 8, true, func(n int16, s uint8) int16 { return n << s }}, + {16, true, 8, false, func(n int16, s uint8) int16 { return n >> s }}, + {16, false, 8, false, func(n uint16, s uint8) uint16 { return n >> s }}, + + {8, true, 64, true, func(n int8, s uint64) int8 { return n << s }}, + {8, true, 64, false, func(n int8, s uint64) int8 { return n >> s }}, + {8, false, 64, false, func(n uint8, s uint64) uint8 { return n >> s }}, + {8, true, 32, true, func(n int8, s uint32) int8 { return n << s }}, + {8, true, 32, false, func(n int8, s uint32) int8 { return n >> s }}, + {8, false, 32, false, func(n uint8, s uint32) uint8 { return n >> s }}, + {8, true, 16, true, func(n int8, s uint16) int8 { return n << s }}, + {8, true, 16, false, func(n int8, s uint16) int8 { return n >> s }}, + {8, false, 16, false, func(n uint8, s uint16) uint8 { return n >> s }}, + {8, true, 8, true, func(n int8, s uint8) int8 { return n << s }}, + {8, true, 8, false, func(n int8, s uint8) int8 { return n >> s }}, + {8, false, 8, false, func(n uint8, s uint8) uint8 { return n >> s }}, + } { + fv := reflect.ValueOf(test.f) + var args [2]reflect.Value + for i := 0; i < test.valueWidth; i++ { + // Build value to be shifted. + var n int64 = 1 + for j := 0; j < i; j++ { + n <<= 1 + } + args[0] = reflect.ValueOf(n).Convert(fv.Type().In(0)) + for s := 0; s <= test.shiftWidth; s++ { + args[1] = reflect.ValueOf(s).Convert(fv.Type().In(1)) + + // Compute desired result. We're testing variable shifts + // assuming constant shifts are correct. + r := n + var op string + switch { + case test.left: + op = "<<" + for j := 0; j < s; j++ { + r <<= 1 + } + switch test.valueWidth { + case 32: + r = int64(int32(r)) + case 16: + r = int64(int16(r)) + case 8: + r = int64(int8(r)) + } + case test.signed: + op = ">>" + switch test.valueWidth { + case 32: + r = int64(int32(r)) + case 16: + r = int64(int16(r)) + case 8: + r = int64(int8(r)) + } + for j := 0; j < s; j++ { + r >>= 1 + } + default: + op = ">>>" + for j := 0; j < s; j++ { + r = int64(uint64(r) >> 1) + } + } + + // Call function. + res := fv.Call(args[:])[0].Convert(reflect.ValueOf(r).Type()) + + if res.Int() != r { + t.Errorf("%s%dx%d(%x,%x)=%x, want %x", op, test.valueWidth, test.shiftWidth, n, s, res.Int(), r) + } + } + } + } +} diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 3bf60ef778..f479900939 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -580,8 +580,8 @@ func (s *state) stmt(n *Node) { case OAS2DOTTYPE: res, resok := s.dottype(n.Rlist.First(), true) - s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0) - s.assign(n.List.Second(), resok, false, false, n.Lineno, 0) + s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0, false) + s.assign(n.List.Second(), resok, false, false, n.Lineno, 0, false) return case ODCL: @@ -700,13 +700,14 @@ func (s *state) stmt(n *Node) { } } var r *ssa.Value + var isVolatile bool needwb := n.Op == OASWB && rhs != nil deref := !canSSAType(t) if deref { if rhs == nil { r = nil // Signal assign to use OpZero. } else { - r = s.addr(rhs, false) + r, isVolatile = s.addr(rhs, false) } } else { if rhs == nil { @@ -755,7 +756,7 @@ func (s *state) stmt(n *Node) { } } - s.assign(n.Left, r, needwb, deref, n.Lineno, skip) + s.assign(n.Left, r, needwb, deref, n.Lineno, skip, isVolatile) case OIF: bThen := s.f.NewBlock(ssa.BlockPlain) @@ -1449,10 +1450,10 @@ func (s *state) expr(n *Node) *ssa.Value { if s.canSSA(n) { return s.variable(n, n.Type) } - addr := s.addr(n, false) + addr, _ := s.addr(n, false) return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) case OCLOSUREVAR: - addr := s.addr(n, false) + addr, _ := s.addr(n, false) return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) case OLITERAL: switch u := n.Val().U.(type) { @@ -1926,7 +1927,9 @@ func (s *state) expr(n *Node) *ssa.Value { return s.expr(n.Left) case OADDR: - return s.addr(n.Left, n.Bounded) + a, _ := s.addr(n.Left, n.Bounded) + // Note we know the volatile result is false because you can't write &f() in Go. + return a case OINDREG: if int(n.Reg) != Thearch.REGSP { @@ -1946,7 +1949,7 @@ func (s *state) expr(n *Node) *ssa.Value { v := s.expr(n.Left) return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v) } - p := s.addr(n, false) + p, _ := s.addr(n, false) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) case ODOTPTR: @@ -1973,11 +1976,11 @@ func (s *state) expr(n *Node) *ssa.Value { } return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem()) case n.Left.Type.IsSlice(): - p := s.addr(n, false) + p, _ := s.addr(n, false) return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem()) case n.Left.Type.IsArray(): // TODO: fix when we can SSA arrays of length 1. - p := s.addr(n, false) + p, _ := s.addr(n, false) return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem()) default: s.Fatalf("bad type for index %v", n.Left.Type) @@ -2142,7 +2145,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value { var slice, addr *ssa.Value if inplace { - addr = s.addr(sn, false) + addr, _ = s.addr(sn, false) slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) } else { slice = s.expr(sn) @@ -2213,15 +2216,21 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value { } // Evaluate args - args := make([]*ssa.Value, 0, nargs) - store := make([]bool, 0, nargs) + type argRec struct { + // if store is true, we're appending the value v. If false, we're appending the + // value at *v. If store==false, isVolatile reports whether the source + // is in the outargs section of the stack frame. + v *ssa.Value + store bool + isVolatile bool + } + args := make([]argRec, 0, nargs) for _, n := range n.List.Slice()[1:] { if canSSAType(n.Type) { - args = append(args, s.expr(n)) - store = append(store, true) + args = append(args, argRec{v: s.expr(n), store: true}) } else { - args = append(args, s.addr(n, false)) - store = append(store, false) + v, isVolatile := s.addr(n, false) + args = append(args, argRec{v: v, isVolatile: isVolatile}) } } @@ -2235,17 +2244,17 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value { // TODO: maybe just one writeBarrier.enabled check? for i, arg := range args { addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i))) - if store[i] { + if arg.store { if haspointers(et) { - s.insertWBstore(et, addr, arg, n.Lineno, 0) + s.insertWBstore(et, addr, arg.v, n.Lineno, 0) } else { - s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem()) + s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg.v, s.mem()) } } else { if haspointers(et) { - s.insertWBmove(et, addr, arg, n.Lineno) + s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile) } else { - s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem()) + s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg.v, s.mem()) } } } @@ -2317,9 +2326,10 @@ const ( // Right has already been evaluated to ssa, left has not. // If deref is true, then we do left = *right instead (and right has already been nil-checked). // If deref is true and right == nil, just do left = 0. +// If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage. // Include a write barrier if wb is true. // skip indicates assignments (at the top level) that can be avoided. -func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask) { +func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask, rightIsVolatile bool) { if left.Op == ONAME && isblank(left) { return } @@ -2360,7 +2370,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, } // Recursively assign the new value we've made to the base of the dot op. - s.assign(left.Left, new, false, false, line, 0) + s.assign(left.Left, new, false, false, line, 0, rightIsVolatile) // TODO: do we need to update named values here? return } @@ -2370,7 +2380,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, return } // Left is not ssa-able. Compute its address. - addr := s.addr(left, false) + addr, _ := s.addr(left, false) if left.Op == ONAME && skip == 0 { s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem()) } @@ -2381,7 +2391,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, return } if wb { - s.insertWBmove(t, addr, right, line) + s.insertWBmove(t, addr, right, line, rightIsVolatile) return } s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem()) @@ -2579,6 +2589,9 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { } i := s.expr(fn.Left) itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i) + if k != callNormal { + s.nilCheck(itab) + } itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab itab = s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), itabidx, itab) if k == callNormal { @@ -2702,10 +2715,12 @@ func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} { } // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. +// Also returns a bool reporting whether the returned value is "volatile", that is it +// points to the outargs section and thus the referent will be clobbered by any call. // The value that the returned Value represents is guaranteed to be non-nil. // If bounded is true then this address does not require a nil check for its operand // even if that would otherwise be implied. -func (s *state) addr(n *Node, bounded bool) *ssa.Value { +func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) { t := Ptrto(n.Type) switch n.Op { case ONAME: @@ -2718,41 +2733,41 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { if n.Xoffset != 0 { v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v) } - return v + return v, false case PPARAM: // parameter slot v := s.decladdrs[n] if v != nil { - return v + return v, false } if n.String() == ".fp" { // Special arg that points to the frame pointer. // (Used by the race detector, others?) aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n}) - return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp) + return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp), false } s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs) - return nil + return nil, false case PAUTO: aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n}) - return s.newValue1A(ssa.OpAddr, t, aux, s.sp) + return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early. // ensure that we reuse symbols for out parameters so // that cse works on their addresses aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n}) - return s.newValue1A(ssa.OpAddr, t, aux, s.sp) + return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false default: s.Unimplementedf("variable address class %v not implemented", classnames[n.Class]) - return nil + return nil, false } case OINDREG: // indirect off a register // used for storing/loading arguments/returns to/from callees if int(n.Reg) != Thearch.REGSP { s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n) - return nil + return nil, false } - return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp) + return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp), true case OINDEX: if n.Left.Type.IsSlice() { a := s.expr(n.Left) @@ -2763,37 +2778,37 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { s.boundsCheck(i, len) } p := s.newValue1(ssa.OpSlicePtr, t, a) - return s.newValue2(ssa.OpPtrIndex, t, p, i) + return s.newValue2(ssa.OpPtrIndex, t, p, i), false } else { // array - a := s.addr(n.Left, bounded) + a, isVolatile := s.addr(n.Left, bounded) i := s.expr(n.Right) i = s.extendIndex(i, Panicindex) len := s.constInt(Types[TINT], n.Left.Type.NumElem()) if !n.Bounded { s.boundsCheck(i, len) } - return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i) + return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i), isVolatile } case OIND: - return s.exprPtr(n.Left, bounded, n.Lineno) + return s.exprPtr(n.Left, bounded, n.Lineno), false case ODOT: - p := s.addr(n.Left, bounded) - return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p) + p, isVolatile := s.addr(n.Left, bounded) + return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile case ODOTPTR: p := s.exprPtr(n.Left, bounded, n.Lineno) - return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p) + return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false case OCLOSUREVAR: return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, - s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8]))) + s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8]))), false case OCONVNOP: - addr := s.addr(n.Left, bounded) - return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type + addr, isVolatile := s.addr(n.Left, bounded) + return s.newValue1(ssa.OpCopy, t, addr), isVolatile // ensure that addr has the right type case OCALLFUNC, OCALLINTER, OCALLMETH: - return s.call(n, callNormal) + return s.call(n, callNormal), true default: s.Unimplementedf("unhandled addr %v", n.Op) - return nil + return nil, false } } @@ -3023,7 +3038,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val // insertWBmove inserts the assignment *left = *right including a write barrier. // t is the type being assigned. -func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) { +func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightIsVolatile bool) { // if writeBarrier.enabled { // typedmemmove(&t, left, right) // } else { @@ -3053,8 +3068,25 @@ func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) { b.AddEdgeTo(bElse) s.startBlock(bThen) - taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb) - s.rtcall(typedmemmove, true, nil, taddr, left, right) + + if !rightIsVolatile { + // Issue typedmemmove call. + taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb) + s.rtcall(typedmemmove, true, nil, taddr, left, right) + } else { + // Copy to temp location if the source is volatile (will be clobbered by + // a function call). Marshaling the args to typedmemmove might clobber the + // value we're trying to move. + tmp := temp(t) + s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, tmp, s.mem()) + tmpaddr, _ := s.addr(tmp, true) + s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), tmpaddr, right, s.mem()) + // Issue typedmemmove call. + taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb) + s.rtcall(typedmemmove, true, nil, taddr, left, tmpaddr) + // Mark temp as dead. + s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, tmp, s.mem()) + } s.endBlock().AddEdgeTo(bEnd) s.startBlock(bElse) @@ -4387,7 +4419,7 @@ func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot { // namedAuto returns a new AUTO variable with the given name and type. func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode { t := typ.(*Type) - s := Lookup(name) + s := &Sym{Name: name, Pkg: autopkg} n := Nod(ONAME, nil, nil) s.Def = n s.Def.Used = true diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index c2abff7b63..1db1cbade8 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1860,7 +1860,13 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) { dot := adddot(NodSym(OXDOT, this.Left, method.Sym)) // generate call - if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) { + // It's not possible to use a tail call when dynamic linking on ppc64le. The + // bad scenario is when a local call is made to the wrapper: the wrapper will + // call the implementation, which might be in a different module and so set + // the TOC to the appropriate value for that module. But if it returns + // directly to the wrapper's caller, nothing will reset it to the correct + // value for that function. + if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(Thearch.LinkArch.Name == "ppc64le" && Ctxt.Flag_dynlink) { // generate tail call: adjust pointer receiver and jump to embedded method. dot = dot.Left // skip final .M // TODO(mdempsky): Remove dependency on dotlist. diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go index aac92fd311..4940c97a90 100644 --- a/src/cmd/compile/internal/gc/swt.go +++ b/src/cmd/compile/internal/gc/swt.go @@ -104,7 +104,7 @@ func typecheckswitch(n *Node) { n.Type = t - var def *Node + var def, niltype *Node for _, ncase := range n.List.Slice() { setlineno(n) if ncase.List.Len() == 0 { @@ -150,6 +150,12 @@ func typecheckswitch(n *Node) { var ptr int switch { case n1.Op == OLITERAL && n1.Type.IsKind(TNIL): + // case nil: + if niltype != nil { + Yyerror("multiple nil cases in type switch (first at %v)", niltype.Line()) + } else { + niltype = ncase + } case n1.Op != OTYPE && n1.Type != nil: // should this be ||? Yyerror("%v is not a type", Nconv(n1, FmtLong)) // reset to original type diff --git a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go index eea6165938..28cdcc339b 100644 --- a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go +++ b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go @@ -208,6 +208,89 @@ func main() { } } } + + // Constant folding for comparisons + for _, s := range szs { + fmt.Fprintf(w, "func TestConstFoldCompare%s(t *testing.T) {\n", s.name) + for _, x := range s.i { + for _, y := range s.i { + fmt.Fprintf(w, "\t{\n") + fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x) + fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y) + if x == y { + fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n") + } + if x != y { + fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n") + } + if x < y { + fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n") + } + if x > y { + fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n") + } + if x <= y { + fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n") + } + if x >= y { + fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n") + } + fmt.Fprintf(w, "\t}\n") + } + } + for _, x := range s.u { + for _, y := range s.u { + fmt.Fprintf(w, "\t{\n") + fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x) + fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y) + if x == y { + fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n") + } + if x != y { + fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n") + } + if x < y { + fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n") + } + if x > y { + fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n") + } + if x <= y { + fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n") + } + if x >= y { + fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n") + } else { + fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n") + } + fmt.Fprintf(w, "\t}\n") + } + } + fmt.Fprintf(w, "}\n") + } + // gofmt result b := w.Bytes() src, err := format.Source(b) diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go index b55af7e25a..270d4c3770 100644 --- a/src/cmd/compile/internal/gc/universe.go +++ b/src/cmd/compile/internal/gc/universe.go @@ -358,9 +358,7 @@ func typeinit() { itable = typPtr(Types[TUINT8]) } -func lexinit1() { - // t = interface { Error() string } - +func makeErrorInterface() *Type { rcvr := typ(TSTRUCT) rcvr.StructType().Funarg = FunargRcvr field := newField() @@ -387,10 +385,18 @@ func lexinit1() { field.Type = f t.SetFields([]*Field{field}) + return t +} + +func lexinit1() { // error type s := Pkglookup("error", builtinpkg) - errortype = t + errortype = makeErrorInterface() errortype.Sym = s + // TODO: If we can prove that it's safe to set errortype.Orig here + // than we don't need the special errortype/errorInterface case in + // bexport.go. See also issue #15920. + // errortype.Orig = makeErrorInterface() s.Def = typenod(errortype) // byte alias diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 7460f183d7..f5d1c98a83 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -246,17 +246,53 @@ // zero shifted. (Lsh64x64 (Const64 [0]) _) -> (Const64 [0]) +(Lsh64x32 (Const64 [0]) _) -> (Const64 [0]) +(Lsh64x16 (Const64 [0]) _) -> (Const64 [0]) +(Lsh64x8 (Const64 [0]) _) -> (Const64 [0]) (Rsh64x64 (Const64 [0]) _) -> (Const64 [0]) +(Rsh64x32 (Const64 [0]) _) -> (Const64 [0]) +(Rsh64x16 (Const64 [0]) _) -> (Const64 [0]) +(Rsh64x8 (Const64 [0]) _) -> (Const64 [0]) (Rsh64Ux64 (Const64 [0]) _) -> (Const64 [0]) -(Lsh32x64 (Const64 [0]) _) -> (Const32 [0]) -(Rsh32x64 (Const64 [0]) _) -> (Const32 [0]) -(Rsh32Ux64 (Const64 [0]) _) -> (Const32 [0]) -(Lsh16x64 (Const64 [0]) _) -> (Const16 [0]) -(Rsh16x64 (Const64 [0]) _) -> (Const16 [0]) -(Rsh16Ux64 (Const64 [0]) _) -> (Const16 [0]) -(Lsh8x64 (Const64 [0]) _) -> (Const8 [0]) -(Rsh8x64 (Const64 [0]) _) -> (Const8 [0]) -(Rsh8Ux64 (Const64 [0]) _) -> (Const8 [0]) +(Rsh64Ux32 (Const64 [0]) _) -> (Const64 [0]) +(Rsh64Ux16 (Const64 [0]) _) -> (Const64 [0]) +(Rsh64Ux8 (Const64 [0]) _) -> (Const64 [0]) +(Lsh32x64 (Const32 [0]) _) -> (Const32 [0]) +(Lsh32x32 (Const32 [0]) _) -> (Const32 [0]) +(Lsh32x16 (Const32 [0]) _) -> (Const32 [0]) +(Lsh32x8 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32x64 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32x32 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32x16 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32x8 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32Ux64 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32Ux32 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32Ux16 (Const32 [0]) _) -> (Const32 [0]) +(Rsh32Ux8 (Const32 [0]) _) -> (Const32 [0]) +(Lsh16x64 (Const16 [0]) _) -> (Const16 [0]) +(Lsh16x32 (Const16 [0]) _) -> (Const16 [0]) +(Lsh16x16 (Const16 [0]) _) -> (Const16 [0]) +(Lsh16x8 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16x64 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16x32 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16x16 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16x8 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16Ux64 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16Ux32 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16Ux16 (Const16 [0]) _) -> (Const16 [0]) +(Rsh16Ux8 (Const16 [0]) _) -> (Const16 [0]) +(Lsh8x64 (Const8 [0]) _) -> (Const8 [0]) +(Lsh8x32 (Const8 [0]) _) -> (Const8 [0]) +(Lsh8x16 (Const8 [0]) _) -> (Const8 [0]) +(Lsh8x8 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8x64 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8x32 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8x16 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8x8 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8Ux64 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8Ux32 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8Ux16 (Const8 [0]) _) -> (Const8 [0]) +(Rsh8Ux8 (Const8 [0]) _) -> (Const8 [0]) // large left shifts of all values, and right shifts of unsigned values (Lsh64x64 _ (Const64 [c])) && uint64(c) >= 64 -> (Const64 [0]) @@ -286,31 +322,31 @@ // ((x >> c1) << c2) >> c3 (Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) - && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) -> (Rsh64Ux64 x (Const64 [c1-c2+c3])) -(Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const32 [c1])) (Const32 [c2])) (Const32 [c3])) - && uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2) - -> (Rsh32Ux64 x (Const32 [int64(int32(c1-c2+c3))])) -(Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3])) - && uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2) - -> (Rsh16Ux64 x (Const16 [int64(int16(c1-c2+c3))])) -(Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3])) - && uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2) - -> (Rsh8Ux64 x (Const8 [int64(int8(c1-c2+c3))])) +(Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + -> (Rsh32Ux64 x (Const64 [c1-c2+c3])) +(Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + -> (Rsh16Ux64 x (Const64 [c1-c2+c3])) +(Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + -> (Rsh8Ux64 x (Const64 [c1-c2+c3])) // ((x << c1) >> c2) << c3 (Lsh64x64 (Rsh64Ux64 (Lsh64x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) - && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) -> (Lsh64x64 x (Const64 [c1-c2+c3])) -(Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const32 [c1])) (Const32 [c2])) (Const32 [c3])) - && uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2) - -> (Lsh32x64 x (Const32 [int64(int32(c1-c2+c3))])) -(Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3])) - && uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2) - -> (Lsh16x64 x (Const16 [int64(int16(c1-c2+c3))])) -(Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3])) - && uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2) - -> (Lsh8x64 x (Const8 [int64(int8(c1-c2+c3))])) +(Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + -> (Lsh32x64 x (Const64 [c1-c2+c3])) +(Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + -> (Lsh16x64 x (Const64 [c1-c2+c3])) +(Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + -> (Lsh8x64 x (Const64 [c1-c2+c3])) // constant comparisons (Eq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c == d)]) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index c702919a57..9f08b3c4eb 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -3823,6 +3823,21 @@ func rewriteValuegeneric_OpLsh16x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh16x16 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh16x32(v *Value, config *Config) bool { @@ -3846,6 +3861,21 @@ func rewriteValuegeneric_OpLsh16x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh16x32 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool { @@ -3886,12 +3916,12 @@ func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Lsh16x64 (Const64 [0]) _) + // match: (Lsh16x64 (Const16 [0]) _) // cond: // result: (Const16 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst16 { break } if v_0.AuxInt != 0 { @@ -3947,9 +3977,9 @@ func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - // match: (Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3])) - // cond: uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2) - // result: (Lsh16x64 x (Const16 [int64(int16(c1-c2+c3))])) + // match: (Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + // result: (Lsh16x64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] if v_0.Op != OpRsh16Ux64 { @@ -3961,27 +3991,27 @@ func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool { } x := v_0_0.Args[0] v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpConst16 { + if v_0_0_1.Op != OpConst64 { break } c1 := v_0_0_1.AuxInt v_0_1 := v_0.Args[1] - if v_0_1.Op != OpConst16 { + if v_0_1.Op != OpConst64 { break } c2 := v_0_1.AuxInt v_1 := v.Args[1] - if v_1.Op != OpConst16 { + if v_1.Op != OpConst64 { break } c3 := v_1.AuxInt - if !(uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpLsh16x64) v.AddArg(x) - v0 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16()) - v0.AuxInt = int64(int16(c1 - c2 + c3)) + v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64()) + v0.AuxInt = c1 - c2 + c3 v.AddArg(v0) return true } @@ -4008,6 +4038,21 @@ func rewriteValuegeneric_OpLsh16x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh16x8 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh32x16(v *Value, config *Config) bool { @@ -4031,6 +4076,21 @@ func rewriteValuegeneric_OpLsh32x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh32x16 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh32x32(v *Value, config *Config) bool { @@ -4054,6 +4114,21 @@ func rewriteValuegeneric_OpLsh32x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh32x32 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh32x64(v *Value, config *Config) bool { @@ -4094,12 +4169,12 @@ func rewriteValuegeneric_OpLsh32x64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Lsh32x64 (Const64 [0]) _) + // match: (Lsh32x64 (Const32 [0]) _) // cond: // result: (Const32 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst32 { break } if v_0.AuxInt != 0 { @@ -4155,9 +4230,9 @@ func rewriteValuegeneric_OpLsh32x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - // match: (Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const32 [c1])) (Const32 [c2])) (Const32 [c3])) - // cond: uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2) - // result: (Lsh32x64 x (Const32 [int64(int32(c1-c2+c3))])) + // match: (Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + // result: (Lsh32x64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] if v_0.Op != OpRsh32Ux64 { @@ -4169,27 +4244,27 @@ func rewriteValuegeneric_OpLsh32x64(v *Value, config *Config) bool { } x := v_0_0.Args[0] v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpConst32 { + if v_0_0_1.Op != OpConst64 { break } c1 := v_0_0_1.AuxInt v_0_1 := v_0.Args[1] - if v_0_1.Op != OpConst32 { + if v_0_1.Op != OpConst64 { break } c2 := v_0_1.AuxInt v_1 := v.Args[1] - if v_1.Op != OpConst32 { + if v_1.Op != OpConst64 { break } c3 := v_1.AuxInt - if !(uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpLsh32x64) v.AddArg(x) - v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32()) - v0.AuxInt = int64(int32(c1 - c2 + c3)) + v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64()) + v0.AuxInt = c1 - c2 + c3 v.AddArg(v0) return true } @@ -4216,6 +4291,21 @@ func rewriteValuegeneric_OpLsh32x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh32x8 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh64x16(v *Value, config *Config) bool { @@ -4239,6 +4329,21 @@ func rewriteValuegeneric_OpLsh64x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh64x16 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh64x32(v *Value, config *Config) bool { @@ -4262,6 +4367,21 @@ func rewriteValuegeneric_OpLsh64x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh64x32 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh64x64(v *Value, config *Config) bool { @@ -4364,7 +4484,7 @@ func rewriteValuegeneric_OpLsh64x64(v *Value, config *Config) bool { return true } // match: (Lsh64x64 (Rsh64Ux64 (Lsh64x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) - // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) // result: (Lsh64x64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] @@ -4391,7 +4511,7 @@ func rewriteValuegeneric_OpLsh64x64(v *Value, config *Config) bool { break } c3 := v_1.AuxInt - if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpLsh64x64) @@ -4424,6 +4544,21 @@ func rewriteValuegeneric_OpLsh64x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh64x8 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh8x16(v *Value, config *Config) bool { @@ -4447,6 +4582,21 @@ func rewriteValuegeneric_OpLsh8x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh8x16 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh8x32(v *Value, config *Config) bool { @@ -4470,6 +4620,21 @@ func rewriteValuegeneric_OpLsh8x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh8x32 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpLsh8x64(v *Value, config *Config) bool { @@ -4510,12 +4675,12 @@ func rewriteValuegeneric_OpLsh8x64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Lsh8x64 (Const64 [0]) _) + // match: (Lsh8x64 (Const8 [0]) _) // cond: // result: (Const8 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst8 { break } if v_0.AuxInt != 0 { @@ -4571,9 +4736,9 @@ func rewriteValuegeneric_OpLsh8x64(v *Value, config *Config) bool { v.AddArg(v0) return true } - // match: (Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3])) - // cond: uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2) - // result: (Lsh8x64 x (Const8 [int64(int8(c1-c2+c3))])) + // match: (Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + // result: (Lsh8x64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] if v_0.Op != OpRsh8Ux64 { @@ -4585,27 +4750,27 @@ func rewriteValuegeneric_OpLsh8x64(v *Value, config *Config) bool { } x := v_0_0.Args[0] v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpConst8 { + if v_0_0_1.Op != OpConst64 { break } c1 := v_0_0_1.AuxInt v_0_1 := v_0.Args[1] - if v_0_1.Op != OpConst8 { + if v_0_1.Op != OpConst64 { break } c2 := v_0_1.AuxInt v_1 := v.Args[1] - if v_1.Op != OpConst8 { + if v_1.Op != OpConst64 { break } c3 := v_1.AuxInt - if !(uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpLsh8x64) v.AddArg(x) - v0 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8()) - v0.AuxInt = int64(int8(c1 - c2 + c3)) + v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64()) + v0.AuxInt = c1 - c2 + c3 v.AddArg(v0) return true } @@ -4632,6 +4797,21 @@ func rewriteValuegeneric_OpLsh8x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Lsh8x8 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpMod16(v *Value, config *Config) bool { @@ -6600,6 +6780,21 @@ func rewriteValuegeneric_OpRsh16Ux16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh16Ux16 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh16Ux32(v *Value, config *Config) bool { @@ -6623,6 +6818,21 @@ func rewriteValuegeneric_OpRsh16Ux32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh16Ux32 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool { @@ -6663,12 +6873,12 @@ func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Rsh16Ux64 (Const64 [0]) _) + // match: (Rsh16Ux64 (Const16 [0]) _) // cond: // result: (Const16 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst16 { break } if v_0.AuxInt != 0 { @@ -6724,9 +6934,9 @@ func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool { v.AddArg(v0) return true } - // match: (Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3])) - // cond: uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2) - // result: (Rsh16Ux64 x (Const16 [int64(int16(c1-c2+c3))])) + // match: (Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + // result: (Rsh16Ux64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] if v_0.Op != OpLsh16x64 { @@ -6738,27 +6948,27 @@ func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool { } x := v_0_0.Args[0] v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpConst16 { + if v_0_0_1.Op != OpConst64 { break } c1 := v_0_0_1.AuxInt v_0_1 := v_0.Args[1] - if v_0_1.Op != OpConst16 { + if v_0_1.Op != OpConst64 { break } c2 := v_0_1.AuxInt v_1 := v.Args[1] - if v_1.Op != OpConst16 { + if v_1.Op != OpConst64 { break } c3 := v_1.AuxInt - if !(uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpRsh16Ux64) v.AddArg(x) - v0 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16()) - v0.AuxInt = int64(int16(c1 - c2 + c3)) + v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64()) + v0.AuxInt = c1 - c2 + c3 v.AddArg(v0) return true } @@ -6785,6 +6995,21 @@ func rewriteValuegeneric_OpRsh16Ux8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh16Ux8 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh16x16(v *Value, config *Config) bool { @@ -6808,6 +7033,21 @@ func rewriteValuegeneric_OpRsh16x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh16x16 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh16x32(v *Value, config *Config) bool { @@ -6831,6 +7071,21 @@ func rewriteValuegeneric_OpRsh16x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh16x32 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh16x64(v *Value, config *Config) bool { @@ -6871,12 +7126,12 @@ func rewriteValuegeneric_OpRsh16x64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Rsh16x64 (Const64 [0]) _) + // match: (Rsh16x64 (Const16 [0]) _) // cond: // result: (Const16 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst16 { break } if v_0.AuxInt != 0 { @@ -6939,6 +7194,21 @@ func rewriteValuegeneric_OpRsh16x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh16x8 (Const16 [0]) _) + // cond: + // result: (Const16 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst16 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst16) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh32Ux16(v *Value, config *Config) bool { @@ -6962,6 +7232,21 @@ func rewriteValuegeneric_OpRsh32Ux16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh32Ux16 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh32Ux32(v *Value, config *Config) bool { @@ -6985,6 +7270,21 @@ func rewriteValuegeneric_OpRsh32Ux32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh32Ux32 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool { @@ -7025,12 +7325,12 @@ func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Rsh32Ux64 (Const64 [0]) _) + // match: (Rsh32Ux64 (Const32 [0]) _) // cond: // result: (Const32 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst32 { break } if v_0.AuxInt != 0 { @@ -7086,9 +7386,9 @@ func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool { v.AddArg(v0) return true } - // match: (Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const32 [c1])) (Const32 [c2])) (Const32 [c3])) - // cond: uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2) - // result: (Rsh32Ux64 x (Const32 [int64(int32(c1-c2+c3))])) + // match: (Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + // result: (Rsh32Ux64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] if v_0.Op != OpLsh32x64 { @@ -7100,27 +7400,27 @@ func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool { } x := v_0_0.Args[0] v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpConst32 { + if v_0_0_1.Op != OpConst64 { break } c1 := v_0_0_1.AuxInt v_0_1 := v_0.Args[1] - if v_0_1.Op != OpConst32 { + if v_0_1.Op != OpConst64 { break } c2 := v_0_1.AuxInt v_1 := v.Args[1] - if v_1.Op != OpConst32 { + if v_1.Op != OpConst64 { break } c3 := v_1.AuxInt - if !(uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpRsh32Ux64) v.AddArg(x) - v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32()) - v0.AuxInt = int64(int32(c1 - c2 + c3)) + v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64()) + v0.AuxInt = c1 - c2 + c3 v.AddArg(v0) return true } @@ -7147,6 +7447,21 @@ func rewriteValuegeneric_OpRsh32Ux8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh32Ux8 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh32x16(v *Value, config *Config) bool { @@ -7170,6 +7485,21 @@ func rewriteValuegeneric_OpRsh32x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh32x16 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh32x32(v *Value, config *Config) bool { @@ -7193,6 +7523,21 @@ func rewriteValuegeneric_OpRsh32x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh32x32 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh32x64(v *Value, config *Config) bool { @@ -7233,12 +7578,12 @@ func rewriteValuegeneric_OpRsh32x64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Rsh32x64 (Const64 [0]) _) + // match: (Rsh32x64 (Const32 [0]) _) // cond: // result: (Const32 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst32 { break } if v_0.AuxInt != 0 { @@ -7301,6 +7646,21 @@ func rewriteValuegeneric_OpRsh32x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh32x8 (Const32 [0]) _) + // cond: + // result: (Const32 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst32 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst32) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh64Ux16(v *Value, config *Config) bool { @@ -7324,6 +7684,21 @@ func rewriteValuegeneric_OpRsh64Ux16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh64Ux16 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh64Ux32(v *Value, config *Config) bool { @@ -7347,6 +7722,21 @@ func rewriteValuegeneric_OpRsh64Ux32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh64Ux32 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh64Ux64(v *Value, config *Config) bool { @@ -7449,7 +7839,7 @@ func rewriteValuegeneric_OpRsh64Ux64(v *Value, config *Config) bool { return true } // match: (Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) - // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) // result: (Rsh64Ux64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] @@ -7476,7 +7866,7 @@ func rewriteValuegeneric_OpRsh64Ux64(v *Value, config *Config) bool { break } c3 := v_1.AuxInt - if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpRsh64Ux64) @@ -7509,6 +7899,21 @@ func rewriteValuegeneric_OpRsh64Ux8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh64Ux8 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh64x16(v *Value, config *Config) bool { @@ -7532,6 +7937,21 @@ func rewriteValuegeneric_OpRsh64x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh64x16 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh64x32(v *Value, config *Config) bool { @@ -7555,6 +7975,21 @@ func rewriteValuegeneric_OpRsh64x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh64x32 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh64x64(v *Value, config *Config) bool { @@ -7663,6 +8098,21 @@ func rewriteValuegeneric_OpRsh64x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh64x8 (Const64 [0]) _) + // cond: + // result: (Const64 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst64 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst64) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh8Ux16(v *Value, config *Config) bool { @@ -7686,6 +8136,21 @@ func rewriteValuegeneric_OpRsh8Ux16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh8Ux16 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh8Ux32(v *Value, config *Config) bool { @@ -7709,6 +8174,21 @@ func rewriteValuegeneric_OpRsh8Ux32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh8Ux32 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool { @@ -7749,12 +8229,12 @@ func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Rsh8Ux64 (Const64 [0]) _) + // match: (Rsh8Ux64 (Const8 [0]) _) // cond: // result: (Const8 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst8 { break } if v_0.AuxInt != 0 { @@ -7810,9 +8290,9 @@ func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool { v.AddArg(v0) return true } - // match: (Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3])) - // cond: uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2) - // result: (Rsh8Ux64 x (Const8 [int64(int8(c1-c2+c3))])) + // match: (Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) + // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) + // result: (Rsh8Ux64 x (Const64 [c1-c2+c3])) for { v_0 := v.Args[0] if v_0.Op != OpLsh8x64 { @@ -7824,27 +8304,27 @@ func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool { } x := v_0_0.Args[0] v_0_0_1 := v_0_0.Args[1] - if v_0_0_1.Op != OpConst8 { + if v_0_0_1.Op != OpConst64 { break } c1 := v_0_0_1.AuxInt v_0_1 := v_0.Args[1] - if v_0_1.Op != OpConst8 { + if v_0_1.Op != OpConst64 { break } c2 := v_0_1.AuxInt v_1 := v.Args[1] - if v_1.Op != OpConst8 { + if v_1.Op != OpConst64 { break } c3 := v_1.AuxInt - if !(uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2)) { + if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) { break } v.reset(OpRsh8Ux64) v.AddArg(x) - v0 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8()) - v0.AuxInt = int64(int8(c1 - c2 + c3)) + v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64()) + v0.AuxInt = c1 - c2 + c3 v.AddArg(v0) return true } @@ -7871,6 +8351,21 @@ func rewriteValuegeneric_OpRsh8Ux8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh8Ux8 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh8x16(v *Value, config *Config) bool { @@ -7894,6 +8389,21 @@ func rewriteValuegeneric_OpRsh8x16(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh8x16 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh8x32(v *Value, config *Config) bool { @@ -7917,6 +8427,21 @@ func rewriteValuegeneric_OpRsh8x32(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh8x32 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpRsh8x64(v *Value, config *Config) bool { @@ -7957,12 +8482,12 @@ func rewriteValuegeneric_OpRsh8x64(v *Value, config *Config) bool { v.AddArg(x) return true } - // match: (Rsh8x64 (Const64 [0]) _) + // match: (Rsh8x64 (Const8 [0]) _) // cond: // result: (Const8 [0]) for { v_0 := v.Args[0] - if v_0.Op != OpConst64 { + if v_0.Op != OpConst8 { break } if v_0.AuxInt != 0 { @@ -8025,6 +8550,21 @@ func rewriteValuegeneric_OpRsh8x8(v *Value, config *Config) bool { v.AddArg(v0) return true } + // match: (Rsh8x8 (Const8 [0]) _) + // cond: + // result: (Const8 [0]) + for { + v_0 := v.Args[0] + if v_0.Op != OpConst8 { + break + } + if v_0.AuxInt != 0 { + break + } + v.reset(OpConst8) + v.AuxInt = 0 + return true + } return false } func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool { diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index aa12aa9dc3..9eb9caf392 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1143,8 +1143,8 @@ func checkCC() { } fatal("cannot invoke C compiler %q: %v\n\n"+ "Go needs a system C compiler for use with cgo.\n"+ - "To set a C compiler, export CC=the-compiler.\n"+ - "To disable cgo, export CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output) + "To set a C compiler, set CC=the-compiler.\n"+ + "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output) } } diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 1a1f7d961b..e56d108ad4 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -432,8 +432,8 @@ func (t *tester) registerTests() { }, }) - if t.cgoEnabled && t.goos != "android" && !t.iOS() { - // Disabled on android and iOS. golang.org/issue/8345 + if t.cgoEnabled && !t.iOS() { + // Disabled on iOS. golang.org/issue/15919 t.tests = append(t.tests, distTest{ name: "cgo_stdio", heading: "../misc/cgo/stdio", @@ -465,11 +465,7 @@ func (t *tester) registerTests() { }) } } - if t.cgoEnabled && t.goos != "android" && !t.iOS() { - // TODO(crawshaw): reenable on android and iOS - // golang.org/issue/8345 - // - // These tests are not designed to run off the host. + if t.cgoEnabled { t.tests = append(t.tests, distTest{ name: "cgo_test", heading: "../misc/cgo/test", @@ -729,16 +725,10 @@ func (t *tester) runHostTest(dirBanner, pkg string) error { func (t *tester) cgoTest(dt *distTest) error { env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ()) - if t.goos == "android" || t.iOS() { - cmd := t.dirCmd("misc/cgo/test", "go", "test", t.tags()) - cmd.Env = env - return cmd.Run() - } - cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto", t.runFlag("")) cmd.Env = env - if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" { + if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" && t.goos != "android" && (t.goos != "darwin" || t.goarch != "arm") { // linkmode=internal fails on dragonfly since errno is a TLS relocation. // linkmode=internal fails on ppc64le because cmd/link doesn't // handle the TOC correctly (issue 15409). @@ -792,8 +782,10 @@ func (t *tester) cgoTest(dt *distTest) error { if err := cmd.Run(); err != nil { fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.") } else { - cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) - cmd.Env = env + if t.goos != "android" { + cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) + cmd.Env = env + } cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test") cmd.Env = env @@ -801,8 +793,10 @@ func (t *tester) cgoTest(dt *distTest) error { cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external`) cmd.Env = env - cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) - cmd.Env = env + if t.goos != "android" { + cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) + cmd.Env = env + } } if pair != "freebsd-amd64" { // clang -pie fails to link misc/cgo/test diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 2a64657732..91875616ce 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -5,1591 +5,1589 @@ // DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh. // Edit the documentation in other files and rerun mkalldocs.sh to generate this one. -/* -Go is a tool for managing Go source code. - -Usage: - - go command [arguments] - -The commands are: - - build compile packages and dependencies - clean remove object files - doc show documentation for package or symbol - 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 - run compile and run Go program - test test packages - tool run specified go tool - version print Go version - vet run go tool vet on packages - -Use "go help [command]" for more information about a command. - -Additional help topics: - - c calling between Go and C - buildmode description of build modes - filetype file types - gopath GOPATH environment variable - environment environment variables - importpath import path syntax - packages description of package lists - testflag description of testing flags - testfunc description of testing functions - -Use "go help [topic]" for more information about that topic. - - -Compile packages and dependencies - -Usage: - - go build [-o output] [-i] [build flags] [packages] - -Build compiles the packages named by the import paths, -along with their dependencies, but it does not install the results. - -If the arguments to build are a list of .go files, build treats -them as a list of source files specifying a single package. - -When compiling a single main package, build writes -the resulting executable to an output file named after -the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') -or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). -The '.exe' suffix is added when writing a Windows executable. - -When compiling multiple packages or a single non-main package, -build compiles the packages but discards the resulting object, -serving only as a check that the packages can be built. - -When compiling packages, build ignores files that end in '_test.go'. - -The -o flag, only allowed when compiling a single package, -forces build to write the resulting executable or object -to the named output file, instead of the default behavior described -in the last two paragraphs. - -The -i flag installs the packages that are dependencies of the target. - -The build flags are shared by the build, clean, get, install, list, run, -and test commands: - - -a - force rebuilding of packages that are already up-to-date. - -n - print the commands but do not run them. - -p n - the number of programs, such as build commands or - test binaries, that can be run in parallel. - The default is the number of CPUs available. - -race - enable data race detection. - Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. - -msan - enable interoperation with memory sanitizer. - Supported only on linux/amd64, - and only with Clang/LLVM as the host C compiler. - -v - print the names of packages as they are compiled. - -work - print the name of the temporary work directory and - do not delete it when exiting. - -x - print the commands. - - -asmflags 'flag list' - arguments to pass on each go tool asm invocation. - -buildmode mode - build mode to use. See 'go help buildmode' for more. - -compiler name - name of compiler to use, as in runtime.Compiler (gccgo or gc). - -gccgoflags 'arg list' - arguments to pass on each gccgo compiler/linker invocation. - -gcflags 'arg list' - arguments to pass on each go tool compile invocation. - -installsuffix suffix - a suffix to use in the name of the package installation directory, - in order to keep output separate from default builds. - If using the -race flag, the install suffix is automatically set to race - or, if set explicitly, has _race appended to it. Likewise for the -msan - flag. Using a -buildmode option that requires non-default compile flags - has a similar effect. - -ldflags 'flag list' - arguments to pass on each go tool link invocation. - -linkshared - link against shared libraries previously created with - -buildmode=shared. - -pkgdir dir - install and load all packages from dir instead of the usual locations. - For example, when building with a non-standard configuration, - use -pkgdir to keep generated packages in a separate location. - -tags 'tag list' - a list of build tags to consider satisfied during the build. - For more information about build tags, see the description of - build constraints in the documentation for the go/build package. - -toolexec 'cmd args' - a program to use to invoke toolchain programs like vet and asm. - For example, instead of running asm, the go command will run - 'cmd args /path/to/asm '. - -The list flags accept a space-separated list of strings. To embed spaces -in an element in the list, surround it with either single or double quotes. - -For more about specifying packages, see 'go help packages'. -For more about where packages and binaries are installed, -run 'go help gopath'. -For more about calling between Go and C/C++, run 'go help c'. - -Note: Build adheres to certain conventions such as those described -by 'go help gopath'. Not all projects can follow these conventions, -however. Installations that have their own conventions or that use -a separate software build system may choose to use lower-level -invocations such as 'go tool compile' and 'go tool link' to avoid -some of the overheads and design decisions of the build tool. - -See also: go install, go get, go clean. - - -Remove object files - -Usage: - - go clean [-i] [-r] [-n] [-x] [build flags] [packages] - -Clean removes object files from package source directories. -The go command builds most objects in a temporary directory, -so go clean is mainly concerned with object files left by other -tools or by manual invocations of go build. - -Specifically, clean removes the following files from each of the -source directories corresponding to the import paths: - - _obj/ old object directory, left from Makefiles - _test/ old test directory, left from Makefiles - _testmain.go old gotest file, left from Makefiles - test.out old test log, left from Makefiles - build.out old test log, left from Makefiles - *.[568ao] object files, left from Makefiles - - DIR(.exe) from go build - DIR.test(.exe) from go test -c - MAINFILE(.exe) from go build MAINFILE.go - *.so from SWIG - -In the list, DIR represents the final path element of the -directory, and MAINFILE is the base name of any Go source -file in the directory that is not included when building -the package. - -The -i flag causes clean to remove the corresponding installed -archive or binary (what 'go install' would create). - -The -n flag causes clean to print the remove commands it would execute, -but not run them. - -The -r flag causes clean to be applied recursively to all the -dependencies of the packages named by the import paths. - -The -x flag causes clean to print remove commands as it executes them. - -For more about build flags, see 'go help build'. - -For more about specifying packages, see 'go help packages'. - - -Show documentation for package or symbol - -Usage: - - go doc [-u] [-c] [package|[package.]symbol[.method]] - -Doc prints the documentation comments associated with the item identified by its -arguments (a package, const, func, type, var, or method) followed by a one-line -summary of each of the first-level items "under" that item (package-level -declarations for a package, methods for a type, etc.). - -Doc accepts zero, one, or two arguments. - -Given no arguments, that is, when run as - - go doc - -it prints the package documentation for the package in the current directory. -If the package is a command (package main), the exported symbols of the package -are elided from the presentation unless the -cmd flag is provided. - -When run with one argument, the argument is treated as a Go-syntax-like -representation of the item to be documented. What the argument selects depends -on what is installed in GOROOT and GOPATH, as well as the form of the argument, -which is schematically one of these: - - go doc - go doc [.] - go doc [.][.] - go doc [.][.] - -The first item in this list matched by the argument is the one whose documentation -is printed. (See the examples below.) However, if the argument starts with a capital -letter it is assumed to identify a symbol or method in the current directory. - -For packages, the order of scanning is determined lexically in breadth-first order. -That is, the package presented is the one that matches the search and is nearest -the root and lexically first at its level of the hierarchy. The GOROOT tree is -always scanned in its entirety before GOPATH. - -If there is no package specified or matched, the package in the current -directory is selected, so "go doc Foo" shows the documentation for symbol Foo in -the current package. - -The package path must be either a qualified path or a proper suffix of a -path. The go tool's usual package mechanism does not apply: package path -elements like . and ... are not implemented by go doc. - -When run with two arguments, the first must be a full package path (not just a -suffix), and the second is a symbol or symbol and method; this is similar to the -syntax accepted by godoc: - - go doc [.] - -In all forms, when matching symbols, lower-case letters in the argument match -either case but upper-case letters match exactly. This means that there may be -multiple matches of a lower-case argument in a package if different symbols have -different cases. If this occurs, documentation for all matches is printed. - -Examples: - go doc - Show documentation for current package. - go doc Foo - Show documentation for Foo in the current package. - (Foo starts with a capital letter so it cannot match - a package path.) - go doc encoding/json - Show documentation for the encoding/json package. - go doc json - Shorthand for encoding/json. - go doc json.Number (or go doc json.number) - Show documentation and method summary for json.Number. - go doc json.Number.Int64 (or go doc json.number.int64) - Show documentation for json.Number's Int64 method. - go doc cmd/doc - Show package docs for the doc command. - go doc -cmd cmd/doc - Show package docs and exported symbols within the doc command. - go doc template.new - Show documentation for html/template's New function. - (html/template is lexically before text/template) - go doc text/template.new # One argument - Show documentation for text/template's New function. - go doc text/template new # Two arguments - Show documentation for text/template's New function. - - At least in the current tree, these invocations all print the - documentation for json.Decoder's Decode method: - - go doc json.Decoder.Decode - go doc json.decoder.decode - go doc json.decode - cd go/src/encoding/json; go doc decode - -Flags: - -c - Respect case when matching symbols. - -cmd - Treat a command (package main) like a regular package. - Otherwise package main's exported symbols are hidden - when showing the package's top-level documentation. - -u - Show documentation for unexported as well as exported - symbols and methods. - - -Print Go environment information - -Usage: - - go env [var ...] - -Env prints Go environment information. - -By default env prints information as a shell script -(on Windows, a batch file). If one or more variable -names is given as arguments, env prints the value of -each named variable on its own line. - - -Run go tool fix on packages - -Usage: - - go fix [packages] - -Fix runs the Go fix command on the packages named by the import paths. - -For more about fix, see 'go doc cmd/fix'. -For more about specifying packages, see 'go help packages'. - -To run fix with specific options, run 'go tool fix'. - -See also: go fmt, go vet. - - -Run gofmt on package sources - -Usage: - - go fmt [-n] [-x] [packages] - -Fmt runs the command 'gofmt -l -w' on the packages named -by the import paths. It prints the names of the files that are modified. - -For more about gofmt, see 'go doc cmd/gofmt'. -For more about specifying packages, see 'go help packages'. - -The -n flag prints commands that would be executed. -The -x flag prints commands as they are executed. - -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] [-n] [-v] [-x] [build flags] [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. - $GOLINE - The line number of the directive in the source file. - $GOPACKAGE - The name of the package of the file containing the directive. - $DOLLAR - A dollar sign. - -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 full original source text (excluding - any trailing spaces and final newline) matches the - expression. - -It also accepts the standard build flags including -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 build flags, see 'go help build'. - -For more about specifying packages, see 'go help packages'. - - -Download and install packages and dependencies - -Usage: - - go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages] - -Get downloads and installs the packages named by the import paths, -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. - -The -insecure flag permits fetching from repositories and resolving -custom domains using insecure schemes such as HTTP. Use with caution. - -The -t flag instructs get to also download the packages required to build -the tests for the specified packages. - -The -u flag instructs get to use the network to update the named packages -and their dependencies. By default, get uses the network to check out -missing packages but does not use it to look for updates to existing packages. - -Get also accepts build flags to control the installation. See 'go help build'. - -When checking out a new package, get creates the target directory -GOPATH/src/. If the GOPATH contains multiple entries, -get uses the first one. See 'go help gopath'. - -When checking out or updating a package, get looks for a branch or tag -that matches the locally installed version of Go. The most important -rule is that if the local installation is running version "go1", get -searches for a branch or tag named "go1". If no such version exists it -retrieves the most recent version of the package. - -Unless vendoring support is disabled (see 'go help gopath'), -when go get checks out or updates a Git repository, -it also updates any git submodules referenced by the repository. - -Get never checks out or updates code stored in vendor directories. - -For more about specifying packages, see 'go help packages'. - -For more about how 'go get' finds source code to -download, see 'go help importpath'. - -See also: go build, go install, go clean. - - -Compile and install packages and dependencies - -Usage: - - go install [build flags] [packages] - -Install compiles and installs the packages named by the import paths, -along with their dependencies. - -For more about the build flags, see 'go help build'. -For more about specifying packages, see 'go help packages'. - -See also: go build, go get, go clean. - - -List packages - -Usage: - - go list [-e] [-f format] [-json] [build flags] [packages] - -List lists the packages named by the import paths, one per line. - -The default output shows the package import path: - - bytes - encoding/json - github.com/gorilla/mux - golang.org/x/net/html - -The -f flag specifies an alternate format for the list, using the -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 - ImportComment string // path in import comment on package statement - Name string // package name - Doc string // package documentation string - Target string // install path - Shlib string // the shared library that contains this package (only set when -linkshared) - 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? - StaleReason string // explanation for Stale==true - Root string // Go root or Go path dir containing this package - ConflictDir string // this directory shadows Dir in $GOPATH - BinaryOnly bool // binary-only package: cannot be recompiled from sources - - // Source files - 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 - FFiles []string // .f, .F, .for and .f90 Fortran 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 - CgoCPPFLAGS []string // cgo: flags for C preprocessor - CgoCXXFLAGS []string // cgo: flags for C++ compiler - CgoFFLAGS []string // cgo: flags for Fortran compiler - CgoLDFLAGS []string // cgo: flags for linker - CgoPkgConfig []string // cgo: pkg-config names - - // Dependency information - Imports []string // import paths used by this package - Deps []string // all (recursively) imported dependencies - - // Error information - Incomplete bool // this package or a dependency has an error - Error *PackageError // error loading package - DepsErrors []*PackageError // errors loading dependencies - - TestGoFiles []string // _test.go files in package - TestImports []string // imports from TestGoFiles - XTestGoFiles []string // _test.go files outside package - XTestImports []string // imports from XTestGoFiles - } - -The error information, if any, is - - type PackageError struct { - ImportStack []string // shortest path from package named on command line to this one - Pos string // position of error (if present, file:line:col) - Err string // the error itself - } - -The template function "join" calls strings.Join. - -The template function "context" returns the build context, defined as: - - type Context struct { - GOARCH string // target architecture - GOOS string // target operating system - GOROOT string // Go root - GOPATH string // Go path - CgoEnabled bool // whether cgo can be used - UseAllFiles bool // use files regardless of +build lines, file names - Compiler string // compiler to assume when computing target paths - BuildTags []string // build constraints to match in +build lines - ReleaseTags []string // releases the current release is compatible with - InstallSuffix string // suffix to use in the name of the install dir - } - -For more information about the meaning of these fields see the documentation -for the go/build package's Context type. - -The -json flag causes the package data to be printed in JSON format -instead of using the template format. - -The -e flag changes the handling of erroneous packages, those that -cannot be found or are malformed. By default, the list command -prints an error to standard error for each erroneous package and -omits the packages from consideration during the usual printing. -With the -e flag, the list command never prints errors to standard -error and instead processes the erroneous packages with the usual -printing. Erroneous packages will have a non-empty ImportPath and -a non-nil Error field; other information may or may not be missing -(zeroed). - -For more about build flags, see 'go help build'. - -For more about specifying packages, see 'go help packages'. - - -Compile and run Go program - -Usage: - - go run [build flags] [-exec xprog] gofiles... [arguments...] - -Run compiles and runs the main package comprising the named Go source files. -A Go source file is defined to be a file ending in a literal ".go" suffix. - -By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. -If the -exec flag is given, 'go run' invokes the binary using xprog: - 'xprog a.out arguments...'. -If the -exec flag is not given, GOOS or GOARCH is different from the system -default, and a program named go_$GOOS_$GOARCH_exec can be found -on the current search path, 'go run' invokes the binary using that program, -for example 'go_nacl_386_exec a.out arguments...'. This allows execution of -cross-compiled programs when a simulator or other execution method is -available. - -For more about build flags, see 'go help build'. - -See also: go build. - - -Test packages - -Usage: - - go test [build/test flags] [packages] [build/test flags & test binary flags] - -'Go test' automates testing the packages named by the import paths. -It prints a summary of the test results in the format: - - ok archive/tar 0.011s - FAIL archive/zip 0.022s - ok compress/gzip 0.033s - ... - -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". -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. -Each listed package causes the execution of a separate test binary. - -Test files that declare a package with the suffix "_test" will be compiled as a -separate package, and then linked and run with the main test binary. - -The go tool will ignore a directory named "testdata", making it available -to hold ancillary data needed by the tests. - -By default, go test needs no arguments. It compiles and tests the package -with source in the current directory, including tests, and runs the tests. - -The package is built in a temporary directory so it does not interfere with the -non-test installation. - -In addition to the build flags, the flags handled by 'go test' itself are: - - -args - Pass the remainder of the command line (everything after -args) - to the test binary, uninterpreted and unchanged. - Because this flag consumes the remainder of the command line, - the package list (if present) must appear before this flag. - - -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. - - -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. - -For more about build flags, see 'go help build'. -For more about specifying packages, see 'go help packages'. - -See also: go build, go vet. - - -Run specified go tool - -Usage: - - go tool [-n] command [args...] - -Tool runs the go tool command identified by the arguments. -With no arguments it prints the list of known tools. - -The -n flag causes tool to print the command that would be -executed but not execute it. - -For more about each tool command, see 'go tool command -h'. - - -Print Go version - -Usage: - - go version - -Version prints the Go version, as reported by runtime.Version. - - -Run go tool vet on packages - -Usage: - - go vet [-n] [-x] [build flags] [packages] - -Vet runs the Go vet command on the packages named by the import paths. - -For more about vet, see 'go doc cmd/vet'. -For more about specifying packages, see 'go help packages'. - -To run the vet tool with specific options, run 'go tool vet'. - -The -n flag prints commands that would be executed. -The -x flag prints commands as they are executed. - -For more about build flags, see 'go help build'. - -See also: go fmt, go fix. - - -Calling between Go and C - -There are two different ways to call between Go and C/C++ code. - -The first is the cgo tool, which is part of the Go distribution. For -information on how to use it see the cgo documentation (go doc cmd/cgo). - -The second is the SWIG program, which is a general tool for -interfacing between languages. For information on SWIG see -http://swig.org/. When running go build, any file with a .swig -extension will be passed to SWIG. Any file with a .swigcxx extension -will be passed to SWIG with the -c++ option. - -When either cgo or SWIG is used, go build will pass any .c, .m, .s, -or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++ -compiler. The CC or CXX environment variables may be set to determine -the C or C++ compiler, respectively, to use. - - -Description of build modes - -The 'go build' and 'go install' commands take a -buildmode argument which -indicates which kind of object file is to be built. Currently supported values -are: - - -buildmode=archive - Build the listed non-main packages into .a files. Packages named - main are ignored. - - -buildmode=c-archive - Build the listed main package, plus all packages it imports, - into a C archive file. The only callable symbols will be those - functions exported using a cgo //export comment. Requires - exactly one main package to be listed. - - -buildmode=c-shared - Build the listed main packages, plus all packages that they - import, into C shared libraries. The only callable symbols will - be those functions exported using a cgo //export comment. - Non-main packages are ignored. - - -buildmode=default - Listed main packages are built into executables and listed - non-main packages are built into .a files (the default - behavior). - - -buildmode=shared - Combine all the listed non-main packages into a single shared - library that will be used when building with the -linkshared - option. Packages named main are ignored. - - -buildmode=exe - Build the listed main packages and everything they import into - executables. Packages not named main are ignored. - - -buildmode=pie - Build the listed main packages and everything they import into - position independent executables (PIE). Packages not named - main are ignored. - - -File types - -The go command examines the contents of a restricted set of files -in each directory. It identifies which files to examine based on -the extension of the file name. These extensions are: - - .go - Go source files. - .c, .h - C source files. - If the package uses cgo or SWIG, these will be compiled with the - OS-native compiler (typically gcc); otherwise they will - trigger an error. - .cc, .cpp, .cxx, .hh, .hpp, .hxx - C++ source files. Only useful with cgo or SWIG, and always - compiled with the OS-native compiler. - .m - Objective-C source files. Only useful with cgo, and always - compiled with the OS-native compiler. - .s, .S - Assembler source files. - If the package uses cgo or SWIG, these will be assembled with the - OS-native assembler (typically gcc (sic)); otherwise they - will be assembled with the Go assembler. - .swig, .swigcxx - SWIG definition files. - .syso - System object files. - -Files of each of these types except .syso may contain build -constraints, but the go command stops scanning for build constraints -at the first item in the file that is not a blank line or //-style -line comment. See the go/build package documentation for -more details. - -Non-test Go source files can also include a //go:binary-only-package -comment, indicating that the package sources are included -for documentation only and must not be used to build the -package binary. This enables distribution of Go packages in -their compiled form alone. See the go/build package documentation -for more details. - - -GOPATH environment variable - -The Go path is used to resolve import statements. -It is implemented by and documented in the go/build package. - -The GOPATH environment variable lists places to look for Go code. -On Unix, the value is a colon-separated string. -On Windows, the value is a semicolon-separated string. -On Plan 9, the value is a list. - -GOPATH must be set to get, build and install packages outside the -standard Go tree. - -Each directory listed in GOPATH must have a prescribed structure: - -The src directory holds source code. The path below src -determines the import path or executable name. - -The pkg directory holds installed package objects. -As in the Go tree, each target operating system and -architecture pair has its own subdirectory of pkg -(pkg/GOOS_GOARCH). - -If DIR is a directory listed in the GOPATH, a package with -source in DIR/src/foo/bar can be imported as "foo/bar" and -has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". - -The bin directory holds compiled commands. -Each command is named for its source directory, but only -the final element, not the entire path. That is, the -command with source in DIR/src/foo/quux is installed into -DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped -so that you can add DIR/bin to your PATH to get at the -installed commands. If the GOBIN environment variable is -set, commands are installed to the directory it names instead -of DIR/bin. GOBIN must be an absolute path. - -Here's an example directory layout: - - GOPATH=/home/user/gocode - - /home/user/gocode/ - src/ - foo/ - bar/ (go code in package bar) - x.go - quux/ (go code in package main) - y.go - bin/ - quux (installed command) - pkg/ - linux_amd64/ - foo/ - bar.a (installed package object) - -Go searches each directory listed in GOPATH to find source code, -but new packages are always downloaded into the first directory -in the list. - -See https://golang.org/doc/code.html for an example. - -Internal Directories - -Code in or below a directory named "internal" is importable only -by code in the directory tree rooted at the parent of "internal". -Here's an extended version of the directory layout above: - - /home/user/gocode/ - src/ - crash/ - bang/ (go code in package bang) - b.go - foo/ (go code in package foo) - f.go - bar/ (go code in package bar) - x.go - internal/ - baz/ (go code in package baz) - z.go - quux/ (go code in package main) - y.go - - -The code in z.go is imported as "foo/internal/baz", but that -import statement can only appear in source files in the subtree -rooted at foo. The source files foo/f.go, foo/bar/x.go, and -foo/quux/y.go can all import "foo/internal/baz", but the source file -crash/bang/b.go cannot. - -See https://golang.org/s/go14internal for details. - -Vendor Directories - -Go 1.6 includes support for using local copies of external dependencies -to satisfy imports of those dependencies, often referred to as vendoring. - -Code below a directory named "vendor" is importable only -by code in the directory tree rooted at the parent of "vendor", -and only using an import path that omits the prefix up to and -including the vendor element. - -Here's the example from the previous section, -but with the "internal" directory renamed to "vendor" -and a new foo/vendor/crash/bang directory added: - - /home/user/gocode/ - src/ - crash/ - bang/ (go code in package bang) - b.go - foo/ (go code in package foo) - f.go - bar/ (go code in package bar) - x.go - vendor/ - crash/ - bang/ (go code in package bang) - b.go - baz/ (go code in package baz) - z.go - quux/ (go code in package main) - y.go - -The same visibility rules apply as for internal, but the code -in z.go is imported as "baz", not as "foo/vendor/baz". - -Code in vendor directories deeper in the source tree shadows -code in higher directories. Within the subtree rooted at foo, an import -of "crash/bang" resolves to "foo/vendor/crash/bang", not the -top-level "crash/bang". - -Code in vendor directories is not subject to import path -checking (see 'go help importpath'). - -When 'go get' checks out or updates a git repository, it now also -updates submodules. - -Vendor directories do not affect the placement of new repositories -being checked out for the first time by 'go get': those are always -placed in the main GOPATH, never in a vendor subtree. - -See https://golang.org/s/go15vendor for details. - - -Environment variables - -The go command, and the tools it invokes, examine a few different -environment variables. For many of these, you can see the default -value of on your system by running 'go env NAME', where NAME is the -name of the variable. - -General-purpose environment variables: - - GCCGO - The gccgo command to run for 'go build -compiler=gccgo'. - GOARCH - The architecture, or processor, for which to compile code. - Examples are amd64, 386, arm, ppc64. - GOBIN - The directory where 'go install' will install a command. - GOOS - The operating system for which to compile code. - Examples are linux, darwin, windows, netbsd. - GOPATH - See 'go help gopath'. - GORACE - Options for the race detector. - See https://golang.org/doc/articles/race_detector.html. - GOROOT - The root of the go tree. - -Environment variables for use with cgo: - - CC - The command to use to compile C code. - CGO_ENABLED - Whether the cgo command is supported. Either 0 or 1. - CGO_CFLAGS - Flags that cgo will pass to the compiler when compiling - C code. - CGO_CPPFLAGS - Flags that cgo will pass to the compiler when compiling - C or C++ code. - CGO_CXXFLAGS - Flags that cgo will pass to the compiler when compiling - C++ code. - CGO_LDFLAGS - Flags that cgo will pass to the compiler when linking. - CXX - The command to use to compile C++ code. - -Architecture-specific environment variables: - - GOARM - For GOARCH=arm, the ARM architecture for which to compile. - Valid values are 5, 6, 7. - GO386 - For GOARCH=386, the floating point instruction set. - Valid values are 387, sse2. - -Special-purpose environment variables: - - GOROOT_FINAL - The root of the installed Go tree, when it is - installed in a location other than where it is built. - File names in stack traces are rewritten from GOROOT to - GOROOT_FINAL. - GO_EXTLINK_ENABLED - Whether the linker should use external linking mode - when using -linkmode=auto with code that uses cgo. - Set to 0 to disable external linking mode, 1 to enable it. - - -Import path syntax - -An import path (see 'go help packages') denotes a package -stored in the local file system. In general, an import path denotes -either a standard package (such as "unicode/utf8") or a package -found in one of the work spaces (see 'go help gopath'). - -Relative import paths - -An import path beginning with ./ or ../ is called a relative path. -The toolchain supports relative import paths as a shortcut in two ways. - -First, a relative path can be used as a shorthand on the command line. -If you are working in the directory containing the code imported as -"unicode" and want to run the tests for "unicode/utf8", you can type -"go test ./utf8" instead of needing to specify the full path. -Similarly, in the reverse situation, "go test .." will test "unicode" from -the "unicode/utf8" directory. Relative patterns are also allowed, like -"go test ./..." to test all subdirectories. See 'go help packages' for details -on the pattern syntax. - -Second, if you are compiling a Go program not in a work space, -you can use a relative path in an import statement in that program -to refer to nearby code also not in a work space. -This makes it easy to experiment with small multipackage programs -outside of the usual work spaces, but such programs cannot be -installed with "go install" (there is no work space in which to install them), -so they are rebuilt from scratch each time they are built. -To avoid ambiguity, Go programs cannot use relative import paths -within a work space. - -Remote import paths - -Certain import paths also -describe how to obtain the source code for the package using -a revision control system. - -A few common code hosting sites have special syntax: - - Bitbucket (Git, Mercurial) - - import "bitbucket.org/user/project" - import "bitbucket.org/user/project/sub/directory" - - GitHub (Git) - - import "github.com/user/project" - import "github.com/user/project/sub/directory" - - Launchpad (Bazaar) - - import "launchpad.net/project" - import "launchpad.net/project/series" - import "launchpad.net/project/series/sub/directory" - - 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 -from a tag in the HTML. - -To declare the code location, an import path of the form - - repository.vcs/path - -specifies the given repository, with or without the .vcs suffix, -using the named version control system, and then the path inside -that repository. The supported version control systems are: - - Bazaar .bzr - Git .git - Mercurial .hg - Subversion .svn - -For example, - - import "example.org/user/foo.hg" - -denotes the root directory of the Mercurial repository at -example.org/user/foo or foo.hg, and - - import "example.org/repo.git/foo/bar" - -denotes the foo/bar directory of the Git repository at -example.org/repo or repo.git. - -When a version control system supports multiple protocols, -each is tried in turn when downloading. For example, a Git -download tries https://, then git+ssh://. - -If the import path is not a known code hosting site and also lacks a -version control qualifier, the go tool attempts to fetch the import -over https/http and looks for a tag in the document's HTML -. - -The meta tag has the form: - - - -The import-prefix is the import path corresponding to the repository -root. It must be a prefix or an exact match of the package being -fetched with "go get". If it's not an exact match, another http -request is made at the prefix to verify the tags match. - -The meta tag should appear as early in the file as possible. -In particular, it should appear before any raw JavaScript or CSS, -to avoid confusing the go command's restricted parser. - -The vcs is one of "git", "hg", "svn", etc, - -The repo-root is the root of the version control system -containing a scheme and not containing a .vcs qualifier. - -For example, - - import "example.org/pkg/foo" - -will result in the following requests: - - https://example.org/pkg/foo?go-get=1 (preferred) - http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) - -If that page contains the meta tag - - - -the go tool will verify that https://example.org/?go-get=1 contains the -same meta tag and then git clone https://code.org/r/p/exproj into -GOPATH/src/example.org. - -New downloaded packages are written to the first directory -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 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. - -If vendoring is enabled (see 'go help gopath'), then import path checking is -disabled for code found within vendor trees. This makes it possible to copy -code into alternate locations in vendor trees without needing to update import -comments. - -See https://golang.org/s/go14customimport for details. - - -Description of package lists - -Many commands apply to a set of packages: - - go action [packages] - -Usually, [packages] is a list of import paths. - -An import path that is a rooted path or that begins with -a . or .. element is interpreted as a file system path and -denotes the package in that directory. - -Otherwise, the import path P denotes the package found in -the directory DIR/src/P for some DIR listed in the GOPATH -environment variable (see 'go help gopath'). - -If no import paths are given, the action applies to the -package in the current directory. - -There are four reserved names for paths that should not be used -for packages to be built with the go tool: - -- "main" denotes the top-level package in a stand-alone executable. - -- "all" expands to all package directories found in all the GOPATH -trees. For example, 'go list all' lists all the packages on the local -system. - -- "std" is like all but expands to just the packages in the standard -Go library. - -- "cmd" expands to the Go repository's commands and their -internal libraries. - -An import path is a pattern if it includes one or more "..." wildcards, -each of which can match any string, including the empty string and -strings containing slashes. Such a pattern expands to all package -directories found in the GOPATH trees with names matching the -patterns. As a special case, x/... matches x as well as x's subdirectories. -For example, net/... expands to net and packages in its subdirectories. - -An import path can also name a package to be downloaded from -a remote repository. Run 'go help importpath' for details. - -Every package in a program must have a unique import path. -By convention, this is arranged by starting each path with a -unique prefix that belongs to you. For example, paths used -internally at Google all begin with 'google', and paths -denoting remote repositories begin with the path to the code, -such as 'github.com/user/repo'. - -Packages in a program need not have unique package names, -but there are two reserved package names with special meaning. -The name main indicates a command, not a library. -Commands are built into binaries and cannot be imported. -The name documentation indicates documentation for -a non-Go program in the directory. Files in package documentation -are ignored by the go command. - -As a special case, if the package list is a list of .go files from a -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. - -Directory and file names that begin with "." or "_" are ignored -by the go tool, as are directories named "testdata". - - -Description of testing flags - -The 'go test' command takes both flags that apply to 'go test' itself -and flags that apply to the resulting test binary. - -Several of the flags control profiling and write an execution profile -suitable for "go tool pprof"; run "go tool pprof -h" for more -information. The --alloc_space, --alloc_objects, and --show_bytes -options of pprof control how the information is presented. - -The following flags are recognized by the 'go test' command and -control the execution of any test: - - -bench regexp - Run (sub)benchmarks matching a regular expression. - The given regular expression is split into smaller ones by - top-level '/', where each must match the corresponding part of a - benchmark's identifier. - By default, no benchmarks run. To run all benchmarks, - use '-bench .' or '-bench=.'. - - -benchmem - Print memory allocation statistics for benchmarks. - - -benchtime t - Run enough iterations of each benchmark to take t, specified - as a time.Duration (for example, -benchtime 1h30s). - The default is 1 second (1s). - - -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 - calling runtime.SetBlockProfileRate with n. - See 'go doc runtime.SetBlockProfileRate'. - The profiler aims to sample, on average, one blocking event every - n nanoseconds the program spends blocked. By default, - if -test.blockprofile is set without this flag, all blocking events - are recorded, equivalent to -test.blockprofilerate=1. - - -count n - Run each test and benchmark n times (default 1). - If -cpu is set, run n times for each GOMAXPROCS value. - Examples are always run once. - - -cover - Enable coverage analysis. - - -covermode set,count,atomic - Set the mode for coverage analysis for the package[s] - being tested. The default is "set" unless -race is enabled, - in which case it is "atomic". - The values: - set: bool: does this statement run? - count: int: how many times does this statement run? - atomic: int: count, but correct in multithreaded tests; - significantly more expensive. - Sets -cover. - - -coverpkg pkg1,pkg2,pkg3 - Apply coverage analysis in each test to the given list of packages. - The default is for each test to analyze only the package being tested. - Packages are specified as import paths. - Sets -cover. - - -coverprofile cover.out - Write a coverage profile to the file after all tests have passed. - Sets -cover. - - -cpu 1,2,4 - Specify a list of GOMAXPROCS values for which the tests or - benchmarks should be executed. The default is the current value - of GOMAXPROCS. - - -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 file after all tests have passed. - Writes test binary as -c would. - - -memprofilerate n - Enable more precise (and expensive) memory profiles by setting - runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. - To profile all memory allocations, use -test.memprofilerate=1 - and pass --alloc_space flag to the pprof tool. - - -outputdir directory - Place output files from profiling in the specified directory, - by default the directory in which "go test" is running. - - -parallel n - Allow parallel execution of test functions that call t.Parallel. - The value of this flag is the maximum number of tests to run - simultaneously; by default, it is set to the value of GOMAXPROCS. - Note that -parallel only applies within a single test binary. - The 'go test' command may run tests for different packages - in parallel as well, according to the setting of the -p flag - (see 'go help build'). - - -run regexp - Run only those tests and examples matching the regular expression. - For tests the regular expression is split into smaller ones by - top-level '/', where each must match the corresponding part of a - test's identifier. - - -short - Tell long-running tests to shorten their run time. - It is off by default but set during all.bash so that installing - the Go tree can run a sanity check but not spend time running - exhaustive tests. - - -timeout t - If a test runs longer than t, panic. - The default is 10 minutes (10m). - - -trace trace.out - Write an execution trace to the specified file before exiting. - - -v - Verbose output: log all tests as they are run. Also print all - text from Log and Logf calls even if the test succeeds. - -Each of these flags is also recognized with an optional 'test.' prefix, -as in -test.v. When invoking the generated test binary (the result of -'go test -c') directly, however, the prefix is mandatory. - -The 'go test' command rewrites or removes recognized flags, -as appropriate, both before and after the optional package list, -before invoking the test binary. - -For instance, the command - - go test -v -myflag testdata -cpuprofile=prof.out -x - -will compile the test binary and then run it as - - pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out - -(The -x flag is removed because it applies only to the go command's -execution, not to the test itself.) - -The test flags that generate profiles (other than for coverage) also -leave the test binary in pkg.test for use when analyzing the profiles. - -When 'go test' runs a test binary, it does so from within the -corresponding package's source code directory. Depending on the test, -it may be necessary to do the same when invoking a generated test -binary directly. - -The command-line package list, if present, must appear before any -flag not known to the go test command. Continuing the example above, -the package list would have to appear before -myflag, but could appear -on either side of -v. - -To keep an argument for a test binary from being interpreted as a -known flag or a package name, use -args (see 'go help test') which -passes the remainder of the command line through to the test binary -uninterpreted and unaltered. - -For instance, the command - - go test -v -args -x -v - -will compile the test binary and then run it as - - pkg.test -test.v -x -v - -Similarly, - - go test -args math - -will compile the test binary and then run it as - - pkg.test math - -In the first example, the -x and the second -v are passed through to the -test binary unchanged and with no effect on the go command itself. -In the second example, the argument math is passed through to the test -binary, instead of being interpreted as the package list. - - -Description of testing functions - -The 'go test' command expects to find test, benchmark, and example functions -in the "*_test.go" files corresponding to the package under test. - -A test function is one named TestXXX (where XXX is any alphanumeric string -not starting with a lower case letter) and should have the signature, - - func TestXXX(t *testing.T) { ... } - -A benchmark function is one named BenchmarkXXX and should have the signature, - - func BenchmarkXXX(b *testing.B) { ... } - -An example function is similar to a test function but, instead of using -*testing.T to report success or failure, prints output to os.Stdout. -If the last comment in the function starts with "Output:" then the output -is compared exactly against the comment (see examples below). If the last -comment begins with "Unordered output:" then the output is compared to the -comment, however the order of the lines is ignored. An example with no such -comment, or with no text after "Output:" is compiled but not executed. - -Godoc displays the body of ExampleXXX to demonstrate the use -of the function, constant, or variable XXX. An example of a method M with -receiver type T or *T is named ExampleT_M. There may be multiple examples -for a given function, constant, or variable, distinguished by a trailing _xxx, -where xxx is a suffix not beginning with an upper case letter. - -Here is an example of an example: - - func ExamplePrintln() { - Println("The output of\nthis example.") - // Output: The output of - // this example. - } - -Here is another example where the ordering of the output is ignored: - - func ExamplePerm() { - for _, value := range Perm(4) { - fmt.Println(value) - } - - // Unordered output: 4 - // 2 - // 1 - // 3 - // 0 - } - -The entire test file is presented as the example when it contains a single -example function, at least one other function, type, variable, or constant -declaration, and no test or benchmark functions. - -See the documentation of the testing package for more information. - - -*/ +// Go is a tool for managing Go source code. +// +// Usage: +// +// go command [arguments] +// +// The commands are: +// +// build compile packages and dependencies +// clean remove object files +// doc show documentation for package or symbol +// 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 +// run compile and run Go program +// test test packages +// tool run specified go tool +// version print Go version +// vet run go tool vet on packages +// +// Use "go help [command]" for more information about a command. +// +// Additional help topics: +// +// c calling between Go and C +// buildmode description of build modes +// filetype file types +// gopath GOPATH environment variable +// environment environment variables +// importpath import path syntax +// packages description of package lists +// testflag description of testing flags +// testfunc description of testing functions +// +// Use "go help [topic]" for more information about that topic. +// +// +// Compile packages and dependencies +// +// Usage: +// +// go build [-o output] [-i] [build flags] [packages] +// +// Build compiles the packages named by the import paths, +// along with their dependencies, but it does not install the results. +// +// If the arguments to build are a list of .go files, build treats +// them as a list of source files specifying a single package. +// +// When compiling a single main package, build writes +// the resulting executable to an output file named after +// the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') +// or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). +// The '.exe' suffix is added when writing a Windows executable. +// +// When compiling multiple packages or a single non-main package, +// build compiles the packages but discards the resulting object, +// serving only as a check that the packages can be built. +// +// When compiling packages, build ignores files that end in '_test.go'. +// +// The -o flag, only allowed when compiling a single package, +// forces build to write the resulting executable or object +// to the named output file, instead of the default behavior described +// in the last two paragraphs. +// +// The -i flag installs the packages that are dependencies of the target. +// +// The build flags are shared by the build, clean, get, install, list, run, +// and test commands: +// +// -a +// force rebuilding of packages that are already up-to-date. +// -n +// print the commands but do not run them. +// -p n +// the number of programs, such as build commands or +// test binaries, that can be run in parallel. +// The default is the number of CPUs available. +// -race +// enable data race detection. +// Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. +// -msan +// enable interoperation with memory sanitizer. +// Supported only on linux/amd64, +// and only with Clang/LLVM as the host C compiler. +// -v +// print the names of packages as they are compiled. +// -work +// print the name of the temporary work directory and +// do not delete it when exiting. +// -x +// print the commands. +// +// -asmflags 'flag list' +// arguments to pass on each go tool asm invocation. +// -buildmode mode +// build mode to use. See 'go help buildmode' for more. +// -compiler name +// name of compiler to use, as in runtime.Compiler (gccgo or gc). +// -gccgoflags 'arg list' +// arguments to pass on each gccgo compiler/linker invocation. +// -gcflags 'arg list' +// arguments to pass on each go tool compile invocation. +// -installsuffix suffix +// a suffix to use in the name of the package installation directory, +// in order to keep output separate from default builds. +// If using the -race flag, the install suffix is automatically set to race +// or, if set explicitly, has _race appended to it. Likewise for the -msan +// flag. Using a -buildmode option that requires non-default compile flags +// has a similar effect. +// -ldflags 'flag list' +// arguments to pass on each go tool link invocation. +// -linkshared +// link against shared libraries previously created with +// -buildmode=shared. +// -pkgdir dir +// install and load all packages from dir instead of the usual locations. +// For example, when building with a non-standard configuration, +// use -pkgdir to keep generated packages in a separate location. +// -tags 'tag list' +// a list of build tags to consider satisfied during the build. +// For more information about build tags, see the description of +// build constraints in the documentation for the go/build package. +// -toolexec 'cmd args' +// a program to use to invoke toolchain programs like vet and asm. +// For example, instead of running asm, the go command will run +// 'cmd args /path/to/asm '. +// +// The list flags accept a space-separated list of strings. To embed spaces +// in an element in the list, surround it with either single or double quotes. +// +// For more about specifying packages, see 'go help packages'. +// For more about where packages and binaries are installed, +// run 'go help gopath'. +// For more about calling between Go and C/C++, run 'go help c'. +// +// Note: Build adheres to certain conventions such as those described +// by 'go help gopath'. Not all projects can follow these conventions, +// however. Installations that have their own conventions or that use +// a separate software build system may choose to use lower-level +// invocations such as 'go tool compile' and 'go tool link' to avoid +// some of the overheads and design decisions of the build tool. +// +// See also: go install, go get, go clean. +// +// +// Remove object files +// +// Usage: +// +// go clean [-i] [-r] [-n] [-x] [build flags] [packages] +// +// Clean removes object files from package source directories. +// The go command builds most objects in a temporary directory, +// so go clean is mainly concerned with object files left by other +// tools or by manual invocations of go build. +// +// Specifically, clean removes the following files from each of the +// source directories corresponding to the import paths: +// +// _obj/ old object directory, left from Makefiles +// _test/ old test directory, left from Makefiles +// _testmain.go old gotest file, left from Makefiles +// test.out old test log, left from Makefiles +// build.out old test log, left from Makefiles +// *.[568ao] object files, left from Makefiles +// +// DIR(.exe) from go build +// DIR.test(.exe) from go test -c +// MAINFILE(.exe) from go build MAINFILE.go +// *.so from SWIG +// +// In the list, DIR represents the final path element of the +// directory, and MAINFILE is the base name of any Go source +// file in the directory that is not included when building +// the package. +// +// The -i flag causes clean to remove the corresponding installed +// archive or binary (what 'go install' would create). +// +// The -n flag causes clean to print the remove commands it would execute, +// but not run them. +// +// The -r flag causes clean to be applied recursively to all the +// dependencies of the packages named by the import paths. +// +// The -x flag causes clean to print remove commands as it executes them. +// +// For more about build flags, see 'go help build'. +// +// For more about specifying packages, see 'go help packages'. +// +// +// Show documentation for package or symbol +// +// Usage: +// +// go doc [-u] [-c] [package|[package.]symbol[.method]] +// +// Doc prints the documentation comments associated with the item identified by its +// arguments (a package, const, func, type, var, or method) followed by a one-line +// summary of each of the first-level items "under" that item (package-level +// declarations for a package, methods for a type, etc.). +// +// Doc accepts zero, one, or two arguments. +// +// Given no arguments, that is, when run as +// +// go doc +// +// it prints the package documentation for the package in the current directory. +// If the package is a command (package main), the exported symbols of the package +// are elided from the presentation unless the -cmd flag is provided. +// +// When run with one argument, the argument is treated as a Go-syntax-like +// representation of the item to be documented. What the argument selects depends +// on what is installed in GOROOT and GOPATH, as well as the form of the argument, +// which is schematically one of these: +// +// go doc +// go doc [.] +// go doc [.][.] +// go doc [.][.] +// +// The first item in this list matched by the argument is the one whose documentation +// is printed. (See the examples below.) However, if the argument starts with a capital +// letter it is assumed to identify a symbol or method in the current directory. +// +// For packages, the order of scanning is determined lexically in breadth-first order. +// That is, the package presented is the one that matches the search and is nearest +// the root and lexically first at its level of the hierarchy. The GOROOT tree is +// always scanned in its entirety before GOPATH. +// +// If there is no package specified or matched, the package in the current +// directory is selected, so "go doc Foo" shows the documentation for symbol Foo in +// the current package. +// +// The package path must be either a qualified path or a proper suffix of a +// path. The go tool's usual package mechanism does not apply: package path +// elements like . and ... are not implemented by go doc. +// +// When run with two arguments, the first must be a full package path (not just a +// suffix), and the second is a symbol or symbol and method; this is similar to the +// syntax accepted by godoc: +// +// go doc [.] +// +// In all forms, when matching symbols, lower-case letters in the argument match +// either case but upper-case letters match exactly. This means that there may be +// multiple matches of a lower-case argument in a package if different symbols have +// different cases. If this occurs, documentation for all matches is printed. +// +// Examples: +// go doc +// Show documentation for current package. +// go doc Foo +// Show documentation for Foo in the current package. +// (Foo starts with a capital letter so it cannot match +// a package path.) +// go doc encoding/json +// Show documentation for the encoding/json package. +// go doc json +// Shorthand for encoding/json. +// go doc json.Number (or go doc json.number) +// Show documentation and method summary for json.Number. +// go doc json.Number.Int64 (or go doc json.number.int64) +// Show documentation for json.Number's Int64 method. +// go doc cmd/doc +// Show package docs for the doc command. +// go doc -cmd cmd/doc +// Show package docs and exported symbols within the doc command. +// go doc template.new +// Show documentation for html/template's New function. +// (html/template is lexically before text/template) +// go doc text/template.new # One argument +// Show documentation for text/template's New function. +// go doc text/template new # Two arguments +// Show documentation for text/template's New function. +// +// At least in the current tree, these invocations all print the +// documentation for json.Decoder's Decode method: +// +// go doc json.Decoder.Decode +// go doc json.decoder.decode +// go doc json.decode +// cd go/src/encoding/json; go doc decode +// +// Flags: +// -c +// Respect case when matching symbols. +// -cmd +// Treat a command (package main) like a regular package. +// Otherwise package main's exported symbols are hidden +// when showing the package's top-level documentation. +// -u +// Show documentation for unexported as well as exported +// symbols and methods. +// +// +// Print Go environment information +// +// Usage: +// +// go env [var ...] +// +// Env prints Go environment information. +// +// By default env prints information as a shell script +// (on Windows, a batch file). If one or more variable +// names is given as arguments, env prints the value of +// each named variable on its own line. +// +// +// Run go tool fix on packages +// +// Usage: +// +// go fix [packages] +// +// Fix runs the Go fix command on the packages named by the import paths. +// +// For more about fix, see 'go doc cmd/fix'. +// For more about specifying packages, see 'go help packages'. +// +// To run fix with specific options, run 'go tool fix'. +// +// See also: go fmt, go vet. +// +// +// Run gofmt on package sources +// +// Usage: +// +// go fmt [-n] [-x] [packages] +// +// Fmt runs the command 'gofmt -l -w' on the packages named +// by the import paths. It prints the names of the files that are modified. +// +// For more about gofmt, see 'go doc cmd/gofmt'. +// For more about specifying packages, see 'go help packages'. +// +// The -n flag prints commands that would be executed. +// The -x flag prints commands as they are executed. +// +// 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] [-n] [-v] [-x] [build flags] [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. +// $GOLINE +// The line number of the directive in the source file. +// $GOPACKAGE +// The name of the package of the file containing the directive. +// $DOLLAR +// A dollar sign. +// +// 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 full original source text (excluding +// any trailing spaces and final newline) matches the +// expression. +// +// It also accepts the standard build flags including -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 build flags, see 'go help build'. +// +// For more about specifying packages, see 'go help packages'. +// +// +// Download and install packages and dependencies +// +// Usage: +// +// go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages] +// +// Get downloads the packages named by the import paths, along with their +// dependencies. It then installs the named packages, like 'go install'. +// +// 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. +// +// The -insecure flag permits fetching from repositories and resolving +// custom domains using insecure schemes such as HTTP. Use with caution. +// +// The -t flag instructs get to also download the packages required to build +// the tests for the specified packages. +// +// The -u flag instructs get to use the network to update the named packages +// and their dependencies. By default, get uses the network to check out +// missing packages but does not use it to look for updates to existing packages. +// +// Get also accepts build flags to control the installation. See 'go help build'. +// +// When checking out a new package, get creates the target directory +// GOPATH/src/. If the GOPATH contains multiple entries, +// get uses the first one. See 'go help gopath'. +// +// When checking out or updating a package, get looks for a branch or tag +// that matches the locally installed version of Go. The most important +// rule is that if the local installation is running version "go1", get +// searches for a branch or tag named "go1". If no such version exists it +// retrieves the most recent version of the package. +// +// Unless vendoring support is disabled (see 'go help gopath'), +// when go get checks out or updates a Git repository, +// it also updates any git submodules referenced by the repository. +// +// Get never checks out or updates code stored in vendor directories. +// +// For more about specifying packages, see 'go help packages'. +// +// For more about how 'go get' finds source code to +// download, see 'go help importpath'. +// +// See also: go build, go install, go clean. +// +// +// Compile and install packages and dependencies +// +// Usage: +// +// go install [build flags] [packages] +// +// Install compiles and installs the packages named by the import paths, +// along with their dependencies. +// +// For more about the build flags, see 'go help build'. +// For more about specifying packages, see 'go help packages'. +// +// See also: go build, go get, go clean. +// +// +// List packages +// +// Usage: +// +// go list [-e] [-f format] [-json] [build flags] [packages] +// +// List lists the packages named by the import paths, one per line. +// +// The default output shows the package import path: +// +// bytes +// encoding/json +// github.com/gorilla/mux +// golang.org/x/net/html +// +// The -f flag specifies an alternate format for the list, using the +// 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 +// ImportComment string // path in import comment on package statement +// Name string // package name +// Doc string // package documentation string +// Target string // install path +// Shlib string // the shared library that contains this package (only set when -linkshared) +// 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? +// StaleReason string // explanation for Stale==true +// Root string // Go root or Go path dir containing this package +// ConflictDir string // this directory shadows Dir in $GOPATH +// BinaryOnly bool // binary-only package: cannot be recompiled from sources +// +// // Source files +// 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 +// FFiles []string // .f, .F, .for and .f90 Fortran 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 +// CgoCPPFLAGS []string // cgo: flags for C preprocessor +// CgoCXXFLAGS []string // cgo: flags for C++ compiler +// CgoFFLAGS []string // cgo: flags for Fortran compiler +// CgoLDFLAGS []string // cgo: flags for linker +// CgoPkgConfig []string // cgo: pkg-config names +// +// // Dependency information +// Imports []string // import paths used by this package +// Deps []string // all (recursively) imported dependencies +// +// // Error information +// Incomplete bool // this package or a dependency has an error +// Error *PackageError // error loading package +// DepsErrors []*PackageError // errors loading dependencies +// +// TestGoFiles []string // _test.go files in package +// TestImports []string // imports from TestGoFiles +// XTestGoFiles []string // _test.go files outside package +// XTestImports []string // imports from XTestGoFiles +// } +// +// The error information, if any, is +// +// type PackageError struct { +// ImportStack []string // shortest path from package named on command line to this one +// Pos string // position of error (if present, file:line:col) +// Err string // the error itself +// } +// +// The template function "join" calls strings.Join. +// +// The template function "context" returns the build context, defined as: +// +// type Context struct { +// GOARCH string // target architecture +// GOOS string // target operating system +// GOROOT string // Go root +// GOPATH string // Go path +// CgoEnabled bool // whether cgo can be used +// UseAllFiles bool // use files regardless of +build lines, file names +// Compiler string // compiler to assume when computing target paths +// BuildTags []string // build constraints to match in +build lines +// ReleaseTags []string // releases the current release is compatible with +// InstallSuffix string // suffix to use in the name of the install dir +// } +// +// For more information about the meaning of these fields see the documentation +// for the go/build package's Context type. +// +// The -json flag causes the package data to be printed in JSON format +// instead of using the template format. +// +// The -e flag changes the handling of erroneous packages, those that +// cannot be found or are malformed. By default, the list command +// prints an error to standard error for each erroneous package and +// omits the packages from consideration during the usual printing. +// With the -e flag, the list command never prints errors to standard +// error and instead processes the erroneous packages with the usual +// printing. Erroneous packages will have a non-empty ImportPath and +// a non-nil Error field; other information may or may not be missing +// (zeroed). +// +// For more about build flags, see 'go help build'. +// +// For more about specifying packages, see 'go help packages'. +// +// +// Compile and run Go program +// +// Usage: +// +// go run [build flags] [-exec xprog] gofiles... [arguments...] +// +// Run compiles and runs the main package comprising the named Go source files. +// A Go source file is defined to be a file ending in a literal ".go" suffix. +// +// By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. +// If the -exec flag is given, 'go run' invokes the binary using xprog: +// 'xprog a.out arguments...'. +// If the -exec flag is not given, GOOS or GOARCH is different from the system +// default, and a program named go_$GOOS_$GOARCH_exec can be found +// on the current search path, 'go run' invokes the binary using that program, +// for example 'go_nacl_386_exec a.out arguments...'. This allows execution of +// cross-compiled programs when a simulator or other execution method is +// available. +// +// For more about build flags, see 'go help build'. +// +// See also: go build. +// +// +// Test packages +// +// Usage: +// +// go test [build/test flags] [packages] [build/test flags & test binary flags] +// +// 'Go test' automates testing the packages named by the import paths. +// It prints a summary of the test results in the format: +// +// ok archive/tar 0.011s +// FAIL archive/zip 0.022s +// ok compress/gzip 0.033s +// ... +// +// 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". +// 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. +// Each listed package causes the execution of a separate test binary. +// +// Test files that declare a package with the suffix "_test" will be compiled as a +// separate package, and then linked and run with the main test binary. +// +// The go tool will ignore a directory named "testdata", making it available +// to hold ancillary data needed by the tests. +// +// By default, go test needs no arguments. It compiles and tests the package +// with source in the current directory, including tests, and runs the tests. +// +// The package is built in a temporary directory so it does not interfere with the +// non-test installation. +// +// In addition to the build flags, the flags handled by 'go test' itself are: +// +// -args +// Pass the remainder of the command line (everything after -args) +// to the test binary, uninterpreted and unchanged. +// Because this flag consumes the remainder of the command line, +// the package list (if present) must appear before this flag. +// +// -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. +// +// -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. +// +// For more about build flags, see 'go help build'. +// For more about specifying packages, see 'go help packages'. +// +// See also: go build, go vet. +// +// +// Run specified go tool +// +// Usage: +// +// go tool [-n] command [args...] +// +// Tool runs the go tool command identified by the arguments. +// With no arguments it prints the list of known tools. +// +// The -n flag causes tool to print the command that would be +// executed but not execute it. +// +// For more about each tool command, see 'go tool command -h'. +// +// +// Print Go version +// +// Usage: +// +// go version +// +// Version prints the Go version, as reported by runtime.Version. +// +// +// Run go tool vet on packages +// +// Usage: +// +// go vet [-n] [-x] [build flags] [packages] +// +// Vet runs the Go vet command on the packages named by the import paths. +// +// For more about vet, see 'go doc cmd/vet'. +// For more about specifying packages, see 'go help packages'. +// +// To run the vet tool with specific options, run 'go tool vet'. +// +// The -n flag prints commands that would be executed. +// The -x flag prints commands as they are executed. +// +// For more about build flags, see 'go help build'. +// +// See also: go fmt, go fix. +// +// +// Calling between Go and C +// +// There are two different ways to call between Go and C/C++ code. +// +// The first is the cgo tool, which is part of the Go distribution. For +// information on how to use it see the cgo documentation (go doc cmd/cgo). +// +// The second is the SWIG program, which is a general tool for +// interfacing between languages. For information on SWIG see +// http://swig.org/. When running go build, any file with a .swig +// extension will be passed to SWIG. Any file with a .swigcxx extension +// will be passed to SWIG with the -c++ option. +// +// When either cgo or SWIG is used, go build will pass any .c, .m, .s, +// or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++ +// compiler. The CC or CXX environment variables may be set to determine +// the C or C++ compiler, respectively, to use. +// +// +// Description of build modes +// +// The 'go build' and 'go install' commands take a -buildmode argument which +// indicates which kind of object file is to be built. Currently supported values +// are: +// +// -buildmode=archive +// Build the listed non-main packages into .a files. Packages named +// main are ignored. +// +// -buildmode=c-archive +// Build the listed main package, plus all packages it imports, +// into a C archive file. The only callable symbols will be those +// functions exported using a cgo //export comment. Requires +// exactly one main package to be listed. +// +// -buildmode=c-shared +// Build the listed main packages, plus all packages that they +// import, into C shared libraries. The only callable symbols will +// be those functions exported using a cgo //export comment. +// Non-main packages are ignored. +// +// -buildmode=default +// Listed main packages are built into executables and listed +// non-main packages are built into .a files (the default +// behavior). +// +// -buildmode=shared +// Combine all the listed non-main packages into a single shared +// library that will be used when building with the -linkshared +// option. Packages named main are ignored. +// +// -buildmode=exe +// Build the listed main packages and everything they import into +// executables. Packages not named main are ignored. +// +// -buildmode=pie +// Build the listed main packages and everything they import into +// position independent executables (PIE). Packages not named +// main are ignored. +// +// +// File types +// +// The go command examines the contents of a restricted set of files +// in each directory. It identifies which files to examine based on +// the extension of the file name. These extensions are: +// +// .go +// Go source files. +// .c, .h +// C source files. +// If the package uses cgo or SWIG, these will be compiled with the +// OS-native compiler (typically gcc); otherwise they will +// trigger an error. +// .cc, .cpp, .cxx, .hh, .hpp, .hxx +// C++ source files. Only useful with cgo or SWIG, and always +// compiled with the OS-native compiler. +// .m +// Objective-C source files. Only useful with cgo, and always +// compiled with the OS-native compiler. +// .s, .S +// Assembler source files. +// If the package uses cgo or SWIG, these will be assembled with the +// OS-native assembler (typically gcc (sic)); otherwise they +// will be assembled with the Go assembler. +// .swig, .swigcxx +// SWIG definition files. +// .syso +// System object files. +// +// Files of each of these types except .syso may contain build +// constraints, but the go command stops scanning for build constraints +// at the first item in the file that is not a blank line or //-style +// line comment. See the go/build package documentation for +// more details. +// +// Non-test Go source files can also include a //go:binary-only-package +// comment, indicating that the package sources are included +// for documentation only and must not be used to build the +// package binary. This enables distribution of Go packages in +// their compiled form alone. See the go/build package documentation +// for more details. +// +// +// GOPATH environment variable +// +// The Go path is used to resolve import statements. +// It is implemented by and documented in the go/build package. +// +// The GOPATH environment variable lists places to look for Go code. +// On Unix, the value is a colon-separated string. +// On Windows, the value is a semicolon-separated string. +// On Plan 9, the value is a list. +// +// GOPATH must be set to get, build and install packages outside the +// standard Go tree. +// +// Each directory listed in GOPATH must have a prescribed structure: +// +// The src directory holds source code. The path below src +// determines the import path or executable name. +// +// The pkg directory holds installed package objects. +// As in the Go tree, each target operating system and +// architecture pair has its own subdirectory of pkg +// (pkg/GOOS_GOARCH). +// +// If DIR is a directory listed in the GOPATH, a package with +// source in DIR/src/foo/bar can be imported as "foo/bar" and +// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". +// +// The bin directory holds compiled commands. +// Each command is named for its source directory, but only +// the final element, not the entire path. That is, the +// command with source in DIR/src/foo/quux is installed into +// DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped +// so that you can add DIR/bin to your PATH to get at the +// installed commands. If the GOBIN environment variable is +// set, commands are installed to the directory it names instead +// of DIR/bin. GOBIN must be an absolute path. +// +// Here's an example directory layout: +// +// GOPATH=/home/user/gocode +// +// /home/user/gocode/ +// src/ +// foo/ +// bar/ (go code in package bar) +// x.go +// quux/ (go code in package main) +// y.go +// bin/ +// quux (installed command) +// pkg/ +// linux_amd64/ +// foo/ +// bar.a (installed package object) +// +// Go searches each directory listed in GOPATH to find source code, +// but new packages are always downloaded into the first directory +// in the list. +// +// See https://golang.org/doc/code.html for an example. +// +// Internal Directories +// +// Code in or below a directory named "internal" is importable only +// by code in the directory tree rooted at the parent of "internal". +// Here's an extended version of the directory layout above: +// +// /home/user/gocode/ +// src/ +// crash/ +// bang/ (go code in package bang) +// b.go +// foo/ (go code in package foo) +// f.go +// bar/ (go code in package bar) +// x.go +// internal/ +// baz/ (go code in package baz) +// z.go +// quux/ (go code in package main) +// y.go +// +// +// The code in z.go is imported as "foo/internal/baz", but that +// import statement can only appear in source files in the subtree +// rooted at foo. The source files foo/f.go, foo/bar/x.go, and +// foo/quux/y.go can all import "foo/internal/baz", but the source file +// crash/bang/b.go cannot. +// +// See https://golang.org/s/go14internal for details. +// +// Vendor Directories +// +// Go 1.6 includes support for using local copies of external dependencies +// to satisfy imports of those dependencies, often referred to as vendoring. +// +// Code below a directory named "vendor" is importable only +// by code in the directory tree rooted at the parent of "vendor", +// and only using an import path that omits the prefix up to and +// including the vendor element. +// +// Here's the example from the previous section, +// but with the "internal" directory renamed to "vendor" +// and a new foo/vendor/crash/bang directory added: +// +// /home/user/gocode/ +// src/ +// crash/ +// bang/ (go code in package bang) +// b.go +// foo/ (go code in package foo) +// f.go +// bar/ (go code in package bar) +// x.go +// vendor/ +// crash/ +// bang/ (go code in package bang) +// b.go +// baz/ (go code in package baz) +// z.go +// quux/ (go code in package main) +// y.go +// +// The same visibility rules apply as for internal, but the code +// in z.go is imported as "baz", not as "foo/vendor/baz". +// +// Code in vendor directories deeper in the source tree shadows +// code in higher directories. Within the subtree rooted at foo, an import +// of "crash/bang" resolves to "foo/vendor/crash/bang", not the +// top-level "crash/bang". +// +// Code in vendor directories is not subject to import path +// checking (see 'go help importpath'). +// +// When 'go get' checks out or updates a git repository, it now also +// updates submodules. +// +// Vendor directories do not affect the placement of new repositories +// being checked out for the first time by 'go get': those are always +// placed in the main GOPATH, never in a vendor subtree. +// +// See https://golang.org/s/go15vendor for details. +// +// +// Environment variables +// +// The go command, and the tools it invokes, examine a few different +// environment variables. For many of these, you can see the default +// value of on your system by running 'go env NAME', where NAME is the +// name of the variable. +// +// General-purpose environment variables: +// +// GCCGO +// The gccgo command to run for 'go build -compiler=gccgo'. +// GOARCH +// The architecture, or processor, for which to compile code. +// Examples are amd64, 386, arm, ppc64. +// GOBIN +// The directory where 'go install' will install a command. +// GOOS +// The operating system for which to compile code. +// Examples are linux, darwin, windows, netbsd. +// GOPATH +// See 'go help gopath'. +// GORACE +// Options for the race detector. +// See https://golang.org/doc/articles/race_detector.html. +// GOROOT +// The root of the go tree. +// +// Environment variables for use with cgo: +// +// CC +// The command to use to compile C code. +// CGO_ENABLED +// Whether the cgo command is supported. Either 0 or 1. +// CGO_CFLAGS +// Flags that cgo will pass to the compiler when compiling +// C code. +// CGO_CPPFLAGS +// Flags that cgo will pass to the compiler when compiling +// C or C++ code. +// CGO_CXXFLAGS +// Flags that cgo will pass to the compiler when compiling +// C++ code. +// CGO_LDFLAGS +// Flags that cgo will pass to the compiler when linking. +// CXX +// The command to use to compile C++ code. +// +// Architecture-specific environment variables: +// +// GOARM +// For GOARCH=arm, the ARM architecture for which to compile. +// Valid values are 5, 6, 7. +// GO386 +// For GOARCH=386, the floating point instruction set. +// Valid values are 387, sse2. +// +// Special-purpose environment variables: +// +// GOROOT_FINAL +// The root of the installed Go tree, when it is +// installed in a location other than where it is built. +// File names in stack traces are rewritten from GOROOT to +// GOROOT_FINAL. +// GO_EXTLINK_ENABLED +// Whether the linker should use external linking mode +// when using -linkmode=auto with code that uses cgo. +// Set to 0 to disable external linking mode, 1 to enable it. +// +// +// Import path syntax +// +// An import path (see 'go help packages') denotes a package +// stored in the local file system. In general, an import path denotes +// either a standard package (such as "unicode/utf8") or a package +// found in one of the work spaces (see 'go help gopath'). +// +// Relative import paths +// +// An import path beginning with ./ or ../ is called a relative path. +// The toolchain supports relative import paths as a shortcut in two ways. +// +// First, a relative path can be used as a shorthand on the command line. +// If you are working in the directory containing the code imported as +// "unicode" and want to run the tests for "unicode/utf8", you can type +// "go test ./utf8" instead of needing to specify the full path. +// Similarly, in the reverse situation, "go test .." will test "unicode" from +// the "unicode/utf8" directory. Relative patterns are also allowed, like +// "go test ./..." to test all subdirectories. See 'go help packages' for details +// on the pattern syntax. +// +// Second, if you are compiling a Go program not in a work space, +// you can use a relative path in an import statement in that program +// to refer to nearby code also not in a work space. +// This makes it easy to experiment with small multipackage programs +// outside of the usual work spaces, but such programs cannot be +// installed with "go install" (there is no work space in which to install them), +// so they are rebuilt from scratch each time they are built. +// To avoid ambiguity, Go programs cannot use relative import paths +// within a work space. +// +// Remote import paths +// +// Certain import paths also +// describe how to obtain the source code for the package using +// a revision control system. +// +// A few common code hosting sites have special syntax: +// +// Bitbucket (Git, Mercurial) +// +// import "bitbucket.org/user/project" +// import "bitbucket.org/user/project/sub/directory" +// +// GitHub (Git) +// +// import "github.com/user/project" +// import "github.com/user/project/sub/directory" +// +// Launchpad (Bazaar) +// +// import "launchpad.net/project" +// import "launchpad.net/project/series" +// import "launchpad.net/project/series/sub/directory" +// +// 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 +// from a tag in the HTML. +// +// To declare the code location, an import path of the form +// +// repository.vcs/path +// +// specifies the given repository, with or without the .vcs suffix, +// using the named version control system, and then the path inside +// that repository. The supported version control systems are: +// +// Bazaar .bzr +// Git .git +// Mercurial .hg +// Subversion .svn +// +// For example, +// +// import "example.org/user/foo.hg" +// +// denotes the root directory of the Mercurial repository at +// example.org/user/foo or foo.hg, and +// +// import "example.org/repo.git/foo/bar" +// +// denotes the foo/bar directory of the Git repository at +// example.org/repo or repo.git. +// +// When a version control system supports multiple protocols, +// each is tried in turn when downloading. For example, a Git +// download tries https://, then git+ssh://. +// +// If the import path is not a known code hosting site and also lacks a +// version control qualifier, the go tool attempts to fetch the import +// over https/http and looks for a tag in the document's HTML +// . +// +// The meta tag has the form: +// +// +// +// The import-prefix is the import path corresponding to the repository +// root. It must be a prefix or an exact match of the package being +// fetched with "go get". If it's not an exact match, another http +// request is made at the prefix to verify the tags match. +// +// The meta tag should appear as early in the file as possible. +// In particular, it should appear before any raw JavaScript or CSS, +// to avoid confusing the go command's restricted parser. +// +// The vcs is one of "git", "hg", "svn", etc, +// +// The repo-root is the root of the version control system +// containing a scheme and not containing a .vcs qualifier. +// +// For example, +// +// import "example.org/pkg/foo" +// +// will result in the following requests: +// +// https://example.org/pkg/foo?go-get=1 (preferred) +// http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) +// +// If that page contains the meta tag +// +// +// +// the go tool will verify that https://example.org/?go-get=1 contains the +// same meta tag and then git clone https://code.org/r/p/exproj into +// GOPATH/src/example.org. +// +// New downloaded packages are written to the first directory +// 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 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. +// +// If vendoring is enabled (see 'go help gopath'), then import path checking is +// disabled for code found within vendor trees. This makes it possible to copy +// code into alternate locations in vendor trees without needing to update import +// comments. +// +// See https://golang.org/s/go14customimport for details. +// +// +// Description of package lists +// +// Many commands apply to a set of packages: +// +// go action [packages] +// +// Usually, [packages] is a list of import paths. +// +// An import path that is a rooted path or that begins with +// a . or .. element is interpreted as a file system path and +// denotes the package in that directory. +// +// Otherwise, the import path P denotes the package found in +// the directory DIR/src/P for some DIR listed in the GOPATH +// environment variable (see 'go help gopath'). +// +// If no import paths are given, the action applies to the +// package in the current directory. +// +// There are four reserved names for paths that should not be used +// for packages to be built with the go tool: +// +// - "main" denotes the top-level package in a stand-alone executable. +// +// - "all" expands to all package directories found in all the GOPATH +// trees. For example, 'go list all' lists all the packages on the local +// system. +// +// - "std" is like all but expands to just the packages in the standard +// Go library. +// +// - "cmd" expands to the Go repository's commands and their +// internal libraries. +// +// An import path is a pattern if it includes one or more "..." wildcards, +// each of which can match any string, including the empty string and +// strings containing slashes. Such a pattern expands to all package +// directories found in the GOPATH trees with names matching the +// patterns. As a special case, x/... matches x as well as x's subdirectories. +// For example, net/... expands to net and packages in its subdirectories. +// +// An import path can also name a package to be downloaded from +// a remote repository. Run 'go help importpath' for details. +// +// Every package in a program must have a unique import path. +// By convention, this is arranged by starting each path with a +// unique prefix that belongs to you. For example, paths used +// internally at Google all begin with 'google', and paths +// denoting remote repositories begin with the path to the code, +// such as 'github.com/user/repo'. +// +// Packages in a program need not have unique package names, +// but there are two reserved package names with special meaning. +// The name main indicates a command, not a library. +// Commands are built into binaries and cannot be imported. +// The name documentation indicates documentation for +// a non-Go program in the directory. Files in package documentation +// are ignored by the go command. +// +// As a special case, if the package list is a list of .go files from a +// 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. +// +// Directory and file names that begin with "." or "_" are ignored +// by the go tool, as are directories named "testdata". +// +// +// Description of testing flags +// +// The 'go test' command takes both flags that apply to 'go test' itself +// and flags that apply to the resulting test binary. +// +// Several of the flags control profiling and write an execution profile +// suitable for "go tool pprof"; run "go tool pprof -h" for more +// information. The --alloc_space, --alloc_objects, and --show_bytes +// options of pprof control how the information is presented. +// +// The following flags are recognized by the 'go test' command and +// control the execution of any test: +// +// -bench regexp +// Run (sub)benchmarks matching a regular expression. +// The given regular expression is split into smaller ones by +// top-level '/', where each must match the corresponding part of a +// benchmark's identifier. +// By default, no benchmarks run. To run all benchmarks, +// use '-bench .' or '-bench=.'. +// +// -benchmem +// Print memory allocation statistics for benchmarks. +// +// -benchtime t +// Run enough iterations of each benchmark to take t, specified +// as a time.Duration (for example, -benchtime 1h30s). +// The default is 1 second (1s). +// +// -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 +// calling runtime.SetBlockProfileRate with n. +// See 'go doc runtime.SetBlockProfileRate'. +// The profiler aims to sample, on average, one blocking event every +// n nanoseconds the program spends blocked. By default, +// if -test.blockprofile is set without this flag, all blocking events +// are recorded, equivalent to -test.blockprofilerate=1. +// +// -count n +// Run each test and benchmark n times (default 1). +// If -cpu is set, run n times for each GOMAXPROCS value. +// Examples are always run once. +// +// -cover +// Enable coverage analysis. +// +// -covermode set,count,atomic +// Set the mode for coverage analysis for the package[s] +// being tested. The default is "set" unless -race is enabled, +// in which case it is "atomic". +// The values: +// set: bool: does this statement run? +// count: int: how many times does this statement run? +// atomic: int: count, but correct in multithreaded tests; +// significantly more expensive. +// Sets -cover. +// +// -coverpkg pkg1,pkg2,pkg3 +// Apply coverage analysis in each test to the given list of packages. +// The default is for each test to analyze only the package being tested. +// Packages are specified as import paths. +// Sets -cover. +// +// -coverprofile cover.out +// Write a coverage profile to the file after all tests have passed. +// Sets -cover. +// +// -cpu 1,2,4 +// Specify a list of GOMAXPROCS values for which the tests or +// benchmarks should be executed. The default is the current value +// of GOMAXPROCS. +// +// -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 file after all tests have passed. +// Writes test binary as -c would. +// +// -memprofilerate n +// Enable more precise (and expensive) memory profiles by setting +// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. +// To profile all memory allocations, use -test.memprofilerate=1 +// and pass --alloc_space flag to the pprof tool. +// +// -outputdir directory +// Place output files from profiling in the specified directory, +// by default the directory in which "go test" is running. +// +// -parallel n +// Allow parallel execution of test functions that call t.Parallel. +// The value of this flag is the maximum number of tests to run +// simultaneously; by default, it is set to the value of GOMAXPROCS. +// Note that -parallel only applies within a single test binary. +// The 'go test' command may run tests for different packages +// in parallel as well, according to the setting of the -p flag +// (see 'go help build'). +// +// -run regexp +// Run only those tests and examples matching the regular expression. +// For tests the regular expression is split into smaller ones by +// top-level '/', where each must match the corresponding part of a +// test's identifier. +// +// -short +// Tell long-running tests to shorten their run time. +// It is off by default but set during all.bash so that installing +// the Go tree can run a sanity check but not spend time running +// exhaustive tests. +// +// -timeout t +// If a test runs longer than t, panic. +// The default is 10 minutes (10m). +// +// -trace trace.out +// Write an execution trace to the specified file before exiting. +// +// -v +// Verbose output: log all tests as they are run. Also print all +// text from Log and Logf calls even if the test succeeds. +// +// Each of these flags is also recognized with an optional 'test.' prefix, +// as in -test.v. When invoking the generated test binary (the result of +// 'go test -c') directly, however, the prefix is mandatory. +// +// The 'go test' command rewrites or removes recognized flags, +// as appropriate, both before and after the optional package list, +// before invoking the test binary. +// +// For instance, the command +// +// go test -v -myflag testdata -cpuprofile=prof.out -x +// +// will compile the test binary and then run it as +// +// pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out +// +// (The -x flag is removed because it applies only to the go command's +// execution, not to the test itself.) +// +// The test flags that generate profiles (other than for coverage) also +// leave the test binary in pkg.test for use when analyzing the profiles. +// +// When 'go test' runs a test binary, it does so from within the +// corresponding package's source code directory. Depending on the test, +// it may be necessary to do the same when invoking a generated test +// binary directly. +// +// The command-line package list, if present, must appear before any +// flag not known to the go test command. Continuing the example above, +// the package list would have to appear before -myflag, but could appear +// on either side of -v. +// +// To keep an argument for a test binary from being interpreted as a +// known flag or a package name, use -args (see 'go help test') which +// passes the remainder of the command line through to the test binary +// uninterpreted and unaltered. +// +// For instance, the command +// +// go test -v -args -x -v +// +// will compile the test binary and then run it as +// +// pkg.test -test.v -x -v +// +// Similarly, +// +// go test -args math +// +// will compile the test binary and then run it as +// +// pkg.test math +// +// In the first example, the -x and the second -v are passed through to the +// test binary unchanged and with no effect on the go command itself. +// In the second example, the argument math is passed through to the test +// binary, instead of being interpreted as the package list. +// +// +// Description of testing functions +// +// The 'go test' command expects to find test, benchmark, and example functions +// in the "*_test.go" files corresponding to the package under test. +// +// A test function is one named TestXXX (where XXX is any alphanumeric string +// not starting with a lower case letter) and should have the signature, +// +// func TestXXX(t *testing.T) { ... } +// +// A benchmark function is one named BenchmarkXXX and should have the signature, +// +// func BenchmarkXXX(b *testing.B) { ... } +// +// An example function is similar to a test function but, instead of using +// *testing.T to report success or failure, prints output to os.Stdout. +// If the last comment in the function starts with "Output:" then the output +// is compared exactly against the comment (see examples below). If the last +// comment begins with "Unordered output:" then the output is compared to the +// comment, however the order of the lines is ignored. An example with no such +// comment, or with no text after "Output:" is compiled but not executed. +// +// Godoc displays the body of ExampleXXX to demonstrate the use +// of the function, constant, or variable XXX. An example of a method M with +// receiver type T or *T is named ExampleT_M. There may be multiple examples +// for a given function, constant, or variable, distinguished by a trailing _xxx, +// where xxx is a suffix not beginning with an upper case letter. +// +// Here is an example of an example: +// +// func ExamplePrintln() { +// Println("The output of\nthis example.") +// // Output: The output of +// // this example. +// } +// +// Here is another example where the ordering of the output is ignored: +// +// func ExamplePerm() { +// for _, value := range Perm(4) { +// fmt.Println(value) +// } +// +// // Unordered output: 4 +// // 2 +// // 1 +// // 3 +// // 0 +// } +// +// The entire test file is presented as the example when it contains a single +// example function, at least one other function, type, variable, or constant +// declaration, and no test or benchmark functions. +// +// See the documentation of the testing package for more information. +// +// package main diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index e0cb216b8c..11a4eab093 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2182,7 +2182,6 @@ func mkAbs(dir, f string) string { type toolchain interface { // gc runs the compiler in a specific directory on a set of files // and returns the name of the generated output file. - // The compiler runs in the directory dir. gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) // cc runs the toolchain's C compiler in a directory on a C file // to produce an output file. @@ -2328,7 +2327,15 @@ 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", "include") sfile = mkAbs(p.Dir, sfile) - args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile} + args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags} + if p.ImportPath == "runtime" && goarch == "386" { + for _, arg := range buildAsmflags { + if arg == "-dynlink" { + args = append(args, "-D=GOBUILDMODE_shared=1") + } + } + } + args = append(args, sfile) if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil { return err } @@ -2625,7 +2632,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles) } -func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { +func (tools gccgoToolchain) link(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string, buildmode, desc string) error { // gccgo needs explicit linking with all package dependencies, // and all LDFLAGS from cgo dependencies. apackagePathsSeen := make(map[string]bool) @@ -2634,9 +2641,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions ldflags := b.gccArchArgs() cgoldflags := []string{} usesCgo := false - cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0 - objc := len(root.p.MFiles) > 0 - fortran := len(root.p.FFiles) > 0 + cxx := false + objc := false + fortran := false + if root.p != nil { + cxx = len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0 + objc = len(root.p.MFiles) > 0 + fortran = len(root.p.FFiles) > 0 + } readCgoFlags := func(flagsFile string) error { flags, err := ioutil.ReadFile(flagsFile) @@ -2683,11 +2695,11 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions } newarchive := newa.Name() - err = b.run(b.work, root.p.ImportPath, nil, "ar", "x", newarchive, "_cgo_flags") + err = b.run(b.work, desc, nil, "ar", "x", newarchive, "_cgo_flags") if err != nil { return "", err } - err = b.run(".", root.p.ImportPath, nil, "ar", "d", newarchive, "_cgo_flags") + err = b.run(".", desc, nil, "ar", "d", newarchive, "_cgo_flags") if err != nil { return "", err } @@ -2793,7 +2805,9 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions ldflags = append(ldflags, cgoldflags...) ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) - ldflags = append(ldflags, root.p.CgoLDFLAGS...) + if root.p != nil { + ldflags = append(ldflags, root.p.CgoLDFLAGS...) + } ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)") @@ -2808,7 +2822,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions } var realOut string - switch ldBuildmode { + switch buildmode { case "exe": if usesCgo && goos == "linux" { ldflags = append(ldflags, "-Wl,-E") @@ -2843,12 +2857,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions case "c-shared": ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc") + case "shared": + ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") default: - fatalf("-buildmode=%s not supported for gccgo", ldBuildmode) + fatalf("-buildmode=%s not supported for gccgo", buildmode) } - switch ldBuildmode { + switch buildmode { case "exe", "c-shared": if cxx { ldflags = append(ldflags, "-lstdc++") @@ -2869,41 +2885,27 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions } } - if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil { + if err := b.run(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil { return err } - switch ldBuildmode { + switch buildmode { case "c-archive": - if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil { + if err := b.run(".", desc, nil, "ar", "rc", realOut, out); err != nil { return err } } return nil } +func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { + return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.p.ImportPath) +} + func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { - args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"} - for _, a := range toplevelactions { - args = append(args, a.target) - } - args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") - shlibs := []string{} - for _, a := range allactions { - if strings.HasSuffix(a.target, ".so") { - shlibs = append(shlibs, a.target) - } - } - for _, shlib := range shlibs { - args = append( - args, - "-L"+filepath.Dir(shlib), - "-Wl,-rpath="+filepath.Dir(shlib), - "-l"+strings.TrimSuffix( - strings.TrimPrefix(filepath.Base(shlib), "lib"), - ".so")) - } - return b.run(".", out, nil, tools.linker(), args, buildGccgoflags) + fakeRoot := &action{} + fakeRoot.deps = toplevelactions + return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out) } func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { @@ -3088,7 +3090,7 @@ func (b *builder) gccSupportsFlag(flag string) bool { } cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) cmd.Dir = b.work - cmd.Env = envForDir(cmd.Dir, os.Environ()) + cmd.Env = mergeEnvLists([]string{"LC_ALL=C"}, envForDir(cmd.Dir, os.Environ())) out, err := cmd.CombinedOutput() supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) b.flagCache[flag] = supported diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index b52991a5fc..969760a77e 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -19,8 +19,8 @@ var cmdGet = &Command{ UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]", Short: "download and install packages and dependencies", Long: ` -Get downloads and installs the packages named by the import paths, -along with their dependencies. +Get downloads the packages named by the import paths, along with their +dependencies. It then installs the named packages, like 'go install'. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 50e6b500da..a6c70d97b6 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1332,15 +1332,31 @@ func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) { tg.run("test", "main_test") } +// 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") + // Issue 12690 func TestPackageNotStaleWithTrailingSlash(t *testing.T) { tg := testgo(t) defer tg.cleanup() + + // Make sure the packages below are not stale. + tg.run("install", "runtime", "os", "io") + goroot := runtime.GOROOT() tg.setenv("GOROOT", goroot+"/") - tg.wantNotStale("runtime", "", "with trailing slash in GOROOT, runtime listed as stale") - tg.wantNotStale("os", "", "with trailing slash in GOROOT, os listed as stale") - tg.wantNotStale("io", "", "with trailing slash in GOROOT, io listed as stale") + + want := "" + if isGoRelease { + want = "standard package in Go release distribution" + } + + tg.wantNotStale("runtime", want, "with trailing slash in GOROOT, runtime listed as stale") + tg.wantNotStale("os", want, "with trailing slash in GOROOT, os listed as stale") + tg.wantNotStale("io", want, "with trailing slash in GOROOT, io listed as stale") } // With $GOBIN set, binaries get installed to $GOBIN. @@ -2342,6 +2358,11 @@ func TestGoGetRscIoToolstash(t *testing.T) { // Issue 13037: Was not parsing tags in 404 served over HTTPS func TestGoGetHTTPS404(t *testing.T) { testenv.MustHaveExternalNetwork(t) + switch runtime.GOOS { + case "darwin", "linux", "freebsd": + default: + t.Skipf("test case does not work on %s", runtime.GOOS) + } tg := testgo(t) defer tg.cleanup() @@ -2877,3 +2898,25 @@ func TestBinaryOnlyPackages(t *testing.T) { tg.run("run", tg.path("src/p3/p3.go")) tg.grepStdout("hello from p1", "did not see message from p1") } + +// Issue 16050. +func TestAlwaysLinkSysoFiles(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src/syso") + tg.tempFile("src/syso/a.syso", ``) + tg.tempFile("src/syso/b.go", `package syso`) + tg.setenv("GOPATH", tg.path(".")) + + // We should see the .syso file regardless of the setting of + // CGO_ENABLED. + + tg.setenv("CGO_ENABLED", "1") + tg.run("list", "-f", "{{.SysoFiles}}", "syso") + tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1") + + tg.setenv("CGO_ENABLED", "0") + tg.run("list", "-f", "{{.SysoFiles}}", "syso") + tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0") +} diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 177c2af190..65ec61bd7d 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -214,15 +214,7 @@ var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}} {{end}}{{.Long | trim}} ` -var documentationTemplate = `// 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. - -// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh. -// Edit the documentation in other files and rerun mkalldocs.sh to generate this one. - -/* -{{range .}}{{if .Short}}{{.Short | capitalize}} +var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}} {{end}}{{if .Runnable}}Usage: @@ -231,9 +223,39 @@ var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reserv {{end}}{{.Long | trim}} -{{end}}*/ -package main -` +{{end}}` + +// commentWriter writes a Go comment to the underlying io.Writer, +// using line comment form (//). +type commentWriter struct { + W io.Writer + wroteSlashes bool // Wrote "//" at the beginning of the current line. +} + +func (c *commentWriter) Write(p []byte) (int, error) { + var n int + for i, b := range p { + if !c.wroteSlashes { + s := "//" + if b != '\n' { + s = "// " + } + if _, err := io.WriteString(c.W, s); err != nil { + return n, err + } + c.wroteSlashes = true + } + n0, err := c.W.Write(p[i : i+1]) + n += n0 + if err != nil { + return n, err + } + if b == '\n' { + c.wroteSlashes = false + } + } + return len(p), nil +} // An errWriter wraps a writer, recording whether a write error occurred. type errWriter struct { @@ -310,10 +332,18 @@ func help(args []string) { // 'go help documentation' generates doc.go. if arg == "documentation" { + fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.") + fmt.Println("// Use of this source code is governed by a BSD-style") + fmt.Println("// license that can be found in the LICENSE file.") + fmt.Println() + fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.") + fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.") + fmt.Println() buf := new(bytes.Buffer) printUsage(buf) usage := &Command{Long: buf.String()} - tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...)) + tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...)) + fmt.Println("package main") return } diff --git a/src/cmd/go/mkalldocs.sh b/src/cmd/go/mkalldocs.sh index 0f48ff2543..72886db1ea 100755 --- a/src/cmd/go/mkalldocs.sh +++ b/src/cmd/go/mkalldocs.sh @@ -6,7 +6,6 @@ set -e go build -o go.latest -./go.latest help documentation | sed 's; \*/; * /;' >alldocs.go +./go.latest help documentation >alldocs.go gofmt -w alldocs.go rm go.latest - diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index ee3f403dd6..07aa3ff2bc 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -1022,9 +1022,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package p.MFiles = nil p.SwigFiles = nil p.SwigCXXFiles = nil - p.SysoFiles = nil // Note that SFiles are okay (they go to the Go assembler) // and HFiles are okay (they might be used by the SFiles). + // Also Sysofiles are okay (they might not contain object + // code; see issue #16050). } // The gc toolchain only permits C source files with cgo. diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index bc5982e61c..e1527da255 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -129,7 +129,7 @@ control the execution of any test: const testFlag2 = ` -bench regexp Run (sub)benchmarks matching a regular expression. - The given regular expression is split into smaller ones by + The given regular expression is split into smaller ones by top-level '/', where each must match the corresponding part of a benchmark's identifier. By default, no benchmarks run. To run all benchmarks, @@ -221,7 +221,7 @@ const testFlag2 = ` -run regexp Run only those tests and examples matching the regular expression. For tests the regular expression is split into smaller ones by - top-level '/', where each must match the corresponding part of a + top-level '/', where each must match the corresponding part of a test's identifier. -short @@ -263,7 +263,7 @@ execution, not to the test itself.) The test flags that generate profiles (other than for coverage) also leave the test binary in pkg.test for use when analyzing the profiles. -When 'go test' runs a test binary, it does so from within the +When 'go test' runs a test binary, it does so from within the corresponding package's source code directory. Depending on the test, it may be necessary to do the same when invoking a generated test binary directly. diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 10b8cf8c49..f7c34de576 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -779,15 +779,31 @@ type metaImport struct { // errNoMatch is returned from matchGoImport when there's no applicable match. var errNoMatch = errors.New("no import match") +func splitPathHasPrefix(path, prefix []string) bool { + if len(path) < len(prefix) { + return false + } + for i, p := range prefix { + if path[i] != p { + return false + } + } + return true +} + // matchGoImport returns the metaImport from imports matching importPath. // An error is returned if there are multiple matches. // errNoMatch is returned if none match. func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) { match := -1 + imp := strings.Split(importPath, "/") for i, im := range imports { - if !strings.HasPrefix(importPath, im.Prefix) { + pre := strings.Split(im.Prefix, "/") + + if !splitPathHasPrefix(imp, pre) { continue } + if match != -1 { err = fmt.Errorf("multiple meta tags match import path %q", importPath) return diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go index 06650608ba..25e3866df0 100644 --- a/src/cmd/go/vcs_test.go +++ b/src/cmd/go/vcs_test.go @@ -5,6 +5,7 @@ package main import ( + "errors" "internal/testenv" "io/ioutil" "os" @@ -227,3 +228,96 @@ func TestIsSecure(t *testing.T) { } } } + +func TestMatchGoImport(t *testing.T) { + tests := []struct { + imports []metaImport + path string + mi metaImport + err error + }{ + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo", + mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/", + mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo", + mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/fooa", + mi: metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar/baz", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar/baz/qux", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar/baz/", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com", + err: errors.New("pathologically short path"), + }, + } + + for _, test := range tests { + mi, err := matchGoImport(test.imports, test.path) + if mi != test.mi { + t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi) + } + + got := err + want := test.err + if (got == nil) != (want == nil) { + t.Errorf("unexpected error; got %v, want %v", got, want) + } + } +} diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 414a4d34a5..676da40ba5 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -1986,16 +1986,6 @@ func span6(ctxt *obj.Link, s *obj.LSym) { c = naclpad(ctxt, s, c, -c&31) } - // Pad functions with trap instruction, to catch invalid jumps - if c&(FuncAlign-1) != 0 { - v := -c & (FuncAlign - 1) - s.Grow(int64(c) + int64(v)) - for i := c; i < c+v; i++ { - // 0xCC is INT $3 - breakpoint instruction - s.P[i] = uint8(0xCC) - } - c += v - } s.Size = int64(c) if false { /* debug['a'] > 1 */ diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 5dad0bbb98..75638a0183 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -1092,6 +1092,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob call.Mode = ctxt.Cursym.Text.Mode call.As = obj.ACALL call.To.Type = obj.TYPE_BRANCH + call.To.Name = obj.NAME_EXTERN morestack := "runtime.morestack" switch { case ctxt.Cursym.Cfunc: @@ -1100,8 +1101,17 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob morestack = "runtime.morestack_noctxt" } call.To.Sym = obj.Linklookup(ctxt, morestack, 0) + // When compiling 386 code for dynamic linking, the call needs to be adjusted + // to follow PIC rules. This in turn can insert more instructions, so we need + // to keep track of the start of the call (where the jump will be to) and the + // end (which following instructions are appended to). + callend := call + progedit(ctxt, callend) + for ; callend.Link != nil; callend = callend.Link { + progedit(ctxt, callend.Link) + } - jmp := obj.Appendp(ctxt, call) + jmp := obj.Appendp(ctxt, callend) jmp.As = obj.AJMP jmp.To.Type = obj.TYPE_BRANCH jmp.Pcond = ctxt.Cursym.Text.Link diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go index 3bad034097..c8114603d7 100644 --- a/src/cmd/internal/objfile/elf.go +++ b/src/cmd/internal/objfile/elf.go @@ -106,6 +106,15 @@ func (f *elfFile) goarch() string { return "" } +func (f *elfFile) loadAddress() (uint64, error) { + for _, p := range f.elf.Progs { + if p.Type == elf.PT_LOAD { + return p.Vaddr, nil + } + } + return 0, fmt.Errorf("unknown load address") +} + func (f *elfFile) dwarf() (*dwarf.Data, error) { return f.elf.DWARF() } diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go index 5a084a94be..43435efc68 100644 --- a/src/cmd/internal/objfile/goobj.go +++ b/src/cmd/internal/objfile/goobj.go @@ -94,6 +94,10 @@ func (f *goobjFile) goarch() string { return "GOARCH unimplemented for debug/goobj files" } +func (f *goobjFile) loadAddress() (uint64, error) { + return 0, fmt.Errorf("unknown load address") +} + func (f *goobjFile) dwarf() (*dwarf.Data, error) { return nil, errors.New("no DWARF data in go object file") } diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go index 754674d757..1d22a09b13 100644 --- a/src/cmd/internal/objfile/macho.go +++ b/src/cmd/internal/objfile/macho.go @@ -125,6 +125,10 @@ func (x uint64s) Len() int { return len(x) } func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } +func (f *machoFile) loadAddress() (uint64, error) { + return 0, fmt.Errorf("unknown load address") +} + func (f *machoFile) dwarf() (*dwarf.Data, error) { return f.macho.DWARF() } diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go index 48ed9ed489..e5d99f086b 100644 --- a/src/cmd/internal/objfile/objfile.go +++ b/src/cmd/internal/objfile/objfile.go @@ -18,6 +18,7 @@ type rawFile interface { pcln() (textStart uint64, symtab, pclntab []byte, err error) text() (textStart uint64, text []byte, err error) goarch() string + loadAddress() (uint64, error) dwarf() (*dwarf.Data, error) } @@ -95,6 +96,13 @@ func (f *File) GOARCH() string { return f.raw.goarch() } +// LoadAddress returns the expected load address of the file. +// This differs from the actual load address for a position-independent +// executable. +func (f *File) LoadAddress() (uint64, error) { + return f.raw.loadAddress() +} + // DWARF returns DWARF debug data for the file, if any. // This is for cmd/pprof to locate cgo functions. func (f *File) DWARF() (*dwarf.Data, error) { diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go index c024762371..46b2317242 100644 --- a/src/cmd/internal/objfile/pe.go +++ b/src/cmd/internal/objfile/pe.go @@ -199,6 +199,10 @@ func (f *peFile) goarch() string { return "" } +func (f *peFile) loadAddress() (uint64, error) { + return 0, fmt.Errorf("unknown load address") +} + func (f *peFile) dwarf() (*dwarf.Data, error) { return f.pe.DWARF() } diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go index 6ee389dc2e..3e34f65ae7 100644 --- a/src/cmd/internal/objfile/plan9obj.go +++ b/src/cmd/internal/objfile/plan9obj.go @@ -147,6 +147,10 @@ func (f *plan9File) goarch() string { return "" } +func (f *plan9File) loadAddress() (uint64, error) { + return 0, fmt.Errorf("unknown load address") +} + func (f *plan9File) dwarf() (*dwarf.Data, error) { return nil, errors.New("no DWARF data in Plan 9 file") } diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 48250c92c8..eff9a22566 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -615,7 +615,8 @@ func asmb() { sect := ld.Segtext.Sect ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) + // 0xCC is INT $3 - breakpoint instruction + ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC}) for sect = sect.Next; sect != nil; sect = sect.Next { ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 6e326ec1c9..57a0dad491 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -790,11 +790,14 @@ func blk(start *LSym, addr int64, size int64) { } func Codeblk(addr int64, size int64) { + CodeblkPad(addr, size, zeros[:]) +} +func CodeblkPad(addr int64, size int64, pad []byte) { if Debug['a'] != 0 { fmt.Fprintf(Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) } - blkSlice(Ctxt.Textp, addr, size) + blkSlice(Ctxt.Textp, addr, size, pad) /* again for printing */ if Debug['a'] == 0 { @@ -858,7 +861,7 @@ func Codeblk(addr int64, size int64) { // blkSlice is a variant of blk that processes slices. // After text symbols are converted from a linked list to a slice, // delete blk and give this function its name. -func blkSlice(syms []*LSym, addr, size int64) { +func blkSlice(syms []*LSym, addr, size int64, pad []byte) { for i, s := range syms { if s.Type&obj.SSUB == 0 && s.Value >= addr { syms = syms[i:] @@ -880,13 +883,13 @@ func blkSlice(syms []*LSym, addr, size int64) { errorexit() } if addr < s.Value { - strnput("", int(s.Value-addr)) + strnputPad("", int(s.Value-addr), pad) addr = s.Value } Cwrite(s.P) addr += int64(len(s.P)) if addr < s.Value+s.Size { - strnput("", int(s.Value+s.Size-addr)) + strnputPad("", int(s.Value+s.Size-addr), pad) addr = s.Value + s.Size } if addr != s.Value+s.Size { @@ -899,7 +902,7 @@ func blkSlice(syms []*LSym, addr, size int64) { } if addr < eaddr { - strnput("", int(eaddr-addr)) + strnputPad("", int(eaddr-addr), pad) } Cflush() } @@ -909,7 +912,7 @@ func Datblk(addr int64, size int64) { fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) } - blkSlice(datap, addr, size) + blkSlice(datap, addr, size, zeros[:]) /* again for printing */ if Debug['a'] == 0 { @@ -986,23 +989,27 @@ func Dwarfblk(addr int64, size int64) { var zeros [512]byte // strnput writes the first n bytes of s. -// If n is larger then len(s), +// If n is larger than len(s), // it is padded with NUL bytes. func strnput(s string, n int) { + strnputPad(s, n, zeros[:]) +} + +// strnput writes the first n bytes of s. +// If n is larger than len(s), +// it is padded with the bytes in pad (repeated as needed). +func strnputPad(s string, n int, pad []byte) { if len(s) >= n { Cwritestring(s[:n]) } else { Cwritestring(s) n -= len(s) - for n > 0 { - if len(zeros) >= n { - Cwrite(zeros[:n]) - return - } else { - Cwrite(zeros[:]) - n -= len(zeros) - } + for n > len(pad) { + Cwrite(pad) + n -= len(pad) + } + Cwrite(pad[:n]) } } diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 01747c5430..fa7105f620 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -529,7 +529,7 @@ func walktypedef(die *DWDie) *DWDie { } func walksymtypedef(s *LSym) *LSym { - if t := Linkrlookup(Ctxt, s.Name+".def", int(s.Version)); t != nil { + if t := Linkrlookup(Ctxt, s.Name+"..def", int(s.Version)); t != nil { return t } return s @@ -819,7 +819,7 @@ func dotypedef(parent *DWDie, name string, def *DWDie) { Diag("dwarf: bad def in dotypedef") } - def.sym = Linklookup(Ctxt, def.sym.Name+".def", 0) + def.sym = Linklookup(Ctxt, def.sym.Name+"..def", 0) def.sym.Attr |= AttrHidden def.sym.Type = obj.SDWARFINFO @@ -1021,7 +1021,7 @@ func newtype(gotype *LSym) *DWDie { } func nameFromDIESym(dwtype *LSym) string { - return strings.TrimSuffix(dwtype.Name[len(infoprefix):], ".def") + return strings.TrimSuffix(dwtype.Name[len(infoprefix):], "..def") } // Find or construct *T given T. diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index bab71fb311..14f4fa9aad 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1222,19 +1222,28 @@ func hostlink() { } } + sanitizers := flag_race != 0 + + for _, flag := range ldflag { + if strings.HasPrefix(flag, "-fsanitize=") { + sanitizers = true + } + } + argv = append(argv, ldflag...) - if flag_race != 0 { + if sanitizers { // On a system where the toolchain creates position independent - // executables by default, tsan initialization can fail. So we pass - // -no-pie here, but support for that flag is quite new and we test - // for its support first. + // executables by default, tsan/msan/asan/etc initialization can + // fail. So we pass -no-pie here, but support for that flag is quite + // new and we test for its support first. src := filepath.Join(tmpdir, "trivial.c") if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { Ctxt.Diag("WriteFile trivial.c failed: %v", err) } cmd := exec.Command(argv[0], "-c", "-no-pie", "trivial.c") cmd.Dir = tmpdir + cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...) out, err := cmd.CombinedOutput() supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) if supported { diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 2a3513f6a6..cc8f96f27f 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -609,7 +609,8 @@ func asmb() { sect := ld.Segtext.Sect ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) - ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) + // 0xCC is INT $3 - breakpoint instruction + ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC}) for sect = sect.Next; sect != nil; sect = sect.Next { ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index bce37dcb97..0187045b4a 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -117,6 +117,9 @@ func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) { name: name, file: of, } + if load, err := of.LoadAddress(); err == nil { + f.offset = start - load + } return f, nil } @@ -169,10 +172,11 @@ func (*objTool) SetConfig(config string) { // (instead of invoking GNU binutils). // A file represents a single executable being analyzed. type file struct { - name string - sym []objfile.Sym - file *objfile.File - pcln *gosym.Table + name string + offset uint64 + sym []objfile.Sym + file *objfile.File + pcln *gosym.Table triedDwarf bool dwarf *dwarf.Data @@ -200,6 +204,7 @@ func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) { } f.pcln = pcln } + addr -= f.offset file, line, fn := f.pcln.PCToLine(addr) if fn != nil { frame := []plugin.Frame{ diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go index 8467d7749d..8a085ba347 100644 --- a/src/compress/flate/deflate.go +++ b/src/compress/flate/deflate.go @@ -16,9 +16,12 @@ const ( BestCompression = 9 DefaultCompression = -1 HuffmanOnly = -2 // Disables match search and only does Huffman entropy reduction. - logWindowSize = 15 - windowSize = 1 << logWindowSize - windowMask = windowSize - 1 +) + +const ( + logWindowSize = 15 + windowSize = 1 << logWindowSize + windowMask = windowSize - 1 // The LZ77 step produces a sequence of literal tokens and // pair tokens. The offset is also known as distance. The underlying wire diff --git a/src/context/context.go b/src/context/context.go index 169db74f57..fc2a56ebff 100644 --- a/src/context/context.go +++ b/src/context/context.go @@ -107,7 +107,7 @@ type Context interface { // collisions. // // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: + // for the values stored using that key: // // // Package user defines a User type that's stored in Contexts. // package user diff --git a/src/crypto/subtle/constant_time.go b/src/crypto/subtle/constant_time.go index 6f80e7c58d..11312b8dd4 100644 --- a/src/crypto/subtle/constant_time.go +++ b/src/crypto/subtle/constant_time.go @@ -6,7 +6,7 @@ // code but require careful thought to use correctly. package subtle -// ConstantTimeCompare returns 1 iff the two slices, x +// ConstantTimeCompare returns 1 if and only if the two slices, x // and y, have equal contents. The time taken is a function of the length of // the slices and is independent of the contents. func ConstantTimeCompare(x, y []byte) int { diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index 40c17440d6..87bef23d91 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -71,10 +71,12 @@ type Conn struct { clientProtocolFallback bool // input/output - in, out halfConn // in.Mutex < out.Mutex - rawInput *block // raw input, right off the wire - input *block // application data waiting to be read - hand bytes.Buffer // handshake data waiting to be read + in, out halfConn // in.Mutex < out.Mutex + rawInput *block // raw input, right off the wire + input *block // application data waiting to be read + hand bytes.Buffer // handshake data waiting to be read + buffering bool // whether records are buffered in sendBuf + sendBuf []byte // a buffer of records waiting to be sent // bytesSent counts the bytes of application data sent. // packetsSent counts packets. @@ -803,6 +805,30 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int { return n } +// c.out.Mutex <= L. +func (c *Conn) write(data []byte) (int, error) { + if c.buffering { + c.sendBuf = append(c.sendBuf, data...) + return len(data), nil + } + + n, err := c.conn.Write(data) + c.bytesSent += int64(n) + return n, err +} + +func (c *Conn) flush() (int, error) { + if len(c.sendBuf) == 0 { + return 0, nil + } + + n, err := c.conn.Write(c.sendBuf) + c.bytesSent += int64(n) + c.sendBuf = nil + c.buffering = false + return n, err +} + // writeRecordLocked writes a TLS record with the given type and payload to the // connection and updates the record layer state. // c.out.Mutex <= L. @@ -862,10 +888,9 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { } copy(b.data[recordHeaderLen+explicitIVLen:], data) c.out.encrypt(b, explicitIVLen) - if _, err := c.conn.Write(b.data); err != nil { + if _, err := c.write(b.data); err != nil { return n, err } - c.bytesSent += int64(m) n += m data = data[m:] } diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 475737b989..f789e6f888 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -206,6 +206,7 @@ NextCipherSuite: hs.finishedHash.Write(hs.hello.marshal()) hs.finishedHash.Write(hs.serverHello.marshal()) + c.buffering = true if isResume { if err := hs.establishKeys(); err != nil { return err @@ -220,6 +221,9 @@ NextCipherSuite: if err := hs.sendFinished(c.clientFinished[:]); err != nil { return err } + if _, err := c.flush(); err != nil { + return err + } } else { if err := hs.doFullHandshake(); err != nil { return err @@ -230,6 +234,9 @@ NextCipherSuite: if err := hs.sendFinished(c.clientFinished[:]); err != nil { return err } + if _, err := c.flush(); err != nil { + return err + } c.clientFinishedIsFirst = true if err := hs.readSessionTicket(); err != nil { return err diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 40b0770e12..c5000e5907 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -983,7 +983,7 @@ func (b *brokenConn) Write(data []byte) (int, error) { func TestFailedWrite(t *testing.T) { // Test that a write error during the handshake is returned. - for _, breakAfter := range []int{0, 1, 2, 3} { + for _, breakAfter := range []int{0, 1} { c, s := net.Pipe() done := make(chan bool) @@ -1003,3 +1003,45 @@ func TestFailedWrite(t *testing.T) { <-done } } + +// writeCountingConn wraps a net.Conn and counts the number of Write calls. +type writeCountingConn struct { + net.Conn + + // numWrites is the number of writes that have been done. + numWrites int +} + +func (wcc *writeCountingConn) Write(data []byte) (int, error) { + wcc.numWrites++ + return wcc.Conn.Write(data) +} + +func TestBuffering(t *testing.T) { + c, s := net.Pipe() + done := make(chan bool) + + clientWCC := &writeCountingConn{Conn: c} + serverWCC := &writeCountingConn{Conn: s} + + go func() { + Server(serverWCC, testConfig).Handshake() + serverWCC.Close() + done <- true + }() + + err := Client(clientWCC, testConfig).Handshake() + if err != nil { + t.Fatal(err) + } + clientWCC.Close() + <-done + + if n := clientWCC.numWrites; n != 2 { + t.Errorf("expected client handshake to complete with only two writes, but saw %d", n) + } + + if n := serverWCC.numWrites; n != 2 { + t.Errorf("expected server handshake to complete with only two writes, but saw %d", n) + } +} diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index cf617df19f..1aac729561 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -52,6 +52,7 @@ func (c *Conn) serverHandshake() error { } // For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3 + c.buffering = true if isResume { // The client has included a session ticket and so we do an abbreviated handshake. if err := hs.doResumeHandshake(); err != nil { @@ -71,6 +72,9 @@ func (c *Conn) serverHandshake() error { if err := hs.sendFinished(c.serverFinished[:]); err != nil { return err } + if _, err := c.flush(); err != nil { + return err + } c.clientFinishedIsFirst = false if err := hs.readFinished(nil); err != nil { return err @@ -89,12 +93,16 @@ func (c *Conn) serverHandshake() error { return err } c.clientFinishedIsFirst = true + c.buffering = true if err := hs.sendSessionTicket(); err != nil { return err } if err := hs.sendFinished(nil); err != nil { return err } + if _, err := c.flush(); err != nil { + return err + } } c.handshakeComplete = true @@ -430,6 +438,10 @@ func (hs *serverHandshakeState) doFullHandshake() error { return err } + if _, err := c.flush(); err != nil { + return err + } + var pub crypto.PublicKey // public key for client auth, if any msg, err := c.readHandshake() diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go index 894d7e82ab..5b665bf532 100644 --- a/src/crypto/tls/tls_test.go +++ b/src/crypto/tls/tls_test.go @@ -481,20 +481,19 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool N := b.N - var serr error go func() { for i := 0; i < N; i++ { sconn, err := ln.Accept() if err != nil { - serr = err - return + // panic rather than synchronize to avoid benchmark overhead + // (cannot call b.Fatal in goroutine) + panic(fmt.Errorf("accept: %v", err)) } serverConfig := *testConfig serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled srv := Server(sconn, &serverConfig) if err := srv.Handshake(); err != nil { - serr = fmt.Errorf("handshake: %v", err) - return + panic(fmt.Errorf("handshake: %v", err)) } io.Copy(srv, srv) } @@ -504,7 +503,7 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool clientConfig := *testConfig clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled - buf := make([]byte, 1<<16) + buf := make([]byte, 1<<14) chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf)))) for i := 0; i < N; i++ { conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) @@ -570,20 +569,19 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) { N := b.N - var serr error go func() { for i := 0; i < N; i++ { sconn, err := ln.Accept() if err != nil { - serr = err - return + // panic rather than synchronize to avoid benchmark overhead + // (cannot call b.Fatal in goroutine) + panic(fmt.Errorf("accept: %v", err)) } serverConfig := *testConfig serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled srv := Server(&slowConn{sconn, bps}, &serverConfig) if err := srv.Handshake(); err != nil { - serr = fmt.Errorf("handshake: %v", err) - return + panic(fmt.Errorf("handshake: %v", err)) } io.Copy(srv, srv) } diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 9e6d67df55..9ad3cf23f6 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -1796,6 +1796,9 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { var rawAttributes []asn1.RawValue b, err := asn1.Marshal(attributes) + if err != nil { + return nil, err + } rest, err := asn1.Unmarshal(b, &rawAttributes) if err != nil { return nil, err diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go index 89283bb303..a5e03a9f8e 100644 --- a/src/encoding/csv/reader.go +++ b/src/encoding/csv/reader.go @@ -86,34 +86,35 @@ var ( // The exported fields can be changed to customize the details before the // first call to Read or ReadAll. // -// Comma is the field delimiter. It defaults to ','. // -// Comment, if not 0, is the comment character. Lines beginning with the -// Comment character are ignored. -// -// If FieldsPerRecord is positive, Read requires each record to -// have the given number of fields. If FieldsPerRecord is 0, Read sets it to -// the number of fields in the first record, so that future records must -// have the same field count. If FieldsPerRecord is negative, no check is -// made and records may have a variable number of fields. -// -// If LazyQuotes is true, a quote may appear in an unquoted field and a -// non-doubled quote may appear in a quoted field. -// -// If TrimLeadingSpace is true, leading white space in a field is ignored. -// If the field delimiter is white space, TrimLeadingSpace will trim the -// delimiter. type Reader struct { - Comma rune // field delimiter (set to ',' by NewReader) - Comment rune // comment character for start of line - FieldsPerRecord int // number of expected fields per record - LazyQuotes bool // allow lazy quotes - TrailingComma bool // ignored; here for backwards compatibility - TrimLeadingSpace bool // trim leading space - line int - column int - r *bufio.Reader - field bytes.Buffer + // Comma is the field delimiter. + // It is set to comma (',') by NewReader. + Comma rune + // Comment, if not 0, is the comment character. Lines beginning with the + // Comment character without preceding whitespace are ignored. + // With leading whitespace the Comment character becomes part of the + // field, even if TrimLeadingSpace is true. + Comment rune + // FieldsPerRecord is the number of expected fields per record. + // If FieldsPerRecord is positive, Read requires each record to + // have the given number of fields. If FieldsPerRecord is 0, Read sets it to + // the number of fields in the first record, so that future records must + // have the same field count. If FieldsPerRecord is negative, no check is + // made and records may have a variable number of fields. + FieldsPerRecord int + // If LazyQuotes is true, a quote may appear in an unquoted field and a + // non-doubled quote may appear in a quoted field. + LazyQuotes bool + TrailingComma bool // ignored; here for backwards compatibility + // If TrimLeadingSpace is true, leading white space in a field is ignored. + // This is done even if the field delimiter, Comma, is white space. + TrimLeadingSpace bool + + line int + column int + r *bufio.Reader + field bytes.Buffer } // NewReader returns a new Reader that reads from r. diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 3917084dc3..d864022730 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -90,8 +90,8 @@ import ( // Int64String int64 `json:",string"` // // The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, dollar signs, percent signs, hyphens, -// underscores and slashes. +// only Unicode letters, digits, and ASCII punctuation except quotation +// marks, backslash, and comma. // // Anonymous struct fields are usually marshaled as if their inner exported fields // were fields in the outer struct, subject to the usual Go visibility rules amended diff --git a/src/flag/flag.go b/src/flag/flag.go index 6acbbcd321..fa0f05e968 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -68,6 +68,7 @@ import ( "fmt" "io" "os" + "reflect" "sort" "strconv" "time" @@ -378,7 +379,21 @@ func Set(name, value string) error { // isZeroValue guesses whether the string represents the zero // value for a flag. It is not accurate but in practice works OK. -func isZeroValue(value string) bool { +func isZeroValue(flag *Flag, value string) bool { + // Build a zero value of the flag's Value type, and see if the + // result of calling its String method equals the value passed in. + // This works unless the Value type is itself an interface type. + typ := reflect.TypeOf(flag.Value) + var z reflect.Value + if typ.Kind() == reflect.Ptr { + z = reflect.New(typ.Elem()) + } else { + z = reflect.Zero(typ) + } + if value == z.Interface().(Value).String() { + return true + } + switch value { case "false": return true @@ -449,7 +464,7 @@ func (f *FlagSet) PrintDefaults() { s += "\n \t" } s += usage - if !isZeroValue(flag.DefValue) { + if !isZeroValue(flag, flag.DefValue) { if _, ok := flag.Value.(*stringValue); ok { // put quotes on the value s += fmt.Sprintf(" (default %q)", flag.DefValue) diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 1a8bdc106a..e2319ec94c 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -393,7 +393,7 @@ const defaultOutput = ` -A for bootstrapping, allow 'any' type -Z int an int that defaults to zero -maxT timeout - set timeout for dial (default 0s) + set timeout for dial ` func TestPrintDefaults(t *testing.T) { diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index f9a428edd4..335e774a7c 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -173,7 +173,7 @@ var pkgDeps = map[string][]string{ "regexp": {"L2", "regexp/syntax"}, "regexp/syntax": {"L2"}, "runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"}, - "runtime/pprof": {"L2", "fmt", "text/tabwriter"}, + "runtime/pprof": {"L2", "fmt", "os", "text/tabwriter"}, "runtime/trace": {"L0"}, "text/tabwriter": {"L2"}, diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index 8de36c713c..d8c5bcfb1c 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -400,3 +400,28 @@ func TestIssue15517(t *testing.T) { } } } + +func TestIssue15920(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + return + } + + // On windows, we have to set the -D option for the compiler to avoid having a drive + // letter and an illegal ':' in the import path - just skip it (see also issue #3483). + if runtime.GOOS == "windows" { + t.Skip("avoid dealing with relative paths/drive letters on windows") + } + + if f := compile(t, "testdata", "issue15920.go"); f != "" { + defer os.Remove(f) + } + + imports := make(map[string]*types.Package) + if _, err := Import(imports, "./testdata/issue15920", "."); err != nil { + t.Fatal(err) + } +} diff --git a/src/go/internal/gcimporter/testdata/issue15920.go b/src/go/internal/gcimporter/testdata/issue15920.go new file mode 100644 index 0000000000..c70f7d8267 --- /dev/null +++ b/src/go/internal/gcimporter/testdata/issue15920.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +// The underlying type of Error is the underlying type of error. +// Make sure we can import this again without problems. +type Error error + +func F() Error { return nil } diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go index c6fd93240a..bff79cab46 100644 --- a/src/go/parser/interface.go +++ b/src/go/parser/interface.go @@ -73,7 +73,7 @@ const ( // // The mode parameter controls the amount of source text parsed and other // optional parser functionality. Position information is recorded in the -// file set fset. +// file set fset, which must not be nil. // // If the source couldn't be read, the returned AST is nil and the error // indicates the specific failure. If the source was read but syntax @@ -82,6 +82,10 @@ const ( // are returned via a scanner.ErrorList which is sorted by file position. // func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) { + if fset == nil { + panic("parser.ParseFile: no token.FileSet provided (fset == nil)") + } + // get source text, err := readSource(filename, src) if err != nil { @@ -125,7 +129,8 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) // // If filter != nil, only the files with os.FileInfo entries passing through // the filter (and ending in ".go") are considered. The mode bits are passed -// to ParseFile unchanged. Position information is recorded in fset. +// to ParseFile unchanged. Position information is recorded in fset, which +// must not be nil. // // If the directory couldn't be read, a nil map and the respective error are // returned. If a parse error occurred, a non-nil but incomplete map and the @@ -169,9 +174,14 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m // ParseExprFrom is a convenience function for parsing an expression. // The arguments have the same meaning as for Parse, but the source must -// be a valid Go (type or value) expression. +// be a valid Go (type or value) expression. Specifically, fset must not +// be nil. // func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) { + if fset == nil { + panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)") + } + // get source text, err := readSource(filename, src) if err != nil { diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 8b8ae1bb5d..035ffd6f39 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -572,6 +572,47 @@ func TestInitOrderInfo(t *testing.T) { `, []string{ "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()", }}, + // test case for issue 10709 + // TODO(gri) enable once the issue is fixed + // {`package p13 + + // var ( + // v = t.m() + // t = makeT(0) + // ) + + // type T struct{} + + // func (T) m() int { return 0 } + + // func makeT(n int) T { + // if n > 0 { + // return makeT(n-1) + // } + // return T{} + // }`, []string{ + // "t = makeT(0)", "v = t.m()", + // }}, + // test case for issue 10709: same as test before, but variable decls swapped + {`package p14 + + var ( + t = makeT(0) + v = t.m() + ) + + type T struct{} + + func (T) m() int { return 0 } + + func makeT(n int) T { + if n > 0 { + return makeT(n-1) + } + return T{} + }`, []string{ + "t = makeT(0)", "v = t.m()", + }}, } for _, test := range tests { diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go index ac9016b46e..cf9b8709d8 100644 --- a/src/go/types/initorder.go +++ b/src/go/types/initorder.go @@ -15,25 +15,40 @@ func (check *Checker) initOrder() { // built from several calls to (*Checker).Files. Clear it. check.Info.InitOrder = check.Info.InitOrder[:0] - // compute the object dependency graph and - // initialize a priority queue with the list - // of graph nodes + // Compute the transposed object dependency graph and initialize + // a priority queue with the list of graph nodes. pq := nodeQueue(dependencyGraph(check.objMap)) heap.Init(&pq) const debug = false if debug { - fmt.Printf("package %s: object dependency graph\n", check.pkg.Name()) - for _, n := range pq { - for _, o := range n.out { - fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name()) + fmt.Printf("Computing initialization order for %s\n\n", check.pkg) + fmt.Println("Object dependency graph:") + for obj, d := range check.objMap { + if len(d.deps) > 0 { + fmt.Printf("\t%s depends on\n", obj.Name()) + for dep := range d.deps { + fmt.Printf("\t\t%s\n", dep.Name()) + } + } else { + fmt.Printf("\t%s has no dependencies\n", obj.Name()) } } fmt.Println() - fmt.Printf("package %s: initialization order\n", check.pkg.Name()) + + fmt.Println("Transposed object dependency graph:") + for _, n := range pq { + fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.in) + for _, out := range n.out { + fmt.Printf("\t\t%s is dependent\n", out.obj.Name()) + } + } + fmt.Println() + + fmt.Println("Processing nodes:") } - // determine initialization order by removing the highest priority node + // Determine initialization order by removing the highest priority node // (the one with the fewest dependencies) and its edges from the graph, // repeatedly, until there are no nodes left. // In a valid Go program, those nodes always have zero dependencies (after @@ -45,6 +60,11 @@ func (check *Checker) initOrder() { // get the next node n := heap.Pop(&pq).(*objNode) + if debug { + fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n", + n.obj.Name(), n.obj.order(), n.in) + } + // if n still depends on other nodes, we have a cycle if n.in > 0 { mark++ // mark nodes using a different value each time @@ -86,14 +106,15 @@ func (check *Checker) initOrder() { } init := &Initializer{infoLhs, info.init} check.Info.InitOrder = append(check.Info.InitOrder, init) - - if debug { - fmt.Printf("\t%s\n", init) - } } if debug { fmt.Println() + fmt.Println("Initialization order:") + for _, init := range check.Info.InitOrder { + fmt.Printf("\t%s\n", init) + } + fmt.Println() } } diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 992188f0ff..cb8e72e4a6 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -32,7 +32,7 @@ func (d *declInfo) hasInitializer() bool { return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil } -// addDep adds obj as a dependency to d. +// addDep adds obj to the set of objects d's init expression depends on. func (d *declInfo) addDep(obj Object) { m := d.deps if m == nil { diff --git a/src/io/io.go b/src/io/io.go index 80398b3997..19d0ae5add 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -102,10 +102,12 @@ type Closer interface { // Seeker is the interface that wraps the basic Seek method. // // Seek sets the offset for the next Read or Write to offset, -// interpreted according to whence: 0 means relative to the start of -// the file, 1 means relative to the current offset, and 2 means -// relative to the end. Seek returns the new offset relative to the -// start of the file and an error, if any. +// interpreted according to whence: +// SeekStart means relative to the start of the file, +// SeekCurrent means relative to the current offset, and +// SeekEnd means relative to the end. +// Seek returns the new offset relative to the start of the +// file and an error, if any. // // Seeking to an offset before the start of the file is an error. // Seeking to any positive offset is legal, but the behavior of subsequent diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go index b6f9993608..b2a1ab05fc 100644 --- a/src/math/big/floatconv_test.go +++ b/src/math/big/floatconv_test.go @@ -290,6 +290,11 @@ func TestFloat64Text(t *testing.T) { // Issue 2625. {383260575764816448, 'f', 0, "383260575764816448"}, {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, + + // Issue 15918. + {1, 'f', -10, "1"}, + {1, 'f', -11, "1"}, + {1, 'f', -12, "1"}, } { // The test cases are from the strconv package which tests float64 values. // When formatting values with prec = -1 (shortest representation), diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go index 624ea5e073..57b16e1ad1 100644 --- a/src/math/big/ftoa.go +++ b/src/math/big/ftoa.go @@ -41,8 +41,11 @@ import ( // x.Prec() mantissa bits. // The prec value is ignored for the 'b' or 'p' format. func (x *Float) Text(format byte, prec int) string { - const extra = 10 // TODO(gri) determine a good/better value here - return string(x.Append(make([]byte, 0, prec+extra), format, prec)) + cap := 10 // TODO(gri) determine a good/better value here + if prec > 0 { + cap += prec + } + return string(x.Append(make([]byte, 0, cap), format, prec)) } // String formats x like x.Text('g', 10). diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 5365677011..9fe507e901 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -87,17 +87,14 @@ func TestDialTimeoutFDLeak(t *testing.T) { // socktest.Switch. // It may happen when the Dial call bumps against TCP // simultaneous open. See selfConnect in tcpsock_posix.go. - defer func() { - sw.Set(socktest.FilterClose, nil) - forceCloseSockets() - }() + defer func() { sw.Set(socktest.FilterClose, nil) }() var mu sync.Mutex var attempts int sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) { mu.Lock() attempts++ mu.Unlock() - return nil, errTimedout + return nil, nil }) const N = 100 diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 9cedcaa73d..a7ab691f6a 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -25,8 +25,6 @@ import ( "encoding/binary" "errors" "fmt" - "golang.org/x/net/http2/hpack" - "golang.org/x/net/lex/httplex" "io" "io/ioutil" "log" @@ -42,6 +40,9 @@ import ( "strings" "sync" "time" + + "golang.org/x/net/http2/hpack" + "golang.org/x/net/lex/httplex" ) // ClientConnPool manages a pool of HTTP/2 client connections. @@ -291,7 +292,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) { t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1") } upgradeFn := func(authority string, c *tls.Conn) RoundTripper { - addr := http2authorityAddr(authority) + addr := http2authorityAddr("https", authority) if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil { go c.Close() return http2erringRoundTripper{err} @@ -2630,6 +2631,12 @@ type http2pipeBuffer interface { io.Reader } +func (p *http2pipe) Len() int { + p.mu.Lock() + defer p.mu.Unlock() + return p.b.Len() +} + // Read waits until data is available and copies bytes // from the buffer into p. func (p *http2pipe) Read(d []byte) (n int, err error) { @@ -4848,6 +4855,10 @@ type http2Transport struct { // uncompressed. DisableCompression bool + // AllowHTTP, if true, permits HTTP/2 requests using the insecure, + // plain-text "http" scheme. Note that this does not enable h2c support. + AllowHTTP bool + // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to // send in the initial settings frame. It is how many bytes // of response headers are allow. Unlike the http2 spec, zero here @@ -4963,6 +4974,7 @@ type http2clientStream struct { done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu // owned by clientConnReadLoop: + firstByte bool // got the first response byte pastHeaders bool // got first MetaHeadersFrame (actual headers) pastTrailers bool // got optional second MetaHeadersFrame (trailers) @@ -5046,20 +5058,24 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) { // authorityAddr returns a given authority (a host/IP, or host:port / ip:port) // and returns a host:port. The port 443 is added if needed. -func http2authorityAddr(authority string) (addr string) { +func http2authorityAddr(scheme string, authority string) (addr string) { if _, _, err := net.SplitHostPort(authority); err == nil { return authority } - return net.JoinHostPort(authority, "443") + port := "443" + if scheme == "http" { + port = "80" + } + return net.JoinHostPort(authority, port) } // RoundTripOpt is like RoundTrip, but takes options. func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) { - if req.URL.Scheme != "https" { + if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) { return nil, errors.New("http2: unsupported scheme") } - addr := http2authorityAddr(req.URL.Host) + addr := http2authorityAddr(req.URL.Scheme, req.URL.Host) for { cc, err := t.connPool().GetClientConn(req, addr) if err != nil { @@ -5944,15 +5960,18 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro return nil } + if !cs.firstByte { + if cs.trace != nil { + + http2traceFirstResponseByte(cs.trace) + } + cs.firstByte = true + } if !cs.pastHeaders { cs.pastHeaders = true } else { return rl.processTrailers(cs, f) } - if cs.trace != nil { - - http2traceFirstResponseByte(cs.trace) - } res, err := rl.handleResponse(cs, f) if err != nil { @@ -6139,8 +6158,10 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) { cc.inflow.add(connAdd) } if err == nil { - if v := cs.inflow.available(); v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh { - streamAdd = http2transportDefaultStreamFlow - v + + v := int(cs.inflow.available()) + cs.bufPipe.Len() + if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh { + streamAdd = int32(http2transportDefaultStreamFlow - v) cs.inflow.add(streamAdd) } } diff --git a/src/net/http/httputil/persist.go b/src/net/http/httputil/persist.go index 51486e78e2..87ddd52cd9 100644 --- a/src/net/http/httputil/persist.go +++ b/src/net/http/httputil/persist.go @@ -25,7 +25,7 @@ var ( var errClosed = errors.New("i/o operation on closed connection") // ServerConn is an artifact of Go's early HTTP implementation. -// Is is low-level, old, and unused by Go's current HTTP stack. +// It is low-level, old, and unused by Go's current HTTP stack. // We should have deleted it before Go 1. // // Deprecated: Use the Server in package net/http instead. @@ -42,7 +42,7 @@ type ServerConn struct { } // NewServerConn is an artifact of Go's early HTTP implementation. -// Is is low-level, old, and unused by Go's current HTTP stack. +// It is low-level, old, and unused by Go's current HTTP stack. // We should have deleted it before Go 1. // // Deprecated: Use the Server in package net/http instead. @@ -218,7 +218,7 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error { } // ClientConn is an artifact of Go's early HTTP implementation. -// Is is low-level, old, and unused by Go's current HTTP stack. +// It is low-level, old, and unused by Go's current HTTP stack. // We should have deleted it before Go 1. // // Deprecated: Use Client or Transport in package net/http instead. @@ -236,7 +236,7 @@ type ClientConn struct { } // NewClientConn is an artifact of Go's early HTTP implementation. -// Is is low-level, old, and unused by Go's current HTTP stack. +// It is low-level, old, and unused by Go's current HTTP stack. // We should have deleted it before Go 1. // // Deprecated: Use the Client or Transport in package net/http instead. @@ -253,7 +253,7 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn { } // NewProxyClientConn is an artifact of Go's early HTTP implementation. -// Is is low-level, old, and unused by Go's current HTTP stack. +// It is low-level, old, and unused by Go's current HTTP stack. // We should have deleted it before Go 1. // // Deprecated: Use the Client or Transport in package net/http instead. diff --git a/src/net/http/request.go b/src/net/http/request.go index e8780dea94..dc5559282d 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -275,9 +275,9 @@ type Request struct { // // For outgoing client requests, the context controls cancelation. // -// For incoming server requests, the context is canceled when either -// the client's connection closes, or when the ServeHTTP method -// returns. +// For incoming server requests, the context is canceled when the +// ServeHTTP method returns. For its associated values, see +// ServerContextKey and LocalAddrContextKey. func (r *Request) Context() context.Context { if r.ctx != nil { return r.ctx diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index c32ff29902..8e4bbdc0c4 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -1996,6 +1996,26 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) { } } +// https://golang.org/issue/15948 +func TestTimeoutHandlerEmptyResponse(t *testing.T) { + defer afterTest(t) + var handler HandlerFunc = func(w ResponseWriter, _ *Request) { + // No response. + } + timeout := 300 * time.Millisecond + ts := httptest.NewServer(TimeoutHandler(handler, timeout, "")) + defer ts.Close() + + res, err := Get(ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if res.StatusCode != StatusOK { + t.Errorf("got res.StatusCode %d, want %v", res.StatusCode, StatusOK) + } +} + // Verifies we don't path.Clean() on the wrong parts in redirects. func TestRedirectMunging(t *testing.T) { req, _ := NewRequest("GET", "http://example.com/", nil) @@ -4166,6 +4186,20 @@ func testServerContext_ServerContextKey(t *testing.T, h2 bool) { res.Body.Close() } +// https://golang.org/issue/15960 +func TestHandlerSetTransferEncodingChunked(t *testing.T) { + defer afterTest(t) + ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Transfer-Encoding", "chunked") + w.Write([]byte("hello")) + })) + resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo") + const hdr = "Transfer-Encoding: chunked" + if n := strings.Count(resp, hdr); n != 1 { + t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp) + } +} + func BenchmarkClientServer(b *testing.B) { b.ReportAllocs() b.StopTimer() diff --git a/src/net/http/server.go b/src/net/http/server.go index 1a8c0fc6cc..8ecced85db 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1147,6 +1147,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { // to avoid closing the connection at EOF. cw.chunking = true setHeader.transferEncoding = "chunked" + delHeader("Transfer-Encoding") } } else { // HTTP version < 1.1: cannot do chunked transfer @@ -2463,6 +2464,9 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { for k, vv := range tw.h { dst[k] = vv } + if !tw.wroteHeader { + tw.code = StatusOK + } w.WriteHeader(tw.code) w.Write(tw.wbuf.Bytes()) if t != nil { diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 1c1a1d0397..d653a5a7fc 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3312,27 +3312,30 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { } got := buf.String() - wantSub := func(sub string) { - if !strings.Contains(got, sub) { - t.Errorf("expected substring %q in output.", sub) + wantOnce := func(sub string) { + if strings.Count(got, sub) != 1 { + t.Errorf("expected substring %q exactly once in output.", sub) } } - if strings.Count(got, "got conn: {") != 1 { - t.Errorf("expected exactly 1 \"got conn\" event.") + wantOnceOrMore := func(sub string) { + if strings.Count(got, sub) == 0 { + t.Errorf("expected substring %q at least once in output.", sub) + } } - wantSub("Getting conn for dns-is-faked.golang:" + port) - wantSub("DNS start: {Host:dns-is-faked.golang}") - wantSub("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err: Coalesced:false}") - wantSub("Connecting to tcp " + addrStr) - wantSub("connected to tcp " + addrStr + " = ") - wantSub("Reused:false WasIdle:false IdleTime:0s") - wantSub("first response byte") + wantOnce("Getting conn for dns-is-faked.golang:" + port) + wantOnce("DNS start: {Host:dns-is-faked.golang}") + wantOnce("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err: Coalesced:false}") + wantOnce("got conn: {") + wantOnceOrMore("Connecting to tcp " + addrStr) + wantOnceOrMore("connected to tcp " + addrStr + " = ") + wantOnce("Reused:false WasIdle:false IdleTime:0s") + wantOnce("first response byte") if !h2 { - wantSub("PutIdleConn = ") + wantOnce("PutIdleConn = ") } - wantSub("Wait100Continue") - wantSub("Got100Continue") - wantSub("WroteRequest: {Err:}") + wantOnce("Wait100Continue") + wantOnce("Got100Continue") + wantOnce("WroteRequest: {Err:}") if strings.Contains(got, " to udp ") { t.Errorf("should not see UDP (DNS) connections") } diff --git a/src/net/main_plan9_test.go b/src/net/main_plan9_test.go index 94501cada9..2bc5be88be 100644 --- a/src/net/main_plan9_test.go +++ b/src/net/main_plan9_test.go @@ -8,6 +8,7 @@ func installTestHooks() {} func uninstallTestHooks() {} +// forceCloseSockets must be called only from TestMain. func forceCloseSockets() {} func enableSocketConnect() {} diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go index bfb4cd0065..0cc129f34d 100644 --- a/src/net/main_unix_test.go +++ b/src/net/main_unix_test.go @@ -45,6 +45,7 @@ func uninstallTestHooks() { } } +// forceCloseSockets must be called only from TestMain. func forceCloseSockets() { for s := range sw.Sockets() { closeFunc(s) diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go index b879717425..6ea318c2a5 100644 --- a/src/net/main_windows_test.go +++ b/src/net/main_windows_test.go @@ -32,6 +32,7 @@ func uninstallTestHooks() { acceptFunc = origAccept } +// forceCloseSockets must be called only from TestMain. func forceCloseSockets() { for s := range sw.Sockets() { closeFunc(s) diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go index 7991a579fd..ed26f2a4af 100644 --- a/src/net/timeout_test.go +++ b/src/net/timeout_test.go @@ -5,6 +5,7 @@ package net import ( + "context" "fmt" "internal/testenv" "io" @@ -41,19 +42,6 @@ func TestDialTimeout(t *testing.T) { defer func() { testHookDialChannel = origTestHookDialChannel }() defer sw.Set(socktest.FilterConnect, nil) - // Avoid tracking open-close jitterbugs between netFD and - // socket that leads to confusion of information inside - // socktest.Switch. - // It may happen when the Dial call bumps against TCP - // simultaneous open. See selfConnect in tcpsock_posix.go. - defer func() { - sw.Set(socktest.FilterClose, nil) - forceCloseSockets() - }() - sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) { - return nil, errTimedout - }) - for i, tt := range dialTimeoutTests { switch runtime.GOOS { case "plan9", "windows": @@ -177,10 +165,13 @@ func TestAcceptTimeout(t *testing.T) { } defer ln.Close() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() for i, tt := range acceptTimeoutTests { if tt.timeout < 0 { go func() { - c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + var d Dialer + c, err := d.DialContext(ctx, ln.Addr().Network(), ln.Addr().String()) if err != nil { t.Error(err) return diff --git a/src/os/exec.go b/src/os/exec.go index 239fd92888..bf3249864d 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -6,6 +6,7 @@ package os import ( "runtime" + "sync" "sync/atomic" "syscall" ) @@ -13,8 +14,9 @@ import ( // Process stores the information about a process created by StartProcess. type Process struct { Pid int - handle uintptr // handle is accessed atomically on Windows - isdone uint32 // process has been successfully waited on, non zero if true + handle uintptr // handle is accessed atomically on Windows + isdone uint32 // process has been successfully waited on, non zero if true + sigMu sync.RWMutex // avoid race between wait and signal } func newProcess(pid int, handle uintptr) *Process { diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go index ed97f85e22..c4999db57f 100644 --- a/src/os/exec_unix.go +++ b/src/os/exec_unix.go @@ -17,6 +17,22 @@ func (p *Process) wait() (ps *ProcessState, err error) { if p.Pid == -1 { return nil, syscall.EINVAL } + + // If we can block until Wait4 will succeed immediately, do so. + ready, err := p.blockUntilWaitable() + if err != nil { + return nil, err + } + if ready { + // Mark the process done now, before the call to Wait4, + // so that Process.signal will not send a signal. + p.setDone() + // Acquire a write lock on sigMu to wait for any + // active call to the signal method to complete. + p.sigMu.Lock() + p.sigMu.Unlock() + } + var status syscall.WaitStatus var rusage syscall.Rusage pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage) @@ -43,6 +59,8 @@ func (p *Process) signal(sig Signal) error { if p.Pid == 0 { return errors.New("os: process not initialized") } + p.sigMu.RLock() + defer p.sigMu.RUnlock() if p.done() { return errFinished } diff --git a/src/os/file.go b/src/os/file.go index 74d3c9f963..e546441497 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -46,6 +46,10 @@ func (f *File) Name() string { return f.name } // Stdin, Stdout, and Stderr are open Files pointing to the standard input, // standard output, and standard error file descriptors. +// +// Note that the Go runtime writes to standard error for panics and crashes; +// closing Stderr may cause those messages to go elsewhere, perhaps +// to a file opened later. var ( Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin") Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout") diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go index 56d786e501..406102c663 100644 --- a/src/os/signal/signal_test.go +++ b/src/os/signal/signal_test.go @@ -139,6 +139,19 @@ func testCancel(t *testing.T, ignore bool) { Reset(syscall.SIGWINCH, syscall.SIGHUP) } + // At this point we do not expect any further signals on c1. + // However, it is just barely possible that the initial SIGWINCH + // at the start of this function was delivered after we called + // Notify on c1. In that case the waitSig for SIGWINCH may have + // picked up that initial SIGWINCH, and the second SIGWINCH may + // then have been delivered on the channel. This sequence of events + // may have caused issue 15661. + // So, read any possible signal from the channel now. + select { + case <-c1: + default: + } + // Send this process a SIGWINCH. It should be ignored. syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) diff --git a/src/os/wait_unimp.go b/src/os/wait_unimp.go new file mode 100644 index 0000000000..7059e59ab2 --- /dev/null +++ b/src/os/wait_unimp.go @@ -0,0 +1,16 @@ +// Copyright 2016 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. + +// +build dragonfly nacl netbsd openbsd solaris + +package os + +// blockUntilWaitable attempts to block until a call to p.Wait will +// succeed immediately, and returns whether it has done so. +// It does not actually call p.Wait. +// This version is used on systems that do not implement waitid, +// or where we have not implemented it yet. +func (p *Process) blockUntilWaitable() (bool, error) { + return false, nil +} diff --git a/src/os/wait_wait6.go b/src/os/wait_wait6.go new file mode 100644 index 0000000000..2f27feda8d --- /dev/null +++ b/src/os/wait_wait6.go @@ -0,0 +1,45 @@ +// Copyright 2016 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. + +// +build freebsd + +package os + +import ( + "runtime" + "syscall" +) + +const _P_PID = 0 + +// blockUntilWaitable attempts to block until a call to p.Wait will +// succeed immediately, and returns whether it has done so. +// It does not actually call p.Wait. +func (p *Process) blockUntilWaitable() (bool, error) { + var errno syscall.Errno + if runtime.GOARCH == "386" { + // The arguments on 32-bit FreeBSD except ARM look + // like the following: + // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or + // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on MIPS or PowerPC + _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0) + } else { + _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0) + } + if errno != 0 { + // The wait6 system call is supported only on FreeBSD + // 9.3 and above, so it may return an ENOSYS error. + // Also the system call may return an ECHILD error + // when the child process has not finished the + // transformation using execve system call. + // In both cases, we just leave the care of child + // process to the following wait4 system call in + // Process.wait. + if errno == syscall.ENOSYS || errno == syscall.ECHILD { + return false, nil + } + return false, NewSyscallError("wait6", errno) + } + return true, nil +} diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go new file mode 100644 index 0000000000..5dbd7f9766 --- /dev/null +++ b/src/os/wait_waitid.go @@ -0,0 +1,34 @@ +// Copyright 2016 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. + +// +build darwin linux + +package os + +import ( + "runtime" + "syscall" + "unsafe" +) + +const _P_PID = 1 + +// blockUntilWaitable attempts to block until a call to p.Wait will +// succeed immediately, and returns whether it has done so. +// It does not actually call p.Wait. +func (p *Process) blockUntilWaitable() (bool, error) { + // The waitid system call expects a pointer to a siginfo_t, + // which is 128 bytes on all GNU/Linux systems. + // On Darwin, it requires greater than or equal to 64 bytes + // for darwin/{386,arm} and 104 bytes for darwin/amd64. + // We don't care about the values it returns. + var siginfo [128]byte + psig := &siginfo[0] + _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0) + runtime.KeepAlive(psig) + if e != 0 { + return false, NewSyscallError("waitid", e) + } + return true, nil +} diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go index 2adb0c7490..9fa68f578d 100644 --- a/src/path/filepath/match.go +++ b/src/path/filepath/match.go @@ -250,6 +250,11 @@ func Glob(pattern string) (matches []string, err error) { return glob(dir, file, nil) } + // Prevent infinite recursion. See issue 15879. + if dir == pattern { + return nil, ErrBadPattern + } + var m []string m, err = Glob(dir) if err != nil { diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go index 8dcfa5972e..6b068c778e 100644 --- a/src/path/filepath/match_test.go +++ b/src/path/filepath/match_test.go @@ -159,6 +159,12 @@ func TestGlobError(t *testing.T) { } } +func TestGlobUNC(t *testing.T) { + // Just make sure this runs without crashing for now. + // See issue 15879. + Glob(`\\?\C:\*`) +} + var globSymlinkTests = []struct { path, dest string brokenLink bool diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index f7cf46daec..97086b1852 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -3934,6 +3934,10 @@ func TestStructOf(t *testing.T) { if s != want { t.Errorf("constructed struct = %s, want %s", s, want) } + const stStr = `struct { S string "s"; X uint8 "x"; Y uint64; Z [3]uint16 }` + if got, want := st.String(), stStr; got != want { + t.Errorf("StructOf(fields).String()=%q, want %q", got, want) + } // check the size, alignment and field offsets stt := TypeOf(struct { diff --git a/src/reflect/type.go b/src/reflect/type.go index 1dff74df62..b70887fbba 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2351,6 +2351,9 @@ type structTypeFixed32 struct { // StructOf returns the struct type containing fields. // The Offset and Index fields are ignored and computed as they would be // by the compiler. +// +// StructOf currently does not generate wrapper methods for embedded fields. +// This limitation may be lifted in a future version. func StructOf(fields []StructField) Type { var ( hash = fnv1(0, []byte("struct {")...) @@ -2637,6 +2640,7 @@ func StructOf(fields []StructField) Type { } typ.str = resolveReflectName(newName(str, "", "", false)) + typ.tflag = 0 typ.hash = hash typ.size = size typ.align = typalign diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go index 463fcf1848..69f187e38a 100644 --- a/src/regexp/exec_test.go +++ b/src/regexp/exec_test.go @@ -658,57 +658,42 @@ func makeText(n int) []byte { return text } -func benchmark(b *testing.B, re string, n int) { - r := MustCompile(re) - t := makeText(n) - b.ResetTimer() - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - if r.Match(t) { - b.Fatal("match!") +func BenchmarkMatch(b *testing.B) { + for _, data := range benchData { + r := MustCompile(data.re) + for _, size := range benchSizes { + t := makeText(size.n) + b.Run(data.name+"/"+size.name, func(b *testing.B) { + b.SetBytes(int64(size.n)) + for i := 0; i < b.N; i++ { + if r.Match(t) { + b.Fatal("match!") + } + } + }) } } } -const ( - easy0 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ$" - easy0i = "(?i)ABCDEFGHIJklmnopqrstuvwxyz$" - easy1 = "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$" - medium = "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$" - hard = "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$" - hard1 = "ABCD|CDEF|EFGH|GHIJ|IJKL|KLMN|MNOP|OPQR|QRST|STUV|UVWX|WXYZ" -) +var benchData = []struct{ name, re string }{ + {"Easy0", "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"}, + {"Easy0i", "(?i)ABCDEFGHIJklmnopqrstuvwxyz$"}, + {"Easy1", "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"}, + {"Medium", "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"}, + {"Hard", "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"}, + {"Hard1", "ABCD|CDEF|EFGH|GHIJ|IJKL|KLMN|MNOP|OPQR|QRST|STUV|UVWX|WXYZ"}, +} -func BenchmarkMatchEasy0_32(b *testing.B) { benchmark(b, easy0, 32<<0) } -func BenchmarkMatchEasy0_1K(b *testing.B) { benchmark(b, easy0, 1<<10) } -func BenchmarkMatchEasy0_32K(b *testing.B) { benchmark(b, easy0, 32<<10) } -func BenchmarkMatchEasy0_1M(b *testing.B) { benchmark(b, easy0, 1<<20) } -func BenchmarkMatchEasy0_32M(b *testing.B) { benchmark(b, easy0, 32<<20) } -func BenchmarkMatchEasy0i_32(b *testing.B) { benchmark(b, easy0i, 32<<0) } -func BenchmarkMatchEasy0i_1K(b *testing.B) { benchmark(b, easy0i, 1<<10) } -func BenchmarkMatchEasy0i_32K(b *testing.B) { benchmark(b, easy0i, 32<<10) } -func BenchmarkMatchEasy0i_1M(b *testing.B) { benchmark(b, easy0i, 1<<20) } -func BenchmarkMatchEasy0i_32M(b *testing.B) { benchmark(b, easy0i, 32<<20) } -func BenchmarkMatchEasy1_32(b *testing.B) { benchmark(b, easy1, 32<<0) } -func BenchmarkMatchEasy1_1K(b *testing.B) { benchmark(b, easy1, 1<<10) } -func BenchmarkMatchEasy1_32K(b *testing.B) { benchmark(b, easy1, 32<<10) } -func BenchmarkMatchEasy1_1M(b *testing.B) { benchmark(b, easy1, 1<<20) } -func BenchmarkMatchEasy1_32M(b *testing.B) { benchmark(b, easy1, 32<<20) } -func BenchmarkMatchMedium_32(b *testing.B) { benchmark(b, medium, 32<<0) } -func BenchmarkMatchMedium_1K(b *testing.B) { benchmark(b, medium, 1<<10) } -func BenchmarkMatchMedium_32K(b *testing.B) { benchmark(b, medium, 32<<10) } -func BenchmarkMatchMedium_1M(b *testing.B) { benchmark(b, medium, 1<<20) } -func BenchmarkMatchMedium_32M(b *testing.B) { benchmark(b, medium, 32<<20) } -func BenchmarkMatchHard_32(b *testing.B) { benchmark(b, hard, 32<<0) } -func BenchmarkMatchHard_1K(b *testing.B) { benchmark(b, hard, 1<<10) } -func BenchmarkMatchHard_32K(b *testing.B) { benchmark(b, hard, 32<<10) } -func BenchmarkMatchHard_1M(b *testing.B) { benchmark(b, hard, 1<<20) } -func BenchmarkMatchHard_32M(b *testing.B) { benchmark(b, hard, 32<<20) } -func BenchmarkMatchHard1_32(b *testing.B) { benchmark(b, hard1, 32<<0) } -func BenchmarkMatchHard1_1K(b *testing.B) { benchmark(b, hard1, 1<<10) } -func BenchmarkMatchHard1_32K(b *testing.B) { benchmark(b, hard1, 32<<10) } -func BenchmarkMatchHard1_1M(b *testing.B) { benchmark(b, hard1, 1<<20) } -func BenchmarkMatchHard1_32M(b *testing.B) { benchmark(b, hard1, 32<<20) } +var benchSizes = []struct { + name string + n int +}{ + {"32", 32}, + {"1K", 1 << 10}, + {"32K", 32 << 10}, + {"1M", 1 << 20}, + {"32M", 32 << 20}, +} func TestLongest(t *testing.T) { re, err := Compile(`a(|b)`) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 530fbb0e27..ea11b2b2fb 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -174,7 +174,7 @@ DATA bad_proc_msg<>+0x00(SB)/8, $"This pro" DATA bad_proc_msg<>+0x08(SB)/8, $"gram can" DATA bad_proc_msg<>+0x10(SB)/8, $" only be" DATA bad_proc_msg<>+0x18(SB)/8, $" run on " -DATA bad_proc_msg<>+0x20(SB)/8, $"processe" +DATA bad_proc_msg<>+0x20(SB)/8, $"processo" DATA bad_proc_msg<>+0x28(SB)/8, $"rs with " DATA bad_proc_msg<>+0x30(SB)/8, $"MMX supp" DATA bad_proc_msg<>+0x38(SB)/4, $"ort." @@ -539,13 +539,20 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // void jmpdefer(fn, sp); // called from deferreturn. // 1. pop the caller -// 2. sub 5 bytes from the callers return +// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers +// return (when building for shared libraries, subtract 16 bytes -- 5 bytes +// for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the +// LEAL to load the offset into BX, and finally 5 for the call & displacement) // 3. jmp to the argument TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8 MOVL fv+0(FP), DX // fn MOVL argp+4(FP), BX // caller sp LEAL -4(BX), SP // caller sp after CALL +#ifdef GOBUILDMODE_shared + SUBL $16, (SP) // return to CALL again +#else SUBL $5, (SP) // return to CALL again +#endif MOVL 0(DX), BX JMP BX // but first run the deferred function diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index e50c443044..6103d54ba6 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -914,8 +914,9 @@ aes0to15: MOVQ $masks<>(SB), AX PAND (AX)(CX*8), X1 final1: - AESENC X0, X1 // scramble input, xor in seed - AESENC X1, X1 // scramble combo 2 times + PXOR X0, X1 // xor data with seed + AESENC X1, X1 // scramble combo 3 times + AESENC X1, X1 AESENC X1, X1 MOVQ X1, (DX) RET @@ -949,9 +950,13 @@ aes17to32: MOVOU (AX), X2 MOVOU -16(AX)(CX*1), X3 + // xor with seed + PXOR X0, X2 + PXOR X1, X3 + // scramble 3 times - AESENC X0, X2 - AESENC X1, X3 + AESENC X2, X2 + AESENC X3, X3 AESENC X2, X2 AESENC X3, X3 AESENC X2, X2 @@ -977,11 +982,16 @@ aes33to64: MOVOU 16(AX), X5 MOVOU -32(AX)(CX*1), X6 MOVOU -16(AX)(CX*1), X7 + + PXOR X0, X4 + PXOR X1, X5 + PXOR X2, X6 + PXOR X3, X7 - AESENC X0, X4 - AESENC X1, X5 - AESENC X2, X6 - AESENC X3, X7 + AESENC X4, X4 + AESENC X5, X5 + AESENC X6, X6 + AESENC X7, X7 AESENC X4, X4 AESENC X5, X5 @@ -1032,17 +1042,17 @@ aes65to128: MOVOU -32(AX)(CX*1), X14 MOVOU -16(AX)(CX*1), X15 - // scramble data, xor in seed - AESENC X0, X8 - AESENC X1, X9 - AESENC X2, X10 - AESENC X3, X11 - AESENC X4, X12 - AESENC X5, X13 - AESENC X6, X14 - AESENC X7, X15 + // xor with seed + PXOR X0, X8 + PXOR X1, X9 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X13 + PXOR X6, X14 + PXOR X7, X15 - // scramble twice + // scramble 3 times AESENC X8, X8 AESENC X9, X9 AESENC X10, X10 @@ -1051,7 +1061,16 @@ aes65to128: AESENC X13, X13 AESENC X14, X14 AESENC X15, X15 - + + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + AESENC X8, X8 AESENC X9, X9 AESENC X10, X10 @@ -1105,21 +1124,31 @@ aes129plus: MOVOU -32(AX)(CX*1), X14 MOVOU -16(AX)(CX*1), X15 - // scramble input once, xor in seed - AESENC X0, X8 - AESENC X1, X9 - AESENC X2, X10 - AESENC X3, X11 - AESENC X4, X12 - AESENC X5, X13 - AESENC X6, X14 - AESENC X7, X15 + // xor in seed + PXOR X0, X8 + PXOR X1, X9 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X13 + PXOR X6, X14 + PXOR X7, X15 // compute number of remaining 128-byte blocks DECQ CX SHRQ $7, CX aesloop: + // scramble state + AESENC X8, X8 + AESENC X9, X9 + AESENC X10, X10 + AESENC X11, X11 + AESENC X12, X12 + AESENC X13, X13 + AESENC X14, X14 + AESENC X15, X15 + // scramble state, xor in a block MOVOU (AX), X0 MOVOU 16(AX), X1 @@ -1138,7 +1167,11 @@ aesloop: AESENC X6, X14 AESENC X7, X15 - // scramble state + ADDQ $128, AX + DECQ CX + JNE aesloop + + // 3 more scrambles to finish AESENC X8, X8 AESENC X9, X9 AESENC X10, X10 @@ -1147,12 +1180,6 @@ aesloop: AESENC X13, X13 AESENC X14, X14 AESENC X15, X15 - - ADDQ $128, AX - DECQ CX - JNE aesloop - - // 2 more scrambles to finish AESENC X8, X8 AESENC X9, X9 AESENC X10, X10 @@ -1787,7 +1814,7 @@ partial_success9to15: JB loop9to15 JMP fail _16_or_more: - CMPQ AX, $17 + CMPQ AX, $16 JA _17_to_31 MOVOU (BP), X1 LEAQ -15(DI)(DX*1), DX @@ -1801,7 +1828,6 @@ loop16: CMPQ DI,DX JB loop16 JMP fail -//TODO: the code below is wrong. Fix it. See #15679. _17_to_31: LEAQ 1(DI)(DX*1), DX SUBQ AX, DX diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index df6bde61ee..f02297e8f0 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -626,7 +626,7 @@ havem: BL runtime·cgocallbackg(SB) // Restore g->sched (== m->curg->sched) from saved values. - MOVW 4(R13), R5 + MOVW 0(R13), R5 MOVW R5, (g_sched+gobuf_pc)(g) MOVW $12(R13), R4 MOVW R4, (g_sched+gobuf_sp)(g) diff --git a/src/runtime/cgo/gcc_context.c b/src/runtime/cgo/gcc_context.c index 81556cd464..1e6cf7ee12 100644 --- a/src/runtime/cgo/gcc_context.c +++ b/src/runtime/cgo/gcc_context.c @@ -7,21 +7,15 @@ #include "libcgo.h" -// The context function, used when tracing back C calls into Go. -void (*x_cgo_context_function)(struct context_arg*); - -// Sets the context function to call to record the traceback context -// when calling a Go function from C code. Called from runtime.SetCgoTraceback. -void x_cgo_set_context_function(void (*context)(struct context_arg*)) { - x_cgo_context_function = context; -} - // Releases the cgo traceback context. void _cgo_release_context(uintptr_t ctxt) { - if (ctxt != 0 && x_cgo_context_function != nil) { + void (*pfn)(struct context_arg*); + + pfn = _cgo_get_context_function(); + if (ctxt != 0 && pfn != nil) { struct context_arg arg; arg.Context = ctxt; - (*x_cgo_context_function)(&arg); + (*pfn)(&arg); } } diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c index c5b9476380..0bdf40a4ca 100644 --- a/src/runtime/cgo/gcc_libinit.c +++ b/src/runtime/cgo/gcc_libinit.c @@ -15,6 +15,9 @@ static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER; static int runtime_init_done; +// The context function, used when tracing back C calls into Go. +static void (*cgo_context_function)(struct context_arg*); + void x_cgo_sys_thread_create(void* (*func)(void*), void* arg) { pthread_t p; @@ -27,16 +30,30 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) { uintptr_t _cgo_wait_runtime_init_done() { + void (*pfn)(struct context_arg*); + pthread_mutex_lock(&runtime_init_mu); while (runtime_init_done == 0) { pthread_cond_wait(&runtime_init_cond, &runtime_init_mu); } + + // TODO(iant): For the case of a new C thread calling into Go, such + // as when using -buildmode=c-archive, we know that Go runtime + // initialization is complete but we do not know that all Go init + // functions have been run. We should not fetch cgo_context_function + // until they have been, because that is where a call to + // SetCgoTraceback is likely to occur. We are going to wait for Go + // initialization to be complete anyhow, later, by waiting for + // main_init_done to be closed in cgocallbackg1. We should wait here + // instead. See also issue #15943. + pfn = cgo_context_function; + pthread_mutex_unlock(&runtime_init_mu); - if (x_cgo_context_function != nil) { + if (pfn != nil) { struct context_arg arg; arg.Context = 0; - (*x_cgo_context_function)(&arg); + (*pfn)(&arg); return arg.Context; } return 0; @@ -49,3 +66,21 @@ x_cgo_notify_runtime_init_done(void* dummy) { pthread_cond_broadcast(&runtime_init_cond); pthread_mutex_unlock(&runtime_init_mu); } + +// Sets the context function to call to record the traceback context +// when calling a Go function from C code. Called from runtime.SetCgoTraceback. +void x_cgo_set_context_function(void (*context)(struct context_arg*)) { + pthread_mutex_lock(&runtime_init_mu); + cgo_context_function = context; + pthread_mutex_unlock(&runtime_init_mu); +} + +// Gets the context function. +void (*(_cgo_get_context_function(void)))(struct context_arg*) { + void (*ret)(struct context_arg*); + + pthread_mutex_lock(&runtime_init_mu); + ret = cgo_context_function; + pthread_mutex_unlock(&runtime_init_mu); + return ret; +} diff --git a/src/runtime/cgo/gcc_libinit_openbsd.c b/src/runtime/cgo/gcc_libinit_openbsd.c index 07dfcaf660..626bf8adca 100644 --- a/src/runtime/cgo/gcc_libinit_openbsd.c +++ b/src/runtime/cgo/gcc_libinit_openbsd.c @@ -6,6 +6,9 @@ #include #include "libcgo.h" +// The context function, used when tracing back C calls into Go. +static void (*cgo_context_function)(struct context_arg*); + void x_cgo_sys_thread_create(void* (*func)(void*), void* arg) { fprintf(stderr, "x_cgo_sys_thread_create not implemented"); @@ -14,12 +17,16 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) { uintptr_t _cgo_wait_runtime_init_done() { + void (*pfn)(struct context_arg*); + // TODO(spetrovic): implement this method. - if (x_cgo_context_function != nil) { + + pfn = _cgo_get_context_function(); + if (pfn != nil) { struct context_arg arg; arg.Context = 0; - (*x_cgo_context_function)(&arg); + (*pfn)(&arg); return arg.Context; } return 0; @@ -29,3 +36,15 @@ void x_cgo_notify_runtime_init_done(void* dummy) { // TODO(spetrovic): implement this method. } + +// Sets the context function to call to record the traceback context +// when calling a Go function from C code. Called from runtime.SetCgoTraceback. +void x_cgo_set_context_function(void (*context)(struct context_arg*)) { + // TODO(iant): Needs synchronization. + cgo_context_function = context; +} + +// Gets the context function. +void (*(_cgo_get_context_function(void)))(struct context_arg*) { + return cgo_context_function; +} diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c index f5c306d49a..0824e20ad8 100644 --- a/src/runtime/cgo/gcc_libinit_windows.c +++ b/src/runtime/cgo/gcc_libinit_windows.c @@ -70,15 +70,18 @@ _cgo_is_runtime_initialized() { uintptr_t _cgo_wait_runtime_init_done() { + void (*pfn)(struct context_arg*); + _cgo_maybe_run_preinit(); while (!_cgo_is_runtime_initialized()) { WaitForSingleObject(runtime_init_wait, INFINITE); } - if (x_cgo_context_function != nil) { + pfn = _cgo_get_context_function(); + if (pfn != nil) { struct context_arg arg; arg.Context = 0; - (*x_cgo_context_function)(&arg); + (*pfn)(&arg); return arg.Context; } return 0; @@ -98,3 +101,23 @@ x_cgo_notify_runtime_init_done(void* dummy) { } } +// The context function, used when tracing back C calls into Go. +static void (*cgo_context_function)(struct context_arg*); + +// Sets the context function to call to record the traceback context +// when calling a Go function from C code. Called from runtime.SetCgoTraceback. +void x_cgo_set_context_function(void (*context)(struct context_arg*)) { + EnterCriticalSection(&runtime_init_cs); + cgo_context_function = context; + LeaveCriticalSection(&runtime_init_cs); +} + +// Gets the context function. +void (*(_cgo_get_context_function(void)))(struct context_arg*) { + void (*ret)(struct context_arg*); + + EnterCriticalSection(&runtime_init_cs); + ret = cgo_context_function; + LeaveCriticalSection(&runtime_init_cs); + return ret; +} diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c index 50a7e6e078..0c34c66592 100644 --- a/src/runtime/cgo/gcc_linux_amd64.c +++ b/src/runtime/cgo/gcc_linux_amd64.c @@ -89,7 +89,9 @@ threadentry(void *v) ThreadStart ts; ts = *(ThreadStart*)v; + _cgo_tsan_acquire(); free(v); + _cgo_tsan_release(); /* * Set specific keys. diff --git a/src/runtime/cgo/gcc_mmap.c b/src/runtime/cgo/gcc_mmap.c index 14efa5489d..088bcb291e 100644 --- a/src/runtime/cgo/gcc_mmap.c +++ b/src/runtime/cgo/gcc_mmap.c @@ -8,11 +8,15 @@ #include #include +#include "libcgo.h" + void * x_cgo_mmap(void *addr, uintptr_t length, int32_t prot, int32_t flags, int32_t fd, uint32_t offset) { void *p; + _cgo_tsan_acquire(); p = mmap(addr, length, prot, flags, fd, offset); + _cgo_tsan_release(); if (p == MAP_FAILED) { /* This is what the Go code expects on failure. */ p = (void *) (uintptr_t) errno; diff --git a/src/runtime/cgo/gcc_s390x.S b/src/runtime/cgo/gcc_s390x.S index 6b163d0d21..022f82d93e 100644 --- a/src/runtime/cgo/gcc_s390x.S +++ b/src/runtime/cgo/gcc_s390x.S @@ -21,9 +21,12 @@ crosscall_s390x: stdy %f4, 144(%r15) stdy %f6, 152(%r15) - /* assumes this call does not clobber r2 or r15 */ + /* set r0 to 0 */ xgr %r0, %r0 + /* restore g pointer */ + lgr %r13, %r3 + /* grow stack 8 bytes and call fn */ agfi %r15, -8 basr %r14, %r2 diff --git a/src/runtime/cgo/gcc_traceback.c b/src/runtime/cgo/gcc_traceback.c index 01f9bb128b..667ea4c0cf 100644 --- a/src/runtime/cgo/gcc_traceback.c +++ b/src/runtime/cgo/gcc_traceback.c @@ -9,6 +9,7 @@ struct cgoTracebackArg { uintptr_t Context; + uintptr_t SigContext; uintptr_t* Buf; uintptr_t Max; }; @@ -22,6 +23,7 @@ x_cgo_callers(uintptr_t sig, void *info, void *context, void (*cgoTraceback)(str struct cgoTracebackArg arg; arg.Context = 0; + arg.SigContext = (uintptr_t)(context); arg.Buf = cgoCallers; arg.Max = 32; // must match len(runtime.cgoCallers) (*cgoTraceback)(&arg); diff --git a/src/runtime/cgo/gcc_util.c b/src/runtime/cgo/gcc_util.c index 4111fe1195..99af021331 100644 --- a/src/runtime/cgo/gcc_util.c +++ b/src/runtime/cgo/gcc_util.c @@ -11,7 +11,9 @@ x_cgo_thread_start(ThreadStart *arg) ThreadStart *ts; /* Make our own copy that can persist after we return. */ + _cgo_tsan_acquire(); ts = malloc(sizeof *ts); + _cgo_tsan_release(); if(ts == nil) { fprintf(stderr, "runtime/cgo: out of memory in thread_start\n"); abort(); diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h index 6a484ad4a0..01f9e72174 100644 --- a/src/runtime/cgo/libcgo.h +++ b/src/runtime/cgo/libcgo.h @@ -93,4 +93,43 @@ void darwin_arm_init_mach_exception_handler(void); struct context_arg { uintptr_t Context; }; -extern void (*x_cgo_context_function)(struct context_arg*); +extern void (*(_cgo_get_context_function(void)))(struct context_arg*); + +/* + * TSAN support. This is only useful when building with + * CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install + */ +#undef CGO_TSAN +#if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define CGO_TSAN +# endif +#elif defined(__SANITIZE_THREAD__) +# define CGO_TSAN +#endif + +#ifdef CGO_TSAN + +// These must match the definitions in yesTsanProlog in cmd/cgo/out.go. + +long long _cgo_sync __attribute__ ((common)); + +extern void __tsan_acquire(void*); +extern void __tsan_release(void*); + +__attribute__ ((unused)) +static void _cgo_tsan_acquire() { + __tsan_acquire(&_cgo_sync); +} + +__attribute__ ((unused)) +static void _cgo_tsan_release() { + __tsan_release(&_cgo_sync); +} + +#else // !defined(CGO_TSAN) + +#define _cgo_tsan_acquire() +#define _cgo_tsan_release() + +#endif // !defined(CGO_TSAN) diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go index 4b9dfafb90..53082006d0 100644 --- a/src/runtime/cpuprof.go +++ b/src/runtime/cpuprof.go @@ -149,7 +149,7 @@ func SetCPUProfileRate(hz int) { cpuprof.on = true // pprof binary header format. - // http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117 + // https://github.com/gperftools/gperftools/blob/master/src/profiledata.cc#L119 p := &cpuprof.log[0] p[0] = 0 // count for header p[1] = 3 // depth for header @@ -193,7 +193,20 @@ func SetCPUProfileRate(hz int) { // and cannot allocate memory or acquire locks that might be // held at the time of the signal, nor can it use substantial amounts // of stack. It is allowed to call evict. +//go:nowritebarrierrec func (p *cpuProfile) add(pc []uintptr) { + p.addWithFlushlog(pc, p.flushlog) +} + +// addWithFlushlog implements add and addNonGo. +// It is called from signal handlers and other limited environments +// and cannot allocate memory or acquire locks that might be +// held at the time of the signal, nor can it use substantial amounts +// of stack. It may be called by a signal handler with no g or m. +// It is allowed to call evict, passing the flushlog parameter. +//go:nosplit +//go:nowritebarrierrec +func (p *cpuProfile) addWithFlushlog(pc []uintptr, flushlog func() bool) { if len(pc) > maxCPUProfStack { pc = pc[:maxCPUProfStack] } @@ -231,7 +244,7 @@ Assoc: } } if e.count > 0 { - if !p.evict(e) { + if !p.evict(e, flushlog) { // Could not evict entry. Record lost stack. p.lost++ return @@ -248,15 +261,17 @@ Assoc: // evict copies the given entry's data into the log, so that // the entry can be reused. evict is called from add, which // is called from the profiling signal handler, so it must not -// allocate memory or block. It is safe to call flushlog. -// evict returns true if the entry was copied to the log, -// false if there was no room available. -func (p *cpuProfile) evict(e *cpuprofEntry) bool { +// allocate memory or block, and it may be called with no g or m. +// It is safe to call flushlog. evict returns true if the entry was +// copied to the log, false if there was no room available. +//go:nosplit +//go:nowritebarrierrec +func (p *cpuProfile) evict(e *cpuprofEntry, flushlog func() bool) bool { d := e.depth nslot := d + 2 log := &p.log[p.toggle] if p.nlog+nslot > len(log) { - if !p.flushlog() { + if !flushlog() { return false } log = &p.log[p.toggle] @@ -278,6 +293,7 @@ func (p *cpuProfile) evict(e *cpuprofEntry) bool { // flushlog is called from evict, called from add, called from the signal handler, // so it cannot allocate memory or block. It can try to swap logs with // the writing goroutine, as explained in the comment at the top of this file. +//go:nowritebarrierrec func (p *cpuProfile) flushlog() bool { if !atomic.Cas(&p.handoff, 0, uint32(p.nlog)) { return false @@ -299,6 +315,16 @@ func (p *cpuProfile) flushlog() bool { return true } +// addNonGo is like add, but runs on a non-Go thread. +// It can't do anything that might need a g or an m. +// With this entry point, we don't try to flush the log when evicting an +// old entry. Instead, we just drop the stack trace if we're out of space. +//go:nosplit +//go:nowritebarrierrec +func (p *cpuProfile) addNonGo(pc []uintptr) { + p.addWithFlushlog(pc, func() bool { return false }) +} + // getprofile blocks until the next block of profiling data is available // and returns it as a []byte. It is called from the writing goroutine. func (p *cpuProfile) getprofile() []byte { @@ -366,7 +392,7 @@ Flush: b := &p.hash[i] for j := range b.entry { e := &b.entry[j] - if e.count > 0 && !p.evict(e) { + if e.count > 0 && !p.evict(e, p.flushlog) { // Filled the log. Stop the loop and return what we've got. break Flush } diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 5d1cc77c98..9e1811aa16 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -234,18 +234,18 @@ func TestCgoTracebackContext(t *testing.T) { } } -func TestCgoPprof(t *testing.T) { +func testCgoPprof(t *testing.T, buildArg, runArg string) { if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) } testenv.MustHaveGoRun(t) - exe, err := buildTestProg(t, "testprogcgo") + exe, err := buildTestProg(t, "testprogcgo", buildArg) if err != nil { t.Fatal(err) } - got, err := testEnv(exec.Command(exe, "CgoPprof")).CombinedOutput() + got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput() if err != nil { t.Fatal(err) } @@ -253,13 +253,24 @@ func TestCgoPprof(t *testing.T) { defer os.Remove(fn) top, err := exec.Command("go", "tool", "pprof", "-top", "-nodecount=1", exe, fn).CombinedOutput() + t.Logf("%s", top) if err != nil { t.Fatal(err) } - t.Logf("%s", top) - if !bytes.Contains(top, []byte("cpuHog")) { t.Error("missing cpuHog in pprof output") } } + +func TestCgoPprof(t *testing.T) { + testCgoPprof(t, "", "CgoPprof") +} + +func TestCgoPprofPIE(t *testing.T) { + testCgoPprof(t, "-ldflags=-extldflags=-pie", "CgoPprof") +} + +func TestCgoPprofThread(t *testing.T) { + testCgoPprof(t, "", "CgoPprofThread") +} diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 2941b8e8f8..ec740990dc 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -69,7 +69,7 @@ func runTestProg(t *testing.T, binary, name string) string { return string(got) } -func buildTestProg(t *testing.T, binary string) (string, error) { +func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) { checkStaleRuntime(t) testprog.Lock() @@ -86,23 +86,27 @@ func buildTestProg(t *testing.T, binary string) (string, error) { if testprog.target == nil { testprog.target = make(map[string]buildexe) } - target, ok := testprog.target[binary] + name := binary + if len(flags) > 0 { + name += "_" + strings.Join(flags, "_") + } + target, ok := testprog.target[name] if ok { return target.exe, target.err } - exe := filepath.Join(testprog.dir, binary+".exe") - cmd := exec.Command("go", "build", "-o", exe) + exe := filepath.Join(testprog.dir, name+".exe") + cmd := exec.Command("go", append([]string{"build", "-o", exe}, flags...)...) cmd.Dir = "testdata/" + binary out, err := testEnv(cmd).CombinedOutput() if err != nil { exe = "" - target.err = fmt.Errorf("building %s: %v\n%s", binary, err, out) - testprog.target[binary] = target + target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out) + testprog.target[name] = target return "", target.err } target.exe = exe - testprog.target[binary] = target + testprog.target[name] = target return exe, nil } diff --git a/src/runtime/debug/heapdump_test.go b/src/runtime/debug/heapdump_test.go index 5761c015b8..7d5b950895 100644 --- a/src/runtime/debug/heapdump_test.go +++ b/src/runtime/debug/heapdump_test.go @@ -38,7 +38,7 @@ type Obj struct { } func objfin(x *Obj) { - println("finalized", x) + //println("finalized", x) } func TestWriteHeapDumpFinalizers(t *testing.T) { diff --git a/src/runtime/extern.go b/src/runtime/extern.go index 1df8691cfc..441dcd9702 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -82,6 +82,21 @@ It is a comma-separated list of name=val pairs setting these named variables: If the line ends with "(forced)", this GC was forced by a runtime.GC() call and all phases are STW. + Setting gctrace to any value > 0 also causes the garbage collector + to emit a summary when memory is released back to the system. + This process of returning memory to the system is called scavenging. + The format of this summary is subject to change. + Currently it is: + scvg#: # MB released printed only if non-zero + scvg#: inuse: # idle: # sys: # released: # consumed: # (MB) + where the fields are as follows: + scvg# the scavenge cycle number, incremented at each scavenge + inuse: # MB used or partially used spans + idle: # MB spans pending scavenging + sys: # MB mapped from the system + released: # MB released to the system + consumed: # MB allocated from the system + memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate. When set to 0 memory profiling is disabled. Refer to the description of MemProfileRate for the default value. diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go index 96ed68247e..3108b3bf59 100644 --- a/src/runtime/hash_test.go +++ b/src/runtime/hash_test.go @@ -681,3 +681,23 @@ func BenchmarkUnalignedLoad(b *testing.B) { } sink = s } + +func TestCollisions(t *testing.T) { + for i := 0; i < 16; i++ { + for j := 0; j < 16; j++ { + if j == i { + continue + } + var a [16]byte + m := make(map[uint16]struct{}, 1<<16) + for n := 0; n < 1<<16; n++ { + a[i] = byte(n) + a[j] = byte(n >> 8) + m[uint16(BytesHash(a[:], 0))] = struct{}{} + } + if len(m) <= 1<<15 { + t.Errorf("too many collisions i=%d j=%d outputs=%d out of 65536\n", i, j, len(m)) + } + } + } +} diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index 728c3dc24a..b05c925ad1 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -13,6 +13,7 @@ import ( "bytes" "fmt" "io" + "os" "runtime" "sort" "strings" @@ -620,6 +621,42 @@ func profileWriter(w io.Writer) { } w.Write(data) } + + // We are emitting the legacy profiling format, which permits + // a memory map following the CPU samples. The memory map is + // simply a copy of the GNU/Linux /proc/self/maps file. The + // profiler uses the memory map to map PC values in shared + // libraries to a shared library in the filesystem, in order + // to report the correct function and, if the shared library + // has debug info, file/line. This is particularly useful for + // PIE (position independent executables) as on ELF systems a + // PIE is simply an executable shared library. + // + // Because the profiling format expects the memory map in + // GNU/Linux format, we only do this on GNU/Linux for now. To + // add support for profiling PIE on other ELF-based systems, + // it may be necessary to map the system-specific mapping + // information to the GNU/Linux format. For a reasonably + // portable C++ version, see the FillProcSelfMaps function in + // https://github.com/gperftools/gperftools/blob/master/src/base/sysinfo.cc + // + // The code that parses this mapping for the pprof tool is + // ParseMemoryMap in cmd/internal/pprof/legacy_profile.go, but + // don't change that code, as similar code exists in other + // (non-Go) pprof readers. Change this code so that that code works. + // + // We ignore errors reading or copying the memory map; the + // profile is likely usable without it, and we have no good way + // to report errors. + if runtime.GOOS == "linux" { + f, err := os.Open("/proc/self/maps") + if err == nil { + io.WriteString(w, "\nMAPPED_LIBRARIES:\n") + io.Copy(w, f) + f.Close() + } + } + cpu.done <- true } diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 3852d93e72..a6f5eda458 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -86,10 +86,14 @@ func TestCPUProfileMultithreaded(t *testing.T) { }) } -func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) { +func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) { // Convert []byte to []uintptr. - l := len(bytes) / int(unsafe.Sizeof(uintptr(0))) - val := *(*[]uintptr)(unsafe.Pointer(&bytes)) + l := len(valBytes) + if i := bytes.Index(valBytes, []byte("\nMAPPED_LIBRARIES:\n")); i >= 0 { + l = i + } + l /= int(unsafe.Sizeof(uintptr(0))) + val := *(*[]uintptr)(unsafe.Pointer(&valBytes)) val = val[:l] // 5 for the header, 3 for the trailer. diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 727c991a57..a0fddd0052 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3000,6 +3000,8 @@ func _ExternalCode() { _ExternalCode() } func _GC() { _GC() } // Called if we receive a SIGPROF signal. +// Called by the signal handler, may run during STW. +//go:nowritebarrierrec func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { if prof.hz == 0 { return @@ -3159,6 +3161,36 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { mp.mallocing-- } +// If the signal handler receives a SIGPROF signal on a non-Go thread, +// it tries to collect a traceback into sigprofCallers. +// sigprofCallersUse is set to non-zero while sigprofCallers holds a traceback. +var sigprofCallers cgoCallers +var sigprofCallersUse uint32 + +// Called if we receive a SIGPROF signal on a non-Go thread. +// When this is called, sigprofCallersUse will be non-zero. +// g is nil, and what we can do is very limited. +//go:nosplit +//go:nowritebarrierrec +func sigprofNonGo() { + if prof.hz != 0 { + n := 0 + for n < len(sigprofCallers) && sigprofCallers[n] != 0 { + n++ + } + + // Simple cas-lock to coordinate with setcpuprofilerate. + if atomic.Cas(&prof.lock, 0, 1) { + if prof.hz != 0 { + cpuprof.addNonGo(sigprofCallers[:n]) + } + atomic.Store(&prof.lock, 0) + } + } + + atomic.Store(&sigprofCallersUse, 0) +} + // Reports whether a function will set the SP // to an absolute value. Important that // we don't traceback when these are at the bottom diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py index e57fa00e1a..5c9b2a08e8 100644 --- a/src/runtime/runtime-gdb.py +++ b/src/runtime/runtime-gdb.py @@ -448,15 +448,15 @@ class GoroutineCmd(gdb.Command): except gdb.error: pc = int(str(pc).split(None, 1)[0], 16) save_frame = gdb.selected_frame() - gdb.parse_and_eval('$save_pc = $pc') gdb.parse_and_eval('$save_sp = $sp') - gdb.parse_and_eval('$pc = {0}'.format(str(pc))) + gdb.parse_and_eval('$save_pc = $pc') gdb.parse_and_eval('$sp = {0}'.format(str(sp))) + gdb.parse_and_eval('$pc = {0}'.format(str(pc))) try: gdb.execute(cmd) finally: - gdb.parse_and_eval('$pc = $save_pc') gdb.parse_and_eval('$sp = $save_sp') + gdb.parse_and_eval('$pc = $save_pc') save_frame.select() diff --git a/src/runtime/signal_sigtramp.go b/src/runtime/signal_sigtramp.go index 18fc375e24..3e0b104578 100644 --- a/src/runtime/signal_sigtramp.go +++ b/src/runtime/signal_sigtramp.go @@ -18,6 +18,14 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) { } g := getg() if g == nil { + if sig == _SIGPROF { + // Ignore profiling signals that arrive on + // non-Go threads. On some systems they will + // be handled directly by the signal handler, + // by calling sigprofNonGo, in which case we won't + // get here anyhow. + return + } badsignal(uintptr(sig), &sigctxt{info, ctx}) return } diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s index 031e412673..8a8f3cce8b 100644 --- a/src/runtime/sys_linux_amd64.s +++ b/src/runtime/sys_linux_amd64.s @@ -253,7 +253,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 get_tls(CX) MOVQ g(CX),AX TESTQ AX, AX - JZ sigtramp // g == nil + JZ sigtrampnog // g == nil MOVQ g_m(AX), AX TESTQ AX, AX JZ sigtramp // g.m == nil @@ -276,8 +276,8 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 // Jump to a function in runtime/cgo. // That function, written in C, will call the user's traceback // function with proper unwind info, and will then call back here. - // The first three arguments are already in registers. - // Set the last three arguments now. + // The first three arguments, and the fifth, are already in registers. + // Set the two remaining arguments now. MOVQ runtime·cgoTraceback(SB), CX MOVQ $runtime·sigtramp(SB), R9 MOVQ _cgo_callers(SB), AX @@ -286,6 +286,30 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 sigtramp: JMP runtime·sigtramp(SB) +sigtrampnog: + // Signal arrived on a non-Go thread. If this is SIGPROF, get a + // stack trace. + CMPL DI, $27 // 27 == SIGPROF + JNZ sigtramp + + // Lock sigprofCallersUse. + MOVL $0, AX + MOVL $1, CX + MOVQ $runtime·sigprofCallersUse(SB), BX + LOCK + CMPXCHGL CX, 0(BX) + JNZ sigtramp // Skip stack trace if already locked. + + // Jump to the traceback function in runtime/cgo. + // It will call back to sigprofNonGo, which will ignore the + // arguments passed in registers. + // First three arguments to traceback function are in registers already. + MOVQ runtime·cgoTraceback(SB), CX + MOVQ $runtime·sigprofCallers(SB), R8 + MOVQ $runtime·sigprofNonGo(SB), R9 + MOVQ _cgo_callers(SB), AX + JMP AX + // For cgo unwinding to work, this function must look precisely like // the one in glibc. The glibc source code is: // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86_64/sigaction.c diff --git a/src/runtime/testdata/testprogcgo/pprof.go b/src/runtime/testdata/testprogcgo/pprof.go index 04ac4fe92e..cb30ec5b25 100644 --- a/src/runtime/testdata/testprogcgo/pprof.go +++ b/src/runtime/testdata/testprogcgo/pprof.go @@ -30,6 +30,7 @@ static int cpuHogCount; struct cgoTracebackArg { uintptr_t context; + uintptr_t sigContext; uintptr_t* buf; uintptr_t max; }; diff --git a/src/runtime/testdata/testprogcgo/threadpprof.go b/src/runtime/testdata/testprogcgo/threadpprof.go new file mode 100644 index 0000000000..fdeee6910d --- /dev/null +++ b/src/runtime/testdata/testprogcgo/threadpprof.go @@ -0,0 +1,112 @@ +// Copyright 2016 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. + +// +build !plan9,!windows + +package main + +// Run a slow C function saving a CPU profile. + +/* +#include +#include +#include + +int threadSalt1; +int threadSalt2; + +void cpuHogThread() { + int foo = threadSalt1; + int i; + + for (i = 0; i < 100000; i++) { + if (foo > 0) { + foo *= foo; + } else { + foo *= foo + 1; + } + } + threadSalt2 = foo; +} + +static int cpuHogThreadCount; + +struct cgoTracebackArg { + uintptr_t context; + uintptr_t sigContext; + uintptr_t* buf; + uintptr_t max; +}; + +static void *pprofThread(void* p) { + time_t start; + + (void)p; + start = time(NULL); + while (__sync_add_and_fetch(&cpuHogThreadCount, 0) < 2 && time(NULL) - start < 2) { + cpuHogThread(); + } +} + + +// pprofCgoThreadTraceback is passed to runtime.SetCgoTraceback. +// For testing purposes it pretends that all CPU hits in C code are in cpuHog. +void pprofCgoThreadTraceback(void* parg) { + struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg); + arg->buf[0] = (uintptr_t)(cpuHogThread) + 0x10; + arg->buf[1] = 0; + __sync_add_and_fetch(&cpuHogThreadCount, 1); +} + +// getCPUHogThreadCount fetches the number of times we've seen cpuHogThread +// in the traceback. +int getCPUHogThreadCount() { + return __sync_add_and_fetch(&cpuHogThreadCount, 0); +} +*/ +import "C" + +import ( + "fmt" + "io/ioutil" + "os" + "runtime" + "runtime/pprof" + "time" + "unsafe" +) + +func init() { + register("CgoPprofThread", CgoPprofThread) +} + +func CgoPprofThread() { + runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoThreadTraceback), nil, nil) + + f, err := ioutil.TempFile("", "prof") + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + + if err := pprof.StartCPUProfile(f); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + + t0 := time.Now() + for C.getCPUHogThreadCount() < 2 && time.Since(t0) < time.Second { + time.Sleep(100 * time.Millisecond) + } + + pprof.StopCPUProfile() + + name := f.Name() + if err := f.Close(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + + fmt.Println(name) +} diff --git a/src/runtime/testdata/testprogcgo/traceback.go b/src/runtime/testdata/testprogcgo/traceback.go index 38cdef537a..e8b0a04556 100644 --- a/src/runtime/testdata/testprogcgo/traceback.go +++ b/src/runtime/testdata/testprogcgo/traceback.go @@ -30,6 +30,7 @@ static int f1() { struct cgoTracebackArg { uintptr_t context; + uintptr_t sigContext; uintptr_t* buf; uintptr_t max; }; diff --git a/src/runtime/testdata/testprogcgo/tracebackctxt_c.c b/src/runtime/testdata/testprogcgo/tracebackctxt_c.c index bbac39658e..900cada0d3 100644 --- a/src/runtime/testdata/testprogcgo/tracebackctxt_c.c +++ b/src/runtime/testdata/testprogcgo/tracebackctxt_c.c @@ -26,6 +26,7 @@ struct cgoContextArg { struct cgoTracebackArg { uintptr_t context; + uintptr_t sigContext; uintptr_t* buf; uintptr_t max; }; diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 279fb52fc0..80a54407b3 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -844,8 +844,8 @@ func isSystemGoroutine(gp *g) bool { // If the Context field is not 0, then it is a value returned by a // previous call to the context function. This case is called when the // context is no longer needed; that is, when the Go code is returning -// to its C code caller. This permits permits the context function to -// release any associated resources. +// to its C code caller. This permits the context function to release +// any associated resources. // // While it would be correct for the context function to record a // complete a stack trace whenever it is called, and simply copy that @@ -858,15 +858,17 @@ func isSystemGoroutine(gp *g) bool { // pointer to a struct: // // struct { -// Context uintptr -// Buf *uintptr -// Max uintptr +// Context uintptr +// SigContext uintptr +// Buf *uintptr +// Max uintptr // } // // In C syntax, this struct will be // // struct { // uintptr_t Context; +// uintptr_t SigContext; // uintptr_t* Buf; // uintptr_t Max; // }; @@ -887,6 +889,13 @@ func isSystemGoroutine(gp *g) bool { // result, if possible, the first time this is called for a specific // context value. // +// If the traceback function is called from a signal handler on a Unix +// system, SigContext will be the signal context argument passed to +// the signal handler (a C ucontext_t* cast to uintptr_t). This may be +// used to start tracing at the point where the signal occurred. If +// the traceback function is not called from a signal handler, +// SigContext will be zero. +// // Buf is where the traceback information should be stored. It should // be PC values, such that Buf[0] is the PC of the caller, Buf[1] is // the PC of that function's caller, and so on. Max is the maximum @@ -953,12 +962,21 @@ func isSystemGoroutine(gp *g) bool { // traceback function will only be called with the context field set // to zero. If the context function is nil, then calls from Go to C // to Go will not show a traceback for the C portion of the call stack. +// +// SetCgoTraceback should be called only once, ideally from an init function. func SetCgoTraceback(version int, traceback, context, symbolizer unsafe.Pointer) { if version != 0 { panic("unsupported version") } + if cgoTraceback != nil && cgoTraceback != traceback || + cgoContext != nil && cgoContext != context || + cgoSymbolizer != nil && cgoSymbolizer != symbolizer { + panic("call SetCgoTraceback only once") + } + cgoTraceback = traceback + cgoContext = context cgoSymbolizer = symbolizer // The context function is called when a C function calls a Go @@ -969,13 +987,15 @@ func SetCgoTraceback(version int, traceback, context, symbolizer unsafe.Pointer) } var cgoTraceback unsafe.Pointer +var cgoContext unsafe.Pointer var cgoSymbolizer unsafe.Pointer // cgoTracebackArg is the type passed to cgoTraceback. type cgoTracebackArg struct { - context uintptr - buf *uintptr - max uintptr + context uintptr + sigContext uintptr + buf *uintptr + max uintptr } // cgoContextArg is the type passed to the context function. diff --git a/src/strconv/ftoa_test.go b/src/strconv/ftoa_test.go index 0b9f0feafa..1d25242ff3 100644 --- a/src/strconv/ftoa_test.go +++ b/src/strconv/ftoa_test.go @@ -183,59 +183,50 @@ func TestFtoaRandom(t *testing.T) { } } -func BenchmarkFormatFloatDecimal(b *testing.B) { - for i := 0; i < b.N; i++ { - FormatFloat(33909, 'g', -1, 64) - } +var ftoaBenches = []struct { + name string + float float64 + fmt byte + prec int + bitSize int +}{ + {"Decimal", 33909, 'g', -1, 64}, + {"Float", 339.7784, 'g', -1, 64}, + {"Exp", -5.09e75, 'g', -1, 64}, + {"NegExp", -5.11e-95, 'g', -1, 64}, + + {"Big", 123456789123456789123456789, 'g', -1, 64}, + {"BinaryExp", -1, 'b', -1, 64}, + + {"32Integer", 33909, 'g', -1, 32}, + {"32ExactFraction", 3.375, 'g', -1, 32}, + {"32Point", 339.7784, 'g', -1, 32}, + {"32Exp", -5.09e25, 'g', -1, 32}, + {"32NegExp", -5.11e-25, 'g', -1, 32}, + + {"64Fixed1", 123456, 'e', 3, 64}, + {"64Fixed2", 123.456, 'e', 3, 64}, + {"64Fixed3", 1.23456e+78, 'e', 3, 64}, + {"64Fixed4", 1.23456e-78, 'e', 3, 64}, } func BenchmarkFormatFloat(b *testing.B) { - for i := 0; i < b.N; i++ { - FormatFloat(339.7784, 'g', -1, 64) + for _, c := range ftoaBenches { + b.Run(c.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + FormatFloat(c.float, c.fmt, c.prec, c.bitSize) + } + }) } } -func BenchmarkFormatFloatExp(b *testing.B) { - for i := 0; i < b.N; i++ { - FormatFloat(-5.09e75, 'g', -1, 64) - } -} - -func BenchmarkFormatFloatNegExp(b *testing.B) { - for i := 0; i < b.N; i++ { - FormatFloat(-5.11e-95, 'g', -1, 64) - } -} - -func BenchmarkFormatFloatBig(b *testing.B) { - for i := 0; i < b.N; i++ { - FormatFloat(123456789123456789123456789, 'g', -1, 64) - } -} - -func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) { +func BenchmarkAppendFloat(b *testing.B) { dst := make([]byte, 30) - for i := 0; i < b.N; i++ { - AppendFloat(dst[:0], f, fmt, prec, bitSize) + for _, c := range ftoaBenches { + b.Run(c.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + AppendFloat(dst[:0], c.float, c.fmt, c.prec, c.bitSize) + } + }) } } - -func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) } -func BenchmarkAppendFloat(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) } -func BenchmarkAppendFloatExp(b *testing.B) { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) } -func BenchmarkAppendFloatNegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) } -func BenchmarkAppendFloatBig(b *testing.B) { - benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64) -} -func BenchmarkAppendFloatBinaryExp(b *testing.B) { benchmarkAppendFloat(b, -1, 'b', -1, 64) } - -func BenchmarkAppendFloat32Integer(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 32) } -func BenchmarkAppendFloat32ExactFraction(b *testing.B) { benchmarkAppendFloat(b, 3.375, 'g', -1, 32) } -func BenchmarkAppendFloat32Point(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 32) } -func BenchmarkAppendFloat32Exp(b *testing.B) { benchmarkAppendFloat(b, -5.09e25, 'g', -1, 32) } -func BenchmarkAppendFloat32NegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-25, 'g', -1, 32) } - -func BenchmarkAppendFloat64Fixed1(b *testing.B) { benchmarkAppendFloat(b, 123456, 'e', 3, 64) } -func BenchmarkAppendFloat64Fixed2(b *testing.B) { benchmarkAppendFloat(b, 123.456, 'e', 3, 64) } -func BenchmarkAppendFloat64Fixed3(b *testing.B) { benchmarkAppendFloat(b, 1.23456e+78, 'e', 3, 64) } -func BenchmarkAppendFloat64Fixed4(b *testing.B) { benchmarkAppendFloat(b, 1.23456e-78, 'e', 3, 64) } diff --git a/src/strings/strings_amd64.go b/src/strings/strings_amd64.go index 91b29ce358..55bf2d2f6f 100644 --- a/src/strings/strings_amd64.go +++ b/src/strings/strings_amd64.go @@ -7,7 +7,7 @@ package strings // indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s. // indexShortStr requires 2 <= len(c) <= shortStringLen func indexShortStr(s, c string) int // ../runtime/asm_$GOARCH.s -const shortStringLen = 16 // TODO: restore to 31 when #15679 is fixed +const shortStringLen = 31 // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s. func Index(s, sep string) int { diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index 6bd6fb5443..fcef761da7 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -190,6 +190,43 @@ func TestLastIndexByte(t *testing.T) { } } +func simpleIndex(s, sep string) int { + n := len(sep) + for i := n; i <= len(s); i++ { + if s[i-n:i] == sep { + return i - n + } + } + return -1 +} + +func TestIndexRandom(t *testing.T) { + const chars = "abcdefghijklmnopqrstuvwxyz0123456789" + for times := 0; times < 10; times++ { + for strLen := 5 + rand.Intn(5); strLen < 140; strLen += 10 { // Arbitrary + s1 := make([]byte, strLen) + for i := range s1 { + s1[i] = chars[rand.Intn(len(chars))] + } + s := string(s1) + for i := 0; i < 50; i++ { + begin := rand.Intn(len(s) + 1) + end := begin + rand.Intn(len(s)+1-begin) + sep := s[begin:end] + if i%4 == 0 { + pos := rand.Intn(len(sep) + 1) + sep = sep[:pos] + "A" + sep[pos:] + } + want := simpleIndex(s, sep) + res := Index(s, sep) + if res != want { + t.Errorf("Index(%s,%s) = %d; want %d", s, sep, res, want) + } + } + } + } +} + var indexRuneTests = []struct { s string rune rune diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go index 455d412330..6734360e37 100644 --- a/src/sync/rwmutex.go +++ b/src/sync/rwmutex.go @@ -11,13 +11,17 @@ import ( ) // An RWMutex is a reader/writer mutual exclusion lock. -// The lock can be held by an arbitrary number of readers -// or a single writer. -// RWMutexes can be created as part of other -// structures; the zero value for a RWMutex is -// an unlocked mutex. +// The lock can be held by an arbitrary number of readers or a single writer. +// RWMutexes can be created as part of other structures; +// the zero value for a RWMutex is an unlocked mutex. // // An RWMutex must not be copied after first use. +// +// If a goroutine holds a RWMutex for reading, it must not expect this or any +// other goroutine to be able to also take the read lock until the first read +// lock is released. In particular, this prohibits recursive read locking. +// This is to ensure that the lock eventually becomes available; +// a blocked Lock call excludes new readers from acquiring the lock. type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // semaphore for writers to wait for completing readers @@ -73,9 +77,6 @@ func (rw *RWMutex) RUnlock() { // Lock locks rw for writing. // If the lock is already locked for reading or writing, // Lock blocks until the lock is available. -// To ensure that the lock eventually becomes available, -// a blocked Lock call excludes new readers from acquiring -// the lock. func (rw *RWMutex) Lock() { if race.Enabled { _ = rw.w.state diff --git a/src/syscall/dir_plan9.go b/src/syscall/dir_plan9.go index 697bf5499c..15b267411c 100644 --- a/src/syscall/dir_plan9.go +++ b/src/syscall/dir_plan9.go @@ -184,6 +184,7 @@ func gbit8(b []byte) (uint8, []byte) { } // gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b. +//go:nosplit func gbit16(b []byte) (uint16, []byte) { return uint16(b[0]) | uint16(b[1])<<8, b[2:] } diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 5a6b204997..39764f7076 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -20,21 +20,21 @@ type SysProcIDMap struct { } type SysProcAttr struct { - Chroot string // Chroot. - Credential *Credential // Credential. - Ptrace bool // Enable tracing. - Setsid bool // Create session. - Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. - Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) - Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd - Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) - Pgid int // Child's process group ID if Setpgid. - Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) - Cloneflags uintptr // Flags for clone calls (Linux only) - Unshare uintptr // Flags for unshare calls (Linux only) - UidMappings []SysProcIDMap // User ID mappings for user namespaces. - GidMappings []SysProcIDMap // Group ID mappings for user namespaces. + Chroot string // Chroot. + Credential *Credential // Credential. + Ptrace bool // Enable tracing. + Setsid bool // Create session. + Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. + Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd + Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) + Pgid int // Child's process group ID if Setpgid. + Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) + Cloneflags uintptr // Flags for clone calls (Linux only) + Unshareflags uintptr // Flags for unshare calls (Linux only) + UidMappings []SysProcIDMap // User ID mappings for user namespaces. + GidMappings []SysProcIDMap // Group ID mappings for user namespaces. // GidMappingsEnableSetgroups enabling setgroups syscall. // If false, then setgroups syscall will be disabled for the child process. // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged @@ -196,8 +196,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Unshare - if sys.Unshare != 0 { - _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshare, 0, 0) + if sys.Unshareflags != 0 { + _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0) if err1 != 0 { goto childerror } @@ -206,9 +206,15 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // User and groups if cred := sys.Credential; cred != nil { ngroups := uintptr(len(cred.Groups)) + groups := uintptr(0) if ngroups > 0 { - groups := unsafe.Pointer(&cred.Groups[0]) - _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0) + groups = uintptr(unsafe.Pointer(&cred.Groups[0])) + } + // Don't call setgroups in case of user namespace, gid mappings + // and disabled setgroups, because otherwise unprivileged user namespace + // will fail with any non-empty SysProcAttr.Credential. + if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) { + _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0) if err1 != 0 { goto childerror } diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index 099756328c..a562c9cbf2 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -26,7 +26,7 @@ func isChrooted(t *testing.T) bool { return root.Sys().(*syscall.Stat_t).Ino != 2 } -func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd { +func checkUserNS(t *testing.T) { if _, err := os.Stat("/proc/self/ns/user"); err != nil { if os.IsNotExist(err) { t.Skip("kernel doesn't support user namespaces") @@ -56,6 +56,10 @@ func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd { if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" { t.Skip("skipping test on Kubernetes-based builders; see Issue 12815") } +} + +func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd { + checkUserNS(t) cmd := exec.Command("whoami") cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUSER, @@ -141,9 +145,20 @@ func TestUnshare(t *testing.T) { t.Skip("skipping test on Kubernetes-based builders; see Issue 12815") } - cmd := exec.Command("cat", "/proc/net/dev") + path := "/proc/net/dev" + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + t.Skip("kernel doesn't support proc filesystem") + } + if os.IsPermission(err) { + t.Skip("unable to test proc filesystem due to permissions") + } + t.Fatal(err) + } + + cmd := exec.Command("cat", path) cmd.SysProcAttr = &syscall.SysProcAttr{ - Unshare: syscall.CLONE_NEWNET, + Unshareflags: syscall.CLONE_NEWNET, } out, err := cmd.CombinedOutput() if err != nil { @@ -161,3 +176,58 @@ func TestUnshare(t *testing.T) { t.Fatalf("Expected 3 lines of output, got %d", len(lines)) } } + +func TestGroupCleanup(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("we need root for credential") + } + cmd := exec.Command("id") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Credential: &syscall.Credential{ + Uid: 0, + Gid: 0, + }, + } + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("Cmd failed with err %v, output: %s", err, out) + } + strOut := strings.TrimSpace(string(out)) + expected := "uid=0(root) gid=0(root) groups=0(root)" + if strOut != expected { + t.Fatalf("id command output: %s, expected: %s", strOut, expected) + } +} + +func TestGroupCleanupUserNamespace(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("we need root for credential") + } + checkUserNS(t) + cmd := exec.Command("id") + uid, gid := os.Getuid(), os.Getgid() + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUSER, + Credential: &syscall.Credential{ + Uid: uint32(uid), + Gid: uint32(gid), + }, + UidMappings: []syscall.SysProcIDMap{ + {ContainerID: 0, HostID: uid, Size: 1}, + }, + GidMappings: []syscall.SysProcIDMap{ + {ContainerID: 0, HostID: gid, Size: 1}, + }, + } + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("Cmd failed with err %v, output: %s", err, out) + } + strOut := strings.TrimSpace(string(out)) + // there are two possible outs + expected1 := "uid=0(root) gid=0(root) groups=0(root)" + expected2 := "uid=0(root) gid=0(root) groups=0(root),65534(nobody)" + if strOut != expected1 && strOut != expected2 { + t.Fatalf("id command output: %s, expected: %s or %s", strOut, expected1, expected2) + } +} diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go index 28d0225cbf..2a16650c0b 100644 --- a/src/syscall/types_linux.go +++ b/src/syscall/types_linux.go @@ -117,7 +117,7 @@ struct my_epoll_event { // alignment requirements of EABI int32_t padFd; #endif -#ifdef __powerpc64__ +#if defined(__powerpc64__) || defined(__s390x__) int32_t _padFd; #endif int32_t fd; diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go index 3ab8e6a558..cdde47863f 100644 --- a/src/syscall/ztypes_linux_s390x.go +++ b/src/syscall/ztypes_linux_s390x.go @@ -588,6 +588,7 @@ type Ustat_t struct { type EpollEvent struct { Events uint32 + _ int32 Fd int32 Pad int32 } diff --git a/src/time/format.go b/src/time/format.go index 13c2bb6e52..c2ae793020 100644 --- a/src/time/format.go +++ b/src/time/format.go @@ -51,6 +51,9 @@ import "errors" // use of "GMT" in that case. // In general RFC1123Z should be used instead of RFC1123 for servers // that insist on that format, and RFC3339 should be preferred for new protocols. +// RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; +// when used with time.Parse they do not accept all the time formats +// permitted by the RFCs. const ( ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" diff --git a/src/time/genzabbrs.go b/src/time/genzabbrs.go index 9eb0728a42..6281f73ce4 100644 --- a/src/time/genzabbrs.go +++ b/src/time/genzabbrs.go @@ -30,7 +30,7 @@ var filename = flag.String("output", "zoneinfo_abbrs_windows.go", "output file n // getAbbrs finds timezone abbreviations (standard and daylight saving time) // for location l. func getAbbrs(l *time.Location) (st, dt string) { - t := time.Date(time.Now().Year(), 0, 0, 0, 0, 0, 0, l) + t := time.Date(time.Now().Year(), 0, 1, 0, 0, 0, 0, l) abbr1, off1 := t.Zone() for i := 0; i < 12; i++ { t = t.AddDate(0, 1, 0) diff --git a/src/time/sleep.go b/src/time/sleep.go index 7661f7e54f..73114f5eec 100644 --- a/src/time/sleep.go +++ b/src/time/sleep.go @@ -54,6 +54,14 @@ type Timer struct { // expired or been stopped. // Stop does not close the channel, to prevent a read from the channel succeeding // incorrectly. +// +// To prevent the timer firing after a call to Stop, +// check the return value and drain the channel. For example: +// if !t.Stop() { +// <-t.C +// } +// This cannot be done concurrent to other receives from the Timer's +// channel. func (t *Timer) Stop() bool { if t.r.f == nil { panic("time: Stop called on uninitialized Timer") @@ -80,6 +88,20 @@ func NewTimer(d Duration) *Timer { // Reset changes the timer to expire after duration d. // It returns true if the timer had been active, false if the timer had // expired or been stopped. +// +// To reuse an active timer, always call its Stop method first and—if it had +// expired—drain the value from its channel. For example: +// if !t.Stop() { +// <-t.C +// } +// t.Reset(d) +// This should not be done concurrent to other receives from the Timer's +// channel. +// +// Note that it is not possible to use Reset's return value correctly, as there +// is a race condition between draining the channel and the new timer expiring. +// Reset should always be used in concert with Stop, as described above. +// The return value exists to preserve compatibility with existing programs. func (t *Timer) Reset(d Duration) bool { if t.r.f == nil { panic("time: Reset called on uninitialized Timer") diff --git a/src/vendor/golang.org/x/net/route/message_freebsd_test.go b/src/vendor/golang.org/x/net/route/message_freebsd_test.go index 6d03d000a8..785c273f65 100644 --- a/src/vendor/golang.org/x/net/route/message_freebsd_test.go +++ b/src/vendor/golang.org/x/net/route/message_freebsd_test.go @@ -32,11 +32,11 @@ func TestFetchAndParseRIBOnFreeBSD(t *testing.T) { func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) { if _, err := FetchRIB(sysAF_UNSPEC, sysNET_RT_IFLISTL, 0); err != nil { - t.Skip("NET_RT_LISTL not supported") + t.Skip("NET_RT_IFLISTL not supported") } var p uintptr if kernelAlign != int(unsafe.Sizeof(p)) { - t.Skip("NET_RT_LIST vs. NET_RT_LISTL doesn't work for 386 emulation on amd64") + t.Skip("NET_RT_IFLIST vs. NET_RT_IFLISTL doesn't work for 386 emulation on amd64") } var tests = [2]struct { diff --git a/test/fixedbugs/issue15898.go b/test/fixedbugs/issue15898.go new file mode 100644 index 0000000000..7b66ea23dc --- /dev/null +++ b/test/fixedbugs/issue15898.go @@ -0,0 +1,18 @@ +// errorcheck + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f(e interface{}) { + switch e.(type) { + case nil, nil: // ERROR "multiple nil cases in type switch" + } + + switch e.(type) { + case nil: + case nil: // ERROR "multiple nil cases in type switch" + } +} diff --git a/test/fixedbugs/issue15902.go b/test/fixedbugs/issue15902.go new file mode 100644 index 0000000000..9511a220ed --- /dev/null +++ b/test/fixedbugs/issue15902.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2016 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 test makes sure we don't use 4-byte unaligned writes +// to zero memory on architectures that don't support them. + +package main + +type T struct { + a byte + b [10]byte +} + +//go:noinline +func f(t *T) { + // t will be aligned, so &t.b won't be. + t.b = [10]byte{} +} + +var t T + +func main() { + f(&t) +} diff --git a/test/fixedbugs/issue15920.dir/a.go b/test/fixedbugs/issue15920.dir/a.go new file mode 100644 index 0000000000..15f92355f7 --- /dev/null +++ b/test/fixedbugs/issue15920.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2016 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 a + +type Error error + +func F() Error { return nil } diff --git a/test/fixedbugs/issue15920.dir/b.go b/test/fixedbugs/issue15920.dir/b.go new file mode 100644 index 0000000000..0a36c5c6ab --- /dev/null +++ b/test/fixedbugs/issue15920.dir/b.go @@ -0,0 +1,7 @@ +// Copyright 2016 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 b + +import _ "./a" diff --git a/test/fixedbugs/issue15920.go b/test/fixedbugs/issue15920.go new file mode 100644 index 0000000000..4d2844dbb9 --- /dev/null +++ b/test/fixedbugs/issue15920.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2016 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 ignored diff --git a/test/fixedbugs/issue15926.go b/test/fixedbugs/issue15926.go new file mode 100644 index 0000000000..76e25eb640 --- /dev/null +++ b/test/fixedbugs/issue15926.go @@ -0,0 +1,20 @@ +// build + +// Copyright 2016 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. + +// Issue 15926: linker was adding .def to the end of symbols, causing +// a name collision with a method actually named def. + +package main + +type S struct{} + +func (s S) def() {} + +var I = S.def + +func main() { + I(S{}) +} diff --git a/test/fixedbugs/issue15961.go b/test/fixedbugs/issue15961.go new file mode 100644 index 0000000000..db3d662378 --- /dev/null +++ b/test/fixedbugs/issue15961.go @@ -0,0 +1,21 @@ +// compile + +// Copyright 2016 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 y + +type symSet []int + +//go:noinline +func (s symSet) len() (r int) { + return 0 +} + +func f(m map[int]symSet) { + var symSet []int + for _, x := range symSet { + m[x] = nil + } +} diff --git a/test/fixedbugs/issue15975.go b/test/fixedbugs/issue15975.go new file mode 100644 index 0000000000..56a50e1176 --- /dev/null +++ b/test/fixedbugs/issue15975.go @@ -0,0 +1,36 @@ +// run + +// Copyright 2016 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 + +var fail bool + +type Closer interface { + Close() +} + +func nilInterfaceDeferCall() { + var x Closer + defer x.Close() + // if it panics when evaluating x.Close, it should not reach here + fail = true +} + +func shouldPanic(f func()) { + defer func() { + if recover() == nil { + panic("did not panic") + } + }() + f() +} + +func main() { + shouldPanic(nilInterfaceDeferCall) + if fail { + panic("fail") + } +} diff --git a/test/fixedbugs/issue15988.go b/test/fixedbugs/issue15988.go new file mode 100644 index 0000000000..2bed2a9c30 --- /dev/null +++ b/test/fixedbugs/issue15988.go @@ -0,0 +1,14 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f(p, q []int) { + p = append(q, 5) + sink = &p +} + +var sink *[]int diff --git a/test/fixedbugs/issue16008.go b/test/fixedbugs/issue16008.go new file mode 100644 index 0000000000..1b516fbabe --- /dev/null +++ b/test/fixedbugs/issue16008.go @@ -0,0 +1,52 @@ +// errorcheck -0 -race + +package foo + +const benchmarkNumNodes = 10000 + +func BenchmarkUpdateNodeTransaction(b B) { + s, nodeIDs := setupNodes(benchmarkNumNodes) + b.ResetTimer() + for i := 0; i < b.N(); i++ { + _ = s.Update(func(tx1 Tx) error { + _ = UpdateNode(tx1, &Node{ + ID: nodeIDs[i%benchmarkNumNodes], + }) + return nil + }) + } +} + +type B interface { + ResetTimer() + N() int +} + +type Tx interface { +} + +type Node struct { + ID string +} + +type MemoryStore struct { +} + +// go:noinline +func setupNodes(n int) (s *MemoryStore, nodeIDs []string) { + return +} + +//go:noinline +func (s *MemoryStore) Update(cb func(Tx) error) error { + return nil +} + +var sink interface{} + +//go:noinline +func UpdateNode(tx Tx, n *Node) error { + sink = tx + sink = n + return nil +} diff --git a/test/fixedbugs/issue16016.go b/test/fixedbugs/issue16016.go new file mode 100644 index 0000000000..e738e1dba0 --- /dev/null +++ b/test/fixedbugs/issue16016.go @@ -0,0 +1,35 @@ +// run + +// Copyright 2016 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 "time" + +type T struct{} + +func (*T) Foo(vals []interface{}) { + switch v := vals[0].(type) { + case string: + _ = v + } +} + +type R struct{ *T } + +type Q interface { + Foo([]interface{}) +} + +func main() { + var q Q = &R{&T{}} + for i := 0; i < 10000; i++ { + go func() { + defer q.Foo([]interface{}{"meow"}) + time.Sleep(100 * time.Millisecond) + }() + } + time.Sleep(1 * time.Second) +} diff --git a/test/switch5.go b/test/switch5.go new file mode 100644 index 0000000000..7da2c6641f --- /dev/null +++ b/test/switch5.go @@ -0,0 +1,81 @@ +// errorcheck + +// Copyright 2016 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. + +// Verify that switch statements with duplicate cases are detected by the compiler. +// Does not compile. + +package main + +import "fmt" + +func f0(x int) { + switch x { + case 0: + case 0: // ERROR "duplicate case 0 in switch" + } + + switch x { + case 0: + case int(0): // ERROR "duplicate case 0 in switch" + } +} + +func f1(x float32) { + switch x { + case 5: + case 5: // ERROR "duplicate case 5 in switch" + case 5.0: // ERROR "duplicate case 5 in switch" + } +} + +func f2(s string) { + switch s { + case "": + case "": // ERROR "duplicate case .. in switch" + case "abc": + case "abc": // ERROR "duplicate case .abc. in switch" + } +} + +func f3(e interface{}) { + switch e { + case 0: + case 0: // ERROR "duplicate case 0 in switch" + case int64(0): + case float32(10): + case float32(10): // ERROR "duplicate case float32\(10\) in switch" + case float64(10): + case float64(10): // ERROR "duplicate case float64\(10\) in switch" + } +} + +func f4(e interface{}) { + switch e.(type) { + case int: + case int: // ERROR "duplicate case int in type switch" + case int64: + case error: // ERROR "duplicate case error in type switch" + case error: + case fmt.Stringer: + case fmt.Stringer: // ERROR "duplicate case fmt.Stringer in type switch" + case struct { + i int "tag1" + }: + case struct { + i int "tag2" + }: + case struct { + i int "tag1" + }: // ERROR "duplicate case struct { i int .tag1. } in type switch" + } +} + +func f5(a [1]int) { + switch a { + case [1]int{0}: + case [1]int{0}: // OK -- see issue 15896 + } +} diff --git a/test/switch6.go b/test/switch6.go new file mode 100644 index 0000000000..bd62c620b6 --- /dev/null +++ b/test/switch6.go @@ -0,0 +1,32 @@ +// errorcheck + +// Copyright 2016 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. + +// Check the compiler's switch handling that happens +// at typechecking time. +// This must be separate from other checks, +// because errors during typechecking +// prevent other errors from being discovered. + +package main + +// Verify that type switch statements with impossible cases are detected by the compiler. +func f0(e error) { + switch e.(type) { + case int: // ERROR "impossible type switch case: e \(type error\) cannot have dynamic type int \(missing Error method\)" + } +} + +// Verify that the compiler rejects multiple default cases. +func f1(e interface{}) { + switch e { // ERROR "multiple defaults in switch" + default: + default: + } + switch e.(type) { // ERROR "multiple defaults in switch" + default: + default: + } +}