mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.boringcrypto.go1.9] all: merge go1.9.7 into dev.boringcrypto.go1.9
Change-Id: I1f9769a0c2c7c090886afa31c86c403da29d2013
This commit is contained in:
commit
0bad1bef40
@ -63,6 +63,29 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.4">Go
|
||||
1.9.4</a> milestone on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.5 (released 2018/03/28) includes fixes to the compiler, go command, and
|
||||
<code>net/http/pprof</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.5">Go
|
||||
1.9.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.6 (released 2018/05/01) includes fixes to the compiler and go command.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.6">Go
|
||||
1.9.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.7 (released 2018/06/05) includes fixes to the go command, and the
|
||||
<code>crypto/x509</code>, and <code>strings</code> packages.
|
||||
In particular, it adds <a href="https://go.googlesource.com/go/+/d4e21288e444d3ffd30d1a0737f15ea3fc3b8ad9">
|
||||
minimal support to the go command for the vgo transition</a>.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.7">Go
|
||||
1.9.7 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
|
||||
|
||||
<p>
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define fd (100)
|
||||
#define fd (30)
|
||||
|
||||
// Tests libgo2.so, which does not export any functions.
|
||||
// Read a string from the file descriptor and print it.
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
// that the C code can also use.
|
||||
|
||||
const (
|
||||
fd = 100
|
||||
fd = 30
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -909,6 +909,20 @@ var linuxAMD64Tests = []*asmTest{
|
||||
`,
|
||||
[]string{"b\\+40\\(SP\\)"},
|
||||
},
|
||||
{
|
||||
`
|
||||
func f73(a,b [3]int16) bool {
|
||||
return a == b
|
||||
}`,
|
||||
[]string{"\tCMPL\t[A-Z]"},
|
||||
},
|
||||
{
|
||||
`
|
||||
func f74(a,b [12]int8) bool {
|
||||
return a == b
|
||||
}`,
|
||||
[]string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"},
|
||||
},
|
||||
}
|
||||
|
||||
var linux386Tests = []*asmTest{
|
||||
|
@ -1190,8 +1190,22 @@ func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
|
||||
}
|
||||
p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
|
||||
// This is permitted for general use because Solaris
|
||||
// code relies on it in golang.org/x/sys/unix and others.
|
||||
fields := pragmaFields(text)
|
||||
if len(fields) >= 4 {
|
||||
lib := strings.Trim(fields[3], `"`)
|
||||
if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) {
|
||||
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)})
|
||||
}
|
||||
p.pragcgobuf += p.pragcgo(pos, text)
|
||||
return pragmaValue("go:cgo_import_dynamic")
|
||||
}
|
||||
fallthrough
|
||||
case strings.HasPrefix(text, "go:cgo_"):
|
||||
// For security, we disallow //go:cgo_* directives outside cgo-generated files.
|
||||
// For security, we disallow //go:cgo_* directives other
|
||||
// than cgo_import_dynamic outside cgo-generated files.
|
||||
// Exception: they are allowed in the standard library, for runtime and syscall.
|
||||
if !isCgoGeneratedFile(pos) && !compiling_std {
|
||||
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
|
||||
@ -1227,6 +1241,18 @@ func isCgoGeneratedFile(pos src.Pos) bool {
|
||||
return strings.HasPrefix(filepath.Base(filepath.Clean(pos.AbsFilename())), "_cgo_")
|
||||
}
|
||||
|
||||
// safeArg reports whether arg is a "safe" command-line argument,
|
||||
// meaning that when it appears in a command-line, it probably
|
||||
// doesn't have some special meaning other than its own name.
|
||||
// This is copied from SafeArg in cmd/go/internal/load/pkg.go.
|
||||
func safeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
c := name[0]
|
||||
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
func mkname(sym *types.Sym) *Node {
|
||||
n := oldname(sym)
|
||||
if n.Name != nil && n.Name.Pack != nil {
|
||||
|
@ -1272,6 +1272,13 @@ opswitch:
|
||||
}
|
||||
if cs != nil {
|
||||
cmp := Op(n.Etype)
|
||||
// Our comparison below assumes that the non-constant string
|
||||
// is on the left hand side, so rewrite "" cmp x to x cmp "".
|
||||
// See issue 24817.
|
||||
if Isconst(n.Left, CTSTR) {
|
||||
cmp = brrev(cmp)
|
||||
}
|
||||
|
||||
// maxRewriteLen was chosen empirically.
|
||||
// It is the value that minimizes cmd/go file size
|
||||
// across most architectures.
|
||||
@ -3390,18 +3397,23 @@ func walkcompare(n *Node, init *Nodes) *Node {
|
||||
i++
|
||||
remains -= t.Elem().Width
|
||||
} else {
|
||||
elemType := t.Elem().ToUnsigned()
|
||||
cmplw := nod(OINDEX, cmpl, nodintconst(int64(i)))
|
||||
cmplw = conv(cmplw, convType)
|
||||
cmplw = conv(cmplw, elemType) // convert to unsigned
|
||||
cmplw = conv(cmplw, convType) // widen
|
||||
cmprw := nod(OINDEX, cmpr, nodintconst(int64(i)))
|
||||
cmprw = conv(cmprw, elemType)
|
||||
cmprw = conv(cmprw, convType)
|
||||
// For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
|
||||
// ssa will generate a single large load.
|
||||
for offset := int64(1); offset < step; offset++ {
|
||||
lb := nod(OINDEX, cmpl, nodintconst(int64(i+offset)))
|
||||
lb = conv(lb, elemType)
|
||||
lb = conv(lb, convType)
|
||||
lb = nod(OLSH, lb, nodintconst(int64(8*t.Elem().Width*offset)))
|
||||
cmplw = nod(OOR, cmplw, lb)
|
||||
rb := nod(OINDEX, cmpr, nodintconst(int64(i+offset)))
|
||||
rb = conv(rb, elemType)
|
||||
rb = conv(rb, convType)
|
||||
rb = nod(OLSH, rb, nodintconst(int64(8*t.Elem().Width*offset)))
|
||||
cmprw = nod(OOR, cmprw, rb)
|
||||
|
@ -1499,9 +1499,9 @@
|
||||
(SUBQconst (MOVQconst [d]) [c]) -> (MOVQconst [d-c])
|
||||
(SUBQconst (SUBQconst x [d]) [c]) && is32Bit(-c-d) -> (ADDQconst [-c-d] x)
|
||||
(SARQconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
|
||||
(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int32(d))>>uint64(c)])
|
||||
(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int16(d))>>uint64(c)])
|
||||
(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [int64(int8(d))>>uint64(c)])
|
||||
(NEGQ (MOVQconst [c])) -> (MOVQconst [-c])
|
||||
(NEGL (MOVLconst [c])) -> (MOVLconst [int64(int32(-c))])
|
||||
(MULQconst [c] (MOVQconst [d])) -> (MOVQconst [c*d])
|
||||
|
@ -268,22 +268,22 @@ func init() {
|
||||
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
|
||||
|
||||
{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-31
|
||||
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-15
|
||||
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned arg0 >> auxint, shift amount 0-7
|
||||
{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
|
||||
{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint16(arg0) >> auxint, shift amount 0-15
|
||||
{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // unsigned uint8(arg0) >> auxint, shift amount 0-7
|
||||
|
||||
{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
|
||||
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
|
||||
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-15
|
||||
{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-7
|
||||
{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
|
||||
{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int16(arg0) >> auxint, shift amount 0-15
|
||||
{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // signed int8(arg0) >> auxint, shift amount 0-7
|
||||
|
||||
{name: "ROLQ", argLength: 2, reg: gp21shift, asm: "ROLQ", resultInArg0: true, clobberFlags: true}, // arg0 rotate left arg1 bits.
|
||||
{name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true}, // arg0 rotate left arg1 bits.
|
||||
|
@ -978,7 +978,7 @@
|
||||
(SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c])
|
||||
(SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x)
|
||||
(SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
|
||||
(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
|
||||
(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(d))>>uint64(c)])
|
||||
(NEG (MOVDconst [c])) -> (MOVDconst [-c])
|
||||
(NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))])
|
||||
(MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d])
|
||||
|
@ -295,15 +295,15 @@ func init() {
|
||||
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31
|
||||
|
||||
{name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31
|
||||
|
||||
// Arithmetic shifts clobber flags.
|
||||
{name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64
|
||||
{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 32
|
||||
{name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 32
|
||||
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-31
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31
|
||||
|
||||
{name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63
|
||||
{name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31
|
||||
|
@ -33234,7 +33234,7 @@ func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARBconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int8(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@ -33243,7 +33243,7 @@ func rewriteValueAMD64_OpAMD64SARBconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int8(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -33489,7 +33489,7 @@ func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARLconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int32(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@ -33498,7 +33498,7 @@ func rewriteValueAMD64_OpAMD64SARLconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int32(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -33809,7 +33809,7 @@ func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
|
||||
}
|
||||
// match: (SARWconst [c] (MOVQconst [d]))
|
||||
// cond:
|
||||
// result: (MOVQconst [d>>uint64(c)])
|
||||
// result: (MOVQconst [int64(int16(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@ -33818,7 +33818,7 @@ func rewriteValueAMD64_OpAMD64SARWconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpAMD64MOVQconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int16(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -34589,7 +34589,7 @@ func rewriteValueS390X_OpS390XSRAW_0(v *Value) bool {
|
||||
func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
|
||||
// match: (SRAWconst [c] (MOVDconst [d]))
|
||||
// cond:
|
||||
// result: (MOVDconst [d>>uint64(c)])
|
||||
// result: (MOVDconst [int64(int32(d))>>uint64(c)])
|
||||
for {
|
||||
c := v.AuxInt
|
||||
v_0 := v.Args[0]
|
||||
@ -34598,7 +34598,7 @@ func rewriteValueS390X_OpS390XSRAWconst_0(v *Value) bool {
|
||||
}
|
||||
d := v_0.AuxInt
|
||||
v.reset(OpS390XMOVDconst)
|
||||
v.AuxInt = d >> uint64(c)
|
||||
v.AuxInt = int64(int32(d)) >> uint64(c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -4500,3 +4500,36 @@ func TestBadCgoDirectives(t *testing.T) {
|
||||
tg.run("build", "-n", "x")
|
||||
tg.grepStderr("-D@foo", "did not find -D@foo in commands")
|
||||
}
|
||||
|
||||
func TestTwoPkgConfigs(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("no cgo")
|
||||
}
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
t.Skipf("no shell scripts on %s", runtime.GOOS)
|
||||
}
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/x/a.go", `package x
|
||||
// #cgo pkg-config: --static a
|
||||
import "C"
|
||||
`)
|
||||
tg.tempFile("src/x/b.go", `package x
|
||||
// #cgo pkg-config: --static a
|
||||
import "C"
|
||||
`)
|
||||
tg.tempFile("pkg-config.sh", `#!/bin/sh
|
||||
echo $* >>`+tg.path("pkg-config.out"))
|
||||
tg.must(os.Chmod(tg.path("pkg-config.sh"), 0755))
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
|
||||
tg.run("build", "x")
|
||||
out, err := ioutil.ReadFile(tg.path("pkg-config.out"))
|
||||
tg.must(err)
|
||||
out = bytes.TrimSpace(out)
|
||||
want := "--cflags --static --static -- a a\n--libs --static --static -- a a"
|
||||
if !bytes.Equal(out, []byte(want)) {
|
||||
t.Errorf("got %q want %q", out, want)
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
|
||||
continue
|
||||
}
|
||||
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
|
||||
// Ignore VCS type "mod", which is new Go modules.
|
||||
// This code is for old go get and must ignore the new mod lines.
|
||||
// Otherwise matchGoImport will complain about two
|
||||
// different metaImport lines for the same Prefix.
|
||||
if f[1] == "mod" {
|
||||
continue
|
||||
}
|
||||
imports = append(imports, metaImport{
|
||||
Prefix: f[0],
|
||||
VCS: f[1],
|
||||
|
@ -210,7 +210,7 @@ var downloadRootCache = map[string]bool{}
|
||||
// download runs the download half of the get command
|
||||
// for the package named by the argument.
|
||||
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
|
||||
if mode&load.UseVendor != 0 {
|
||||
if mode&load.ResolveImport != 0 {
|
||||
// Caller is responsible for expanding vendor paths.
|
||||
panic("internal error: download mode has useVendor set")
|
||||
}
|
||||
@ -218,7 +218,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||
if parent == nil {
|
||||
return load.LoadPackage(path, stk)
|
||||
}
|
||||
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
|
||||
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
|
||||
}
|
||||
|
||||
p := load1(arg, mode)
|
||||
@ -347,12 +347,12 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||
base.Errorf("%s", err)
|
||||
continue
|
||||
}
|
||||
// If this is a test import, apply vendor lookup now.
|
||||
// We cannot pass useVendor to download, because
|
||||
// If this is a test import, apply module and vendor lookup now.
|
||||
// We cannot pass ResolveImport to download, because
|
||||
// download does caching based on the value of path,
|
||||
// so it must be the fully qualified path already.
|
||||
if i >= len(p.Imports) {
|
||||
path = load.VendoredImportPath(p, path)
|
||||
path = load.ResolveImportPath(p, path)
|
||||
}
|
||||
download(path, p, stk, 0)
|
||||
}
|
||||
|
@ -47,6 +47,20 @@ var parseMetaGoImportsTests = []struct {
|
||||
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">`,
|
||||
[]metaImport{
|
||||
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
|
||||
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
|
||||
[]metaImport{
|
||||
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<head>
|
||||
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
|
@ -767,8 +767,8 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.Contains(mmi.RepoRoot, "://") {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
|
||||
if err := validateRepoRootScheme(mmi.RepoRoot); err != nil {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)
|
||||
}
|
||||
rr := &repoRoot{
|
||||
vcs: vcsByCmd(mmi.VCS),
|
||||
@ -782,6 +782,36 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
// validateRepoRootScheme returns an error if repoRoot does not seem
|
||||
// to have a valid URL scheme. At this point we permit things that
|
||||
// aren't valid URLs, although later, if not using -insecure, we will
|
||||
// restrict repoRoots to be valid URLs. This is only because we've
|
||||
// historically permitted them, and people may depend on that.
|
||||
func validateRepoRootScheme(repoRoot string) error {
|
||||
end := strings.Index(repoRoot, "://")
|
||||
if end <= 0 {
|
||||
return errors.New("no scheme")
|
||||
}
|
||||
|
||||
// RFC 3986 section 3.1.
|
||||
for i := 0; i < end; i++ {
|
||||
c := repoRoot[i]
|
||||
switch {
|
||||
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
|
||||
// OK.
|
||||
case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
|
||||
// OK except at start.
|
||||
if i == 0 {
|
||||
return errors.New("invalid scheme")
|
||||
}
|
||||
default:
|
||||
return errors.New("invalid scheme")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var fetchGroup singleflight.Group
|
||||
var (
|
||||
fetchCacheMu sync.Mutex
|
||||
|
@ -390,3 +390,46 @@ func TestMatchGoImport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRepoRootScheme(t *testing.T) {
|
||||
tests := []struct {
|
||||
root string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
root: "",
|
||||
err: "no scheme",
|
||||
},
|
||||
{
|
||||
root: "http://",
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
root: "a://",
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
root: "a#://",
|
||||
err: "invalid scheme",
|
||||
},
|
||||
{
|
||||
root: "-config://",
|
||||
err: "invalid scheme",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := validateRepoRootScheme(test.root)
|
||||
if err == nil {
|
||||
if test.err != "" {
|
||||
t.Errorf("validateRepoRootScheme(%q) = nil, want %q", test.root, test.err)
|
||||
}
|
||||
} else if test.err == "" {
|
||||
if err != nil {
|
||||
t.Errorf("validateRepoRootScheme(%q) = %q, want nil", test.root, test.err)
|
||||
}
|
||||
} else if err.Error() != test.err {
|
||||
t.Errorf("validateRepoRootScheme(%q) = %q, want %q", test.root, err, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,8 +201,8 @@ func runList(cmd *base.Command, args []string) {
|
||||
|
||||
for _, pkg := range loadpkgs(args) {
|
||||
// Show vendor-expanded paths in listing
|
||||
pkg.TestImports = pkg.Vendored(pkg.TestImports)
|
||||
pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
|
||||
pkg.TestImports = pkg.Resolve(pkg.TestImports)
|
||||
pkg.XTestImports = pkg.Resolve(pkg.XTestImports)
|
||||
|
||||
do(&pkg.PackagePublic)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package load
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"go/build"
|
||||
@ -16,6 +17,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@ -123,7 +125,8 @@ type PackageInternal struct {
|
||||
// Unexported fields are not part of the public API.
|
||||
Build *build.Package
|
||||
Pkgdir string // overrides build.PkgDir
|
||||
Imports []*Package
|
||||
Imports []*Package // this package's direct imports
|
||||
RawImports []string // this package's original imports as they appear in the text of the program
|
||||
Deps []*Package
|
||||
GoFiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
|
||||
SFiles []string
|
||||
@ -169,7 +172,7 @@ func (e *NoGoError) Error() string {
|
||||
return "no Go files in " + e.Package.Dir
|
||||
}
|
||||
|
||||
// Vendored returns the vendor-resolved version of imports,
|
||||
// Resolve returns the resolved version of imports,
|
||||
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
|
||||
// The imports in p.TestImports and p.XTestImports are not recursively
|
||||
// loaded during the initial load of p, so they list the imports found in
|
||||
@ -179,14 +182,14 @@ func (e *NoGoError) Error() string {
|
||||
// can produce better error messages if it starts with the original paths.
|
||||
// The initial load of p loads all the non-test imports and rewrites
|
||||
// the vendored paths, so nothing should ever call p.vendored(p.Imports).
|
||||
func (p *Package) Vendored(imports []string) []string {
|
||||
func (p *Package) Resolve(imports []string) []string {
|
||||
if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
|
||||
panic("internal error: p.vendored(p.Imports) called")
|
||||
panic("internal error: p.Resolve(p.Imports) called")
|
||||
}
|
||||
seen := make(map[string]bool)
|
||||
var all []string
|
||||
for _, path := range imports {
|
||||
path = VendoredImportPath(p, path)
|
||||
path = ResolveImportPath(p, path)
|
||||
if !seen[path] {
|
||||
seen[path] = true
|
||||
all = append(all, path)
|
||||
@ -251,6 +254,7 @@ func (p *Package) copyBuild(pp *build.Package) {
|
||||
// We modify p.Imports in place, so make copy now.
|
||||
p.Imports = make([]string, len(pp.Imports))
|
||||
copy(p.Imports, pp.Imports)
|
||||
p.Internal.RawImports = pp.Imports
|
||||
p.TestGoFiles = pp.TestGoFiles
|
||||
p.TestImports = pp.TestImports
|
||||
p.XTestGoFiles = pp.XTestGoFiles
|
||||
@ -386,18 +390,22 @@ func makeImportValid(r rune) rune {
|
||||
|
||||
// Mode flags for loadImport and download (in get.go).
|
||||
const (
|
||||
// useVendor means that loadImport should do vendor expansion
|
||||
// (provided the vendoring experiment is enabled).
|
||||
// That is, useVendor means that the import path came from
|
||||
// a source file and has not been vendor-expanded yet.
|
||||
// Every import path should be loaded initially with useVendor,
|
||||
// and then the expanded version (with the /vendor/ in it) gets
|
||||
// recorded as the canonical import path. At that point, future loads
|
||||
// of that package must not pass useVendor, because
|
||||
// ResolveImport means that loadImport should do import path expansion.
|
||||
// That is, ResolveImport means that the import path came from
|
||||
// a source file and has not been expanded yet to account for
|
||||
// vendoring or possible module adjustment.
|
||||
// Every import path should be loaded initially with ResolveImport,
|
||||
// and then the expanded version (for example with the /vendor/ in it)
|
||||
// gets recorded as the canonical import path. At that point, future loads
|
||||
// of that package must not pass ResolveImport, because
|
||||
// disallowVendor will reject direct use of paths containing /vendor/.
|
||||
UseVendor = 1 << iota
|
||||
ResolveImport = 1 << iota
|
||||
|
||||
// getTestDeps is for download (part of "go get") and indicates
|
||||
// ResolveModule is for download (part of "go get") and indicates
|
||||
// that the module adjustment should be done, but not vendor adjustment.
|
||||
ResolveModule
|
||||
|
||||
// GetTestDeps is for download (part of "go get") and indicates
|
||||
// that test dependencies should be fetched too.
|
||||
GetTestDeps
|
||||
)
|
||||
@ -420,12 +428,15 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
isLocal := build.IsLocalImport(path)
|
||||
if isLocal {
|
||||
importPath = dirToImportPath(filepath.Join(srcDir, path))
|
||||
} else if mode&UseVendor != 0 {
|
||||
// We do our own vendor resolution, because we want to
|
||||
} else if mode&ResolveImport != 0 {
|
||||
// We do our own path resolution, because we want to
|
||||
// find out the key to use in packageCache without the
|
||||
// overhead of repeated calls to buildContext.Import.
|
||||
// The code is also needed in a few other places anyway.
|
||||
path = VendoredImportPath(parent, path)
|
||||
path = ResolveImportPath(parent, path)
|
||||
importPath = path
|
||||
} else if mode&ResolveModule != 0 {
|
||||
path = ModuleImportPath(parent, path)
|
||||
importPath = path
|
||||
}
|
||||
|
||||
@ -445,7 +456,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
// TODO: After Go 1, decide when to pass build.AllowBinary here.
|
||||
// See issue 3268 for mistakes to avoid.
|
||||
buildMode := build.ImportComment
|
||||
if mode&UseVendor == 0 || path != origPath {
|
||||
if mode&ResolveImport == 0 || path != origPath {
|
||||
// Not vendoring, or we already found the vendored path.
|
||||
buildMode |= build.IgnoreVendor
|
||||
}
|
||||
@ -476,7 +487,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
|
||||
if perr := disallowInternal(srcDir, p, stk); perr != p {
|
||||
return setErrorPos(perr, importPos)
|
||||
}
|
||||
if mode&UseVendor != 0 {
|
||||
if mode&ResolveImport != 0 {
|
||||
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
|
||||
return setErrorPos(perr, importPos)
|
||||
}
|
||||
@ -535,7 +546,50 @@ func isDir(path string) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
// VendoredImportPath returns the expansion of path when it appears in parent.
|
||||
// ResolveImportPath returns the true meaning of path when it appears in parent.
|
||||
// There are two different resolutions applied.
|
||||
// First, there is Go 1.5 vendoring (golang.org/s/go15vendor).
|
||||
// If vendor expansion doesn't trigger, then the path is also subject to
|
||||
// Go 1.11 vgo legacy conversion (golang.org/issue/25069).
|
||||
func ResolveImportPath(parent *Package, path string) (found string) {
|
||||
found = VendoredImportPath(parent, path)
|
||||
if found != path {
|
||||
return found
|
||||
}
|
||||
return ModuleImportPath(parent, path)
|
||||
}
|
||||
|
||||
// dirAndRoot returns the source directory and workspace root
|
||||
// for the package p, guaranteeing that root is a path prefix of dir.
|
||||
func dirAndRoot(p *Package) (dir, root string) {
|
||||
dir = filepath.Clean(p.Dir)
|
||||
root = filepath.Join(p.Root, "src")
|
||||
if !hasFilePathPrefix(dir, root) || p.ImportPath != "command-line-arguments" && filepath.Join(root, p.ImportPath) != dir {
|
||||
// Look for symlinks before reporting error.
|
||||
dir = expandPath(dir)
|
||||
root = expandPath(root)
|
||||
}
|
||||
|
||||
if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || p.ImportPath != "command-line-arguments" && !p.Internal.Local && filepath.Join(root, p.ImportPath) != dir {
|
||||
base.Fatalf("unexpected directory layout:\n"+
|
||||
" import path: %s\n"+
|
||||
" root: %s\n"+
|
||||
" dir: %s\n"+
|
||||
" expand root: %s\n"+
|
||||
" expand dir: %s\n"+
|
||||
" separator: %s",
|
||||
p.ImportPath,
|
||||
filepath.Join(p.Root, "src"),
|
||||
filepath.Clean(p.Dir),
|
||||
root,
|
||||
dir,
|
||||
string(filepath.Separator))
|
||||
}
|
||||
|
||||
return dir, root
|
||||
}
|
||||
|
||||
// VendoredImportPath returns the vendor-expansion of path when it appears in parent.
|
||||
// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
|
||||
// x/vendor/path, vendor/path, or else stay path if none of those exist.
|
||||
// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
|
||||
@ -544,29 +598,7 @@ func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
return path
|
||||
}
|
||||
|
||||
dir := filepath.Clean(parent.Dir)
|
||||
root := filepath.Join(parent.Root, "src")
|
||||
if !hasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
|
||||
// Look for symlinks before reporting error.
|
||||
dir = expandPath(dir)
|
||||
root = expandPath(root)
|
||||
}
|
||||
|
||||
if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
|
||||
base.Fatalf("unexpected directory layout:\n"+
|
||||
" import path: %s\n"+
|
||||
" root: %s\n"+
|
||||
" dir: %s\n"+
|
||||
" expand root: %s\n"+
|
||||
" expand dir: %s\n"+
|
||||
" separator: %s",
|
||||
parent.ImportPath,
|
||||
filepath.Join(parent.Root, "src"),
|
||||
filepath.Clean(parent.Dir),
|
||||
root,
|
||||
dir,
|
||||
string(filepath.Separator))
|
||||
}
|
||||
dir, root := dirAndRoot(parent)
|
||||
|
||||
vpath := "vendor/" + path
|
||||
for i := len(dir); i >= len(root); i-- {
|
||||
@ -610,6 +642,164 @@ func VendoredImportPath(parent *Package, path string) (found string) {
|
||||
return path
|
||||
}
|
||||
|
||||
var (
|
||||
modulePrefix = []byte("\nmodule ")
|
||||
goModPathCache = make(map[string]string)
|
||||
)
|
||||
|
||||
// goModPath returns the module path in the go.mod in dir, if any.
|
||||
func goModPath(dir string) (path string) {
|
||||
path, ok := goModPathCache[dir]
|
||||
if ok {
|
||||
return path
|
||||
}
|
||||
defer func() {
|
||||
goModPathCache[dir] = path
|
||||
}()
|
||||
|
||||
data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
var i int
|
||||
if bytes.HasPrefix(data, modulePrefix[1:]) {
|
||||
i = 0
|
||||
} else {
|
||||
i = bytes.Index(data, modulePrefix)
|
||||
if i < 0 {
|
||||
return ""
|
||||
}
|
||||
i++
|
||||
}
|
||||
line := data[i:]
|
||||
|
||||
// Cut line at \n, drop trailing \r if present.
|
||||
if j := bytes.IndexByte(line, '\n'); j >= 0 {
|
||||
line = line[:j]
|
||||
}
|
||||
if line[len(line)-1] == '\r' {
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
line = line[len("module "):]
|
||||
|
||||
// If quoted, unquote.
|
||||
path = strings.TrimSpace(string(line))
|
||||
if path != "" && path[0] == '"' {
|
||||
s, err := strconv.Unquote(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
path = s
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// findVersionElement returns the slice indices of the final version element /vN in path.
|
||||
// If there is no such element, it returns -1, -1.
|
||||
func findVersionElement(path string) (i, j int) {
|
||||
j = len(path)
|
||||
for i = len(path) - 1; i >= 0; i-- {
|
||||
if path[i] == '/' {
|
||||
if isVersionElement(path[i:j]) {
|
||||
return i, j
|
||||
}
|
||||
j = i
|
||||
}
|
||||
}
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
// isVersionElement reports whether s is a well-formed path version element:
|
||||
// v2, v3, v10, etc, but not v0, v05, v1.
|
||||
func isVersionElement(s string) bool {
|
||||
if len(s) < 3 || s[0] != '/' || s[1] != 'v' || s[2] == '0' || s[2] == '1' && len(s) == 3 {
|
||||
return false
|
||||
}
|
||||
for i := 2; i < len(s); i++ {
|
||||
if s[i] < '0' || '9' < s[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ModuleImportPath translates import paths found in go modules
|
||||
// back down to paths that can be resolved in ordinary builds.
|
||||
//
|
||||
// Define “new” code as code with a go.mod file in the same directory
|
||||
// or a parent directory. If an import in new code says x/y/v2/z but
|
||||
// x/y/v2/z does not exist and x/y/go.mod says “module x/y/v2”,
|
||||
// then go build will read the import as x/y/z instead.
|
||||
// See golang.org/issue/25069.
|
||||
func ModuleImportPath(parent *Package, path string) (found string) {
|
||||
if parent == nil || parent.Root == "" {
|
||||
return path
|
||||
}
|
||||
|
||||
// If there are no vN elements in path, leave it alone.
|
||||
// (The code below would do the same, but only after
|
||||
// some other file system accesses that we can avoid
|
||||
// here by returning early.)
|
||||
if i, _ := findVersionElement(path); i < 0 {
|
||||
return path
|
||||
}
|
||||
|
||||
dir, root := dirAndRoot(parent)
|
||||
|
||||
// Consider dir and parents, up to and including root.
|
||||
for i := len(dir); i >= len(root); i-- {
|
||||
if i < len(dir) && dir[i] != filepath.Separator {
|
||||
continue
|
||||
}
|
||||
if goModPath(dir[:i]) != "" {
|
||||
goto HaveGoMod
|
||||
}
|
||||
}
|
||||
// This code is not in a tree with a go.mod,
|
||||
// so apply no changes to the path.
|
||||
return path
|
||||
|
||||
HaveGoMod:
|
||||
// This import is in a tree with a go.mod.
|
||||
// Allow it to refer to code in GOPATH/src/x/y/z as x/y/v2/z
|
||||
// if GOPATH/src/x/y/go.mod says module "x/y/v2",
|
||||
|
||||
// If x/y/v2/z exists, use it unmodified.
|
||||
if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" {
|
||||
return path
|
||||
}
|
||||
|
||||
// Otherwise look for a go.mod supplying a version element.
|
||||
// Some version-like elements may appear in paths but not
|
||||
// be module versions; we skip over those to look for module
|
||||
// versions. For example the module m/v2 might have a
|
||||
// package m/v2/api/v1/foo.
|
||||
limit := len(path)
|
||||
for limit > 0 {
|
||||
i, j := findVersionElement(path[:limit])
|
||||
if i < 0 {
|
||||
return path
|
||||
}
|
||||
if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" {
|
||||
if mpath := goModPath(bp.Dir); mpath != "" {
|
||||
// Found a valid go.mod file, so we're stopping the search.
|
||||
// If the path is m/v2/p and we found m/go.mod that says
|
||||
// "module m/v2", then we return "m/p".
|
||||
if mpath == path[:j] {
|
||||
return path[:i] + path[j:]
|
||||
}
|
||||
// Otherwise just return the original path.
|
||||
// We didn't find anything worth rewriting,
|
||||
// and the go.mod indicates that we should
|
||||
// not consider parent directories.
|
||||
return path
|
||||
}
|
||||
}
|
||||
limit = i
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// hasGoFiles reports whether dir contains any files with names ending in .go.
|
||||
// For a vendor check we must exclude directories that contain no .go files.
|
||||
// Otherwise it is not possible to vendor just a/b/c and still import the
|
||||
@ -1118,7 +1308,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package
|
||||
if path == "C" {
|
||||
continue
|
||||
}
|
||||
p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor)
|
||||
p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
|
||||
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.Copy(),
|
||||
@ -1224,6 +1414,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package
|
||||
// GNU binutils flagfile specifiers, sometimes called "response files").
|
||||
// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
|
||||
// We accept leading . _ and / as likely in file system paths.
|
||||
// There is a copy of this function in cmd/compile/internal/gc/noder.go.
|
||||
func SafeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
|
@ -499,10 +499,10 @@ func runTest(cmd *base.Command, args []string) {
|
||||
for _, path := range p.Imports {
|
||||
deps[path] = true
|
||||
}
|
||||
for _, path := range p.Vendored(p.TestImports) {
|
||||
for _, path := range p.Resolve(p.TestImports) {
|
||||
deps[path] = true
|
||||
}
|
||||
for _, path := range p.Vendored(p.XTestImports) {
|
||||
for _, path := range p.Resolve(p.XTestImports) {
|
||||
deps[path] = true
|
||||
}
|
||||
}
|
||||
@ -715,8 +715,9 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
var imports, ximports []*load.Package
|
||||
var stk load.ImportStack
|
||||
stk.Push(p.ImportPath + " (test)")
|
||||
rawTestImports := str.StringList(p.TestImports)
|
||||
for i, path := range p.TestImports {
|
||||
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.UseVendor)
|
||||
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.ResolveImport)
|
||||
if p1.Error != nil {
|
||||
return nil, nil, nil, p1.Error
|
||||
}
|
||||
@ -742,8 +743,9 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
stk.Pop()
|
||||
stk.Push(p.ImportPath + "_test")
|
||||
pxtestNeedsPtest := false
|
||||
rawXTestImports := str.StringList(p.XTestImports)
|
||||
for i, path := range p.XTestImports {
|
||||
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.UseVendor)
|
||||
p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.ResolveImport)
|
||||
if p1.Error != nil {
|
||||
return nil, nil, nil, p1.Error
|
||||
}
|
||||
@ -810,8 +812,20 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
|
||||
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
|
||||
ptest.Internal.Target = ""
|
||||
ptest.Imports = str.StringList(p.Imports, p.TestImports)
|
||||
ptest.Internal.Imports = append(append([]*load.Package{}, p.Internal.Imports...), imports...)
|
||||
// Note: The preparation of the compiler import map requires that common
|
||||
// indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports
|
||||
// all line up (but RawImports can be shorter than the others).
|
||||
// That is, for 0 ≤ i < len(RawImports),
|
||||
// RawImports[i] is the import string in the program text,
|
||||
// Imports[i] is the expanded import string (vendoring applied or relative path expanded away),
|
||||
// and Internal.Imports[i] is the corresponding *Package.
|
||||
// Any implicitly added imports appear in Imports and Internal.Imports
|
||||
// but not RawImports (because they were not in the source code).
|
||||
// We insert TestImports, imports, and rawTestImports at the start of
|
||||
// these lists to preserve the alignment.
|
||||
ptest.Imports = str.StringList(p.TestImports, p.Imports)
|
||||
ptest.Internal.Imports = append(imports, p.Internal.Imports...)
|
||||
ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
|
||||
ptest.Internal.Pkgdir = testDir
|
||||
ptest.Internal.Fake = true
|
||||
ptest.Internal.ForceLibrary = true
|
||||
@ -857,6 +871,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
ImportPos: p.Internal.Build.XTestImportPos,
|
||||
},
|
||||
Imports: ximports,
|
||||
RawImports: rawXTestImports,
|
||||
Pkgdir: testDir,
|
||||
Fake: true,
|
||||
External: true,
|
||||
|
@ -1525,16 +1525,29 @@ func splitPkgConfigOutput(out []byte) []string {
|
||||
|
||||
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
|
||||
func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
|
||||
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
||||
if pcargs := p.CgoPkgConfig; len(pcargs) > 0 {
|
||||
// pkg-config permits arguments to appear anywhere in
|
||||
// the command line. Move them all to the front, before --.
|
||||
var pcflags []string
|
||||
var pkgs []string
|
||||
for _, pcarg := range pcargs {
|
||||
if pcarg == "--" {
|
||||
// We're going to add our own "--" argument.
|
||||
} else if strings.HasPrefix(pcarg, "--") {
|
||||
pcflags = append(pcflags, pcarg)
|
||||
} else {
|
||||
pkgs = append(pkgs, pcarg)
|
||||
}
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
if !load.SafeArg(pkg) {
|
||||
return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
|
||||
}
|
||||
}
|
||||
var out []byte
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", "--", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
|
||||
b.showOutput(p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
|
||||
b.Print(err.Error() + "\n")
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
@ -1544,15 +1557,15 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", "--", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
|
||||
b.showOutput(p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
|
||||
b.Print(err.Error() + "\n")
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
if len(out) > 0 {
|
||||
ldflags = strings.Fields(string(out))
|
||||
if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil {
|
||||
if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
@ -2249,11 +2262,10 @@ func (gcToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr b
|
||||
gcargs = append(gcargs, "-dwarf=false")
|
||||
}
|
||||
|
||||
for _, path := range p.Imports {
|
||||
if i := strings.LastIndex(path, "/vendor/"); i >= 0 {
|
||||
gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path)
|
||||
} else if strings.HasPrefix(path, "vendor/") {
|
||||
gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path)
|
||||
for i, raw := range p.Internal.RawImports {
|
||||
final := p.Imports[i]
|
||||
if final != raw {
|
||||
gcargs = append(gcargs, "-importmap", raw+"="+final)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,38 +34,95 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile
|
||||
|
||||
var validCompilerFlags = []*regexp.Regexp{
|
||||
re(`-D([A-Za-z_].*)`),
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-I([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-W`),
|
||||
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
|
||||
re(`-Wa,-mbig-obj`),
|
||||
re(`-Wp,-D([A-Za-z_].*)`),
|
||||
re(`-ansi`),
|
||||
re(`-f(no-)?asynchronous-unwind-tables`),
|
||||
re(`-f(no-)?blocks`),
|
||||
re(`-f(no-)builtin-[a-zA-Z0-9_]*`),
|
||||
re(`-f(no-)?common`),
|
||||
re(`-f(no-)?constant-cfstrings`),
|
||||
re(`-fdiagnostics-show-note-include-stack`),
|
||||
re(`-f(no-)?eliminate-unused-debug-types`),
|
||||
re(`-f(no-)?exceptions`),
|
||||
re(`-f(no-)?fast-math`),
|
||||
re(`-f(no-)?inline-functions`),
|
||||
re(`-finput-charset=([^@\-].*)`),
|
||||
re(`-f(no-)?fat-lto-objects`),
|
||||
re(`-f(no-)?keep-inline-dllexport`),
|
||||
re(`-f(no-)?lto`),
|
||||
re(`-fmacro-backtrace-limit=(.+)`),
|
||||
re(`-fmessage-length=(.+)`),
|
||||
re(`-f(no-)?modules`),
|
||||
re(`-f(no-)?objc-arc`),
|
||||
re(`-f(no-)?objc-nonfragile-abi`),
|
||||
re(`-f(no-)?objc-legacy-dispatch`),
|
||||
re(`-f(no-)?omit-frame-pointer`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-f(no-)?permissive`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?plt`),
|
||||
re(`-f(no-)?rtti`),
|
||||
re(`-f(no-)?split-stack`),
|
||||
re(`-f(no-)?stack-(.+)`),
|
||||
re(`-f(no-)?strict-aliasing`),
|
||||
re(`-f(un)signed-char`),
|
||||
re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
|
||||
re(`-f(no-)?visibility-inlines-hidden`),
|
||||
re(`-fsanitize=(.+)`),
|
||||
re(`-ftemplate-depth-(.+)`),
|
||||
re(`-fvisibility=(.+)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-m32`),
|
||||
re(`-m64`),
|
||||
re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-marm`),
|
||||
re(`-mfloat-abi=([^@\-].*)`),
|
||||
re(`-mfpmath=[0-9a-z,+]*`),
|
||||
re(`-m(no-)?avx[0-9a-z.]*`),
|
||||
re(`-m(no-)?ms-bitfields`),
|
||||
re(`-m(no-)?stack-(.+)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mios-simulator-version-min=(.+)`),
|
||||
re(`-miphoneos-version-min=(.+)`),
|
||||
re(`-mnop-fun-dllimport`),
|
||||
re(`-m(no-)?sse[0-9.]*`),
|
||||
re(`-mthumb(-interwork)?`),
|
||||
re(`-mthreads`),
|
||||
re(`-mwindows`),
|
||||
re(`--param=ssp-buffer-size=[0-9]*`),
|
||||
re(`-pedantic(-errors)?`),
|
||||
re(`-pipe`),
|
||||
re(`-pthread`),
|
||||
re(`-std=([^@\-].*)`),
|
||||
re(`-?-std=([^@\-].*)`),
|
||||
re(`-?-stdlib=([^@\-].*)`),
|
||||
re(`--sysroot=([^@\-].*)`),
|
||||
re(`-w`),
|
||||
re(`-x([^@\-].*)`),
|
||||
}
|
||||
|
||||
var validCompilerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-D",
|
||||
"-I",
|
||||
"-framework",
|
||||
"-isysroot",
|
||||
"-isystem",
|
||||
"--sysroot",
|
||||
"-target",
|
||||
"-x",
|
||||
}
|
||||
|
||||
@ -73,29 +130,76 @@ var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-l([^@\-].*)`),
|
||||
re(`-L([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-fsanitize=([^@\-].*)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-headerpad_max_install_names`),
|
||||
re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-mfloat-abi=([^@\-].*)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mios-simulator-version-min=(.+)`),
|
||||
re(`-miphoneos-version-min=(.+)`),
|
||||
re(`-mthreads`),
|
||||
re(`-mwindows`),
|
||||
re(`-(pic|PIC|pie|PIE)`),
|
||||
re(`-pthread`),
|
||||
re(`-rdynamic`),
|
||||
re(`-shared`),
|
||||
re(`-?-static([-a-z0-9+]*)`),
|
||||
re(`-?-stdlib=([^@\-].*)`),
|
||||
|
||||
// Note that any wildcards in -Wl need to exclude comma,
|
||||
// since -Wl splits its argument at commas and passes
|
||||
// them all to the linker uninterpreted. Allowing comma
|
||||
// in a wildcard would allow tunnelling arbitrary additional
|
||||
// linker arguments through one of these.
|
||||
re(`-Wl,-rpath,([^,@\-][^,]+)`),
|
||||
re(`-Wl,--(no-)?allow-multiple-definition`),
|
||||
re(`-Wl,--(no-)?allow-shlib-undefined`),
|
||||
re(`-Wl,--(no-)?as-needed`),
|
||||
re(`-Wl,-Bdynamic`),
|
||||
re(`-Wl,-Bstatic`),
|
||||
re(`-WL,-O([^@,\-][^,]*)?`),
|
||||
re(`-Wl,-d[ny]`),
|
||||
re(`-Wl,--disable-new-dtags`),
|
||||
re(`-Wl,-e[=,][a-zA-Z0-9]*`),
|
||||
re(`-Wl,--enable-new-dtags`),
|
||||
re(`-Wl,--end-group`),
|
||||
re(`-Wl,-framework,[^,@\-][^,]+`),
|
||||
re(`-Wl,-headerpad_max_install_names`),
|
||||
re(`-Wl,--no-undefined`),
|
||||
re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-s`),
|
||||
re(`-Wl,-search_paths_first`),
|
||||
re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
|
||||
re(`-Wl,--start-group`),
|
||||
re(`-Wl,-?-static`),
|
||||
re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
|
||||
re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
|
||||
re(`-Wl,-?-unresolved-symbols=[^,]+`),
|
||||
re(`-Wl,--(no-)?warn-([^,]+)`),
|
||||
re(`-Wl,-z,(no)?execstack`),
|
||||
re(`-Wl,-z,relro`),
|
||||
|
||||
re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
re(`\./.*\.(a|o|obj|dll|dylib|so)`),
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-arch",
|
||||
"-F",
|
||||
"-l",
|
||||
"-L",
|
||||
"-framework",
|
||||
"-isysroot",
|
||||
"--sysroot",
|
||||
"-target",
|
||||
"-Wl,-framework",
|
||||
"-Wl,-rpath",
|
||||
"-Wl,-undefined",
|
||||
}
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
@ -147,10 +251,21 @@ Args:
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1])
|
||||
|
||||
// Permit -Wl,-framework -Wl,name.
|
||||
if i+1 < len(list) &&
|
||||
strings.HasPrefix(arg, "-Wl,") &&
|
||||
strings.HasPrefix(list[i+1], "-Wl,") &&
|
||||
load.SafeArg(list[i+1][4:]) &&
|
||||
!strings.Contains(list[i+1][4:], ",") {
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument", source, arg)
|
||||
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1])
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg)
|
||||
}
|
||||
}
|
||||
Bad:
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
var goodCompilerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-F/Qt"},
|
||||
{"-I/"},
|
||||
{"-I/etc/passwd"},
|
||||
{"-I."},
|
||||
@ -62,6 +63,8 @@ var goodCompilerFlags = [][]string{
|
||||
var badCompilerFlags = [][]string{
|
||||
{"-D@X"},
|
||||
{"-D-X"},
|
||||
{"-F@dir"},
|
||||
{"-F-dir"},
|
||||
{"-I@dir"},
|
||||
{"-I-dir"},
|
||||
{"-O@1"},
|
||||
@ -125,6 +128,7 @@ var goodLinkerFlags = [][]string{
|
||||
{"-Wl,--no-warn-error"},
|
||||
{"foo.so"},
|
||||
{"_世界.dll"},
|
||||
{"./x.o"},
|
||||
{"libcgosotest.dylib"},
|
||||
{"-F", "framework"},
|
||||
{"-l", "."},
|
||||
@ -132,14 +136,14 @@ var goodLinkerFlags = [][]string{
|
||||
{"-l", "世界"},
|
||||
{"-L", "framework"},
|
||||
{"-framework", "Chocolate"},
|
||||
{"-Wl,-framework", "-Wl,Chocolate"},
|
||||
{"-Wl,-framework,Chocolate"},
|
||||
{"-Wl,-unresolved-symbols=ignore-all"},
|
||||
}
|
||||
|
||||
var badLinkerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-O"},
|
||||
{"-O2"},
|
||||
{"-Osmall"},
|
||||
{"-W"},
|
||||
{"-Wall"},
|
||||
{"-fobjc-arc"},
|
||||
@ -152,7 +156,6 @@ var badLinkerFlags = [][]string{
|
||||
{"-fno-stack-xxx"},
|
||||
{"-mstack-overflow"},
|
||||
{"-mno-stack-overflow"},
|
||||
{"-mmacosx-version"},
|
||||
{"-mnop-fun-dllimport"},
|
||||
{"-std=c99"},
|
||||
{"-xc"},
|
||||
@ -185,9 +188,14 @@ var badLinkerFlags = [][]string{
|
||||
{"-l", "-foo"},
|
||||
{"-framework", "-Caffeine"},
|
||||
{"-framework", "@Home"},
|
||||
{"-Wl,-framework,-Caffeine"},
|
||||
{"-Wl,-framework", "-Wl,@Home"},
|
||||
{"-Wl,-framework", "@Home"},
|
||||
{"-Wl,-framework,Chocolate,@Home"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
{"../x.o"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
|
1
src/cmd/go/testdata/modlegacy/src/new/go.mod
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/go.mod
vendored
Normal file
@ -0,0 +1 @@
|
||||
module "new/v2"
|
3
src/cmd/go/testdata/modlegacy/src/new/new.go
vendored
Normal file
3
src/cmd/go/testdata/modlegacy/src/new/new.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package new
|
||||
|
||||
import _ "new/v2/p2"
|
7
src/cmd/go/testdata/modlegacy/src/new/p1/p1.go
vendored
Normal file
7
src/cmd/go/testdata/modlegacy/src/new/p1/p1.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package p1
|
||||
|
||||
import _ "old/p2"
|
||||
import _ "new/v2"
|
||||
import _ "new/v2/p2"
|
||||
import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module
|
||||
import _ "new/sub/inner/x" // new/sub/inner/go.mod overrides new/sub/go.mod
|
1
src/cmd/go/testdata/modlegacy/src/new/p2/p2.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/p2/p2.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package p2
|
1
src/cmd/go/testdata/modlegacy/src/new/sub/go.mod
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/go.mod
vendored
Normal file
@ -0,0 +1 @@
|
||||
module new/sub/v2
|
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod
vendored
Normal file
@ -0,0 +1 @@
|
||||
module new/sub/inner
|
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package x
|
1
src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package y
|
5
src/cmd/go/testdata/modlegacy/src/old/p1/p1.go
vendored
Normal file
5
src/cmd/go/testdata/modlegacy/src/old/p1/p1.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package p1
|
||||
|
||||
import _ "old/p2"
|
||||
import _ "new/p1"
|
||||
import _ "new"
|
1
src/cmd/go/testdata/modlegacy/src/old/p2/p2.go
vendored
Normal file
1
src/cmd/go/testdata/modlegacy/src/old/p2/p2.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package p2
|
@ -10,6 +10,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -327,3 +328,75 @@ func TestVendor12156(t *testing.T) {
|
||||
tg.grepStderrNot("panic", "panicked")
|
||||
tg.grepStderr(`cannot find package "x"`, "wrong error")
|
||||
}
|
||||
|
||||
// Module legacy support does path rewriting very similar to vendoring.
|
||||
|
||||
func TestModLegacy(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy"))
|
||||
tg.run("list", "-f", "{{.Imports}}", "old/p1")
|
||||
tg.grepStdout("new/p1", "old/p1 should import new/p1")
|
||||
tg.run("list", "-f", "{{.Imports}}", "new/p1")
|
||||
tg.grepStdout("new/p2", "new/p1 should import new/p2 (not new/v2/p2)")
|
||||
tg.grepStdoutNot("new/v2", "new/p1 should NOT import new/v2*")
|
||||
tg.grepStdout("new/sub/x/v1/y", "new/p1 should import new/sub/x/v1/y (not new/sub/v2/x/v1/y)")
|
||||
tg.grepStdoutNot("new/sub/v2", "new/p1 should NOT import new/sub/v2*")
|
||||
tg.grepStdout("new/sub/inner/x", "new/p1 should import new/sub/inner/x (no rewrites)")
|
||||
tg.run("build", "old/p1", "new/p1")
|
||||
}
|
||||
|
||||
func TestModLegacyGet(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.makeTempdir()
|
||||
tg.setenv("GOPATH", tg.path("d1"))
|
||||
tg.run("get", "vcs-test.golang.org/git/modlegacy1-old.git/p1")
|
||||
tg.run("list", "-f", "{{.Deps}}", "vcs-test.golang.org/git/modlegacy1-old.git/p1")
|
||||
tg.grepStdout("new.git/p2", "old/p1 should depend on new/p2")
|
||||
tg.grepStdoutNot("new.git/v2/p2", "old/p1 should NOT depend on new/v2/p2")
|
||||
tg.run("build", "vcs-test.golang.org/git/modlegacy1-old.git/p1", "vcs-test.golang.org/git/modlegacy1-new.git/p1")
|
||||
|
||||
tg.setenv("GOPATH", tg.path("d2"))
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest5")
|
||||
tg.run("get", "github.com/rsc/vgotest4")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest4")
|
||||
tg.run("get", "github.com/rsc/vgotest5")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/rsc/vgotest5", "github.com/rsc/vgotest4")
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", "github.com/myitcv/vgo_example_compat")
|
||||
tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5")
|
||||
|
||||
pkgs := []string{"github.com/myitcv/vgo_example_compat", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5"}
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
for k := 0; k < 3; k++ {
|
||||
if i == j || i == k || k == j {
|
||||
continue
|
||||
}
|
||||
tg.must(os.RemoveAll(tg.path("d2")))
|
||||
tg.run("get", pkgs[i], pkgs[j], pkgs[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,12 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
|
||||
return nil
|
||||
}
|
||||
|
||||
type _CertChainPolicyPara struct {
|
||||
Size uint32
|
||||
Flags uint32
|
||||
ExtraPolicyPara unsafe.Pointer
|
||||
}
|
||||
|
||||
// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
|
||||
// use as a certificate chain for a SSL/TLS server.
|
||||
func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
|
||||
@ -108,13 +114,13 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
|
||||
}
|
||||
sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
|
||||
|
||||
para := &syscall.CertChainPolicyPara{
|
||||
ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
|
||||
para := &_CertChainPolicyPara{
|
||||
ExtraPolicyPara: unsafe.Pointer(sslPara),
|
||||
}
|
||||
para.Size = uint32(unsafe.Sizeof(*para))
|
||||
|
||||
status := syscall.CertChainPolicyStatus{}
|
||||
err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
|
||||
err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, (*syscall.CertChainPolicyPara)(unsafe.Pointer(para)), &status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ func init() {
|
||||
// command line, with arguments separated by NUL bytes.
|
||||
// The package initialization registers it as /debug/pprof/cmdline.
|
||||
func Cmdline(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
|
||||
}
|
||||
@ -100,33 +101,36 @@ func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool {
|
||||
return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds()
|
||||
}
|
||||
|
||||
func serveError(w http.ResponseWriter, status int, txt string) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.Header().Del("Content-Disposition")
|
||||
w.WriteHeader(status)
|
||||
fmt.Fprintln(w, txt)
|
||||
}
|
||||
|
||||
// Profile responds with the pprof-formatted cpu profile.
|
||||
// The package initialization registers it as /debug/pprof/profile.
|
||||
func Profile(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
|
||||
if sec == 0 {
|
||||
sec = 30
|
||||
}
|
||||
|
||||
if durationExceedsWriteTimeout(r, float64(sec)) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
|
||||
serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout")
|
||||
return
|
||||
}
|
||||
|
||||
// Set Content Type assuming StartCPUProfile will work,
|
||||
// because if it does it starts writing.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="profile"`)
|
||||
if err := pprof.StartCPUProfile(w); err != nil {
|
||||
// StartCPUProfile failed, so no writes yet.
|
||||
// Can change header back to text content
|
||||
// and send error code.
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
|
||||
serveError(w, http.StatusInternalServerError,
|
||||
fmt.Sprintf("Could not enable CPU profiling: %s", err))
|
||||
return
|
||||
}
|
||||
sleep(w, time.Duration(sec)*time.Second)
|
||||
@ -137,29 +141,25 @@ func Profile(w http.ResponseWriter, r *http.Request) {
|
||||
// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
|
||||
// The package initialization registers it as /debug/pprof/trace.
|
||||
func Trace(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
|
||||
if sec <= 0 || err != nil {
|
||||
sec = 1
|
||||
}
|
||||
|
||||
if durationExceedsWriteTimeout(r, sec) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
|
||||
serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout")
|
||||
return
|
||||
}
|
||||
|
||||
// Set Content Type assuming trace.Start will work,
|
||||
// because if it does it starts writing.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="trace"`)
|
||||
if err := trace.Start(w); err != nil {
|
||||
// trace.Start failed, so no writes yet.
|
||||
// Can change header back to text content and send error code.
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("X-Go-Pprof", "1")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
|
||||
serveError(w, http.StatusInternalServerError,
|
||||
fmt.Sprintf("Could not enable tracing: %s", err))
|
||||
return
|
||||
}
|
||||
sleep(w, time.Duration(sec*float64(time.Second)))
|
||||
@ -170,6 +170,7 @@ func Trace(w http.ResponseWriter, r *http.Request) {
|
||||
// responding with a table mapping program counters to function names.
|
||||
// The package initialization registers it as /debug/pprof/symbol.
|
||||
func Symbol(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
|
||||
// We have to read the whole POST body before
|
||||
@ -222,18 +223,23 @@ func Handler(name string) http.Handler {
|
||||
type handler string
|
||||
|
||||
func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
debug, _ := strconv.Atoi(r.FormValue("debug"))
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
p := pprof.Lookup(string(name))
|
||||
if p == nil {
|
||||
w.WriteHeader(404)
|
||||
fmt.Fprintf(w, "Unknown profile: %s\n", name)
|
||||
serveError(w, http.StatusNotFound, "Unknown profile")
|
||||
return
|
||||
}
|
||||
gc, _ := strconv.Atoi(r.FormValue("gc"))
|
||||
if name == "heap" && gc > 0 {
|
||||
runtime.GC()
|
||||
}
|
||||
debug, _ := strconv.Atoi(r.FormValue("debug"))
|
||||
if debug != 0 {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
|
||||
}
|
||||
p.WriteTo(w, debug)
|
||||
}
|
||||
|
||||
|
69
src/net/http/pprof/pprof_test.go
Normal file
69
src/net/http/pprof/pprof_test.go
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2018 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 pprof
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandlers(t *testing.T) {
|
||||
testCases := []struct {
|
||||
path string
|
||||
handler http.HandlerFunc
|
||||
statusCode int
|
||||
contentType string
|
||||
contentDisposition string
|
||||
resp []byte
|
||||
}{
|
||||
{"/debug/pprof/<script>scripty<script>", Index, http.StatusNotFound, "text/plain; charset=utf-8", "", []byte("Unknown profile\n")},
|
||||
{"/debug/pprof/heap", Index, http.StatusOK, "application/octet-stream", `attachment; filename="heap"`, nil},
|
||||
{"/debug/pprof/heap?debug=1", Index, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/cmdline", Cmdline, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/profile?seconds=1", Profile, http.StatusOK, "application/octet-stream", `attachment; filename="profile"`, nil},
|
||||
{"/debug/pprof/symbol", Symbol, http.StatusOK, "text/plain; charset=utf-8", "", nil},
|
||||
{"/debug/pprof/trace", Trace, http.StatusOK, "application/octet-stream", `attachment; filename="trace"`, nil},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com"+tc.path, nil)
|
||||
w := httptest.NewRecorder()
|
||||
tc.handler(w, req)
|
||||
|
||||
resp := w.Result()
|
||||
if got, want := resp.StatusCode, tc.statusCode; got != want {
|
||||
t.Errorf("status code: got %d; want %d", got, want)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("when reading response body, expected non-nil err; got %v", err)
|
||||
}
|
||||
if got, want := resp.Header.Get("X-Content-Type-Options"), "nosniff"; got != want {
|
||||
t.Errorf("X-Content-Type-Options: got %q; want %q", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("Content-Type"), tc.contentType; got != want {
|
||||
t.Errorf("Content-Type: got %q; want %q", got, want)
|
||||
}
|
||||
if got, want := resp.Header.Get("Content-Disposition"), tc.contentDisposition; got != want {
|
||||
t.Errorf("Content-Disposition: got %q; want %q", got, want)
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return
|
||||
}
|
||||
if got, want := resp.Header.Get("X-Go-Pprof"), "1"; got != want {
|
||||
t.Errorf("X-Go-Pprof: got %q; want %q", got, want)
|
||||
}
|
||||
if !bytes.Equal(body, tc.resp) {
|
||||
t.Errorf("response: got %q; want %q", body, tc.resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -523,7 +523,7 @@ func Map(mapping func(rune) rune, s string) string {
|
||||
b = make([]byte, len(s)+utf8.UTFMax)
|
||||
nbytes = copy(b, s[:i])
|
||||
if r >= 0 {
|
||||
if r <= utf8.RuneSelf {
|
||||
if r < utf8.RuneSelf {
|
||||
b[nbytes] = byte(r)
|
||||
nbytes++
|
||||
} else {
|
||||
@ -553,7 +553,7 @@ func Map(mapping func(rune) rune, s string) string {
|
||||
r := mapping(c)
|
||||
|
||||
// common case
|
||||
if (0 <= r && r <= utf8.RuneSelf) && nbytes < len(b) {
|
||||
if (0 <= r && r < utf8.RuneSelf) && nbytes < len(b) {
|
||||
b[nbytes] = byte(r)
|
||||
nbytes++
|
||||
continue
|
||||
|
@ -522,6 +522,7 @@ var upperTests = []StringTest{
|
||||
{"AbC123", "ABC123"},
|
||||
{"azAZ09_", "AZAZ09_"},
|
||||
{"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
|
||||
{"a\u0080\U0010FFFF", "A\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune
|
||||
}
|
||||
|
||||
var lowerTests = []StringTest{
|
||||
@ -530,6 +531,7 @@ var lowerTests = []StringTest{
|
||||
{"AbC123", "abc123"},
|
||||
{"azAZ09_", "azaz09_"},
|
||||
{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
|
||||
{"A\u0080\U0010FFFF", "a\u0080\U0010FFFF"}, // test utf8.RuneSelf and utf8.MaxRune
|
||||
}
|
||||
|
||||
const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
|
||||
@ -642,6 +644,27 @@ func TestMap(t *testing.T) {
|
||||
if m != expect {
|
||||
t.Errorf("replace invalid sequence: expected %q got %q", expect, m)
|
||||
}
|
||||
|
||||
// 8. Check utf8.RuneSelf and utf8.MaxRune encoding
|
||||
encode := func(r rune) rune {
|
||||
switch r {
|
||||
case utf8.RuneSelf:
|
||||
return unicode.MaxRune
|
||||
case unicode.MaxRune:
|
||||
return utf8.RuneSelf
|
||||
}
|
||||
return r
|
||||
}
|
||||
s := string(utf8.RuneSelf) + string(utf8.MaxRune)
|
||||
r := string(utf8.MaxRune) + string(utf8.RuneSelf) // reverse of s
|
||||
m = Map(encode, s)
|
||||
if m != r {
|
||||
t.Errorf("encoding not handled correctly: expected %q got %q", r, m)
|
||||
}
|
||||
m = Map(encode, r)
|
||||
if m != s {
|
||||
t.Errorf("encoding not handled correctly: expected %q got %q", s, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
|
||||
|
42
test/fixedbugs/issue23719.go
Normal file
42
test/fixedbugs/issue23719.go
Normal file
@ -0,0 +1,42 @@
|
||||
// run
|
||||
|
||||
// Copyright 2018 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
|
||||
|
||||
func main() {
|
||||
v1 := [2]int32{-1, 88}
|
||||
v2 := [2]int32{-1, 99}
|
||||
if v1 == v2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
|
||||
w1 := [2]int16{-1, 88}
|
||||
w2 := [2]int16{-1, 99}
|
||||
if w1 == w2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
x1 := [4]int16{-1, 88, 88, 88}
|
||||
x2 := [4]int16{-1, 99, 99, 99}
|
||||
if x1 == x2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
|
||||
a1 := [2]int8{-1, 88}
|
||||
a2 := [2]int8{-1, 99}
|
||||
if a1 == a2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
b1 := [4]int8{-1, 88, 88, 88}
|
||||
b2 := [4]int8{-1, 99, 99, 99}
|
||||
if b1 == b2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
c1 := [8]int8{-1, 88, 88, 88, 88, 88, 88, 88}
|
||||
c2 := [8]int8{-1, 99, 99, 99, 99, 99, 99, 99}
|
||||
if c1 == c2 {
|
||||
panic("bad comparison")
|
||||
}
|
||||
}
|
34
test/fixedbugs/issue23812.go
Normal file
34
test/fixedbugs/issue23812.go
Normal file
@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// Copyright 2018 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 "fmt"
|
||||
|
||||
func main() {
|
||||
want := int32(0x3edae8)
|
||||
got := foo(1)
|
||||
if want != got {
|
||||
panic(fmt.Sprintf("want %x, got %x", want, got))
|
||||
}
|
||||
}
|
||||
|
||||
func foo(a int32) int32 {
|
||||
return shr1(int32(shr2(int64(0x14ff6e2207db5d1f), int(a))), 4)
|
||||
}
|
||||
|
||||
func shr1(n int32, m int) int32 { return n >> uint(m) }
|
||||
|
||||
func shr2(n int64, m int) int64 {
|
||||
if m < 0 {
|
||||
m = -m
|
||||
}
|
||||
if m >= 64 {
|
||||
return n
|
||||
}
|
||||
|
||||
return n >> uint(m)
|
||||
}
|
64
test/fixedbugs/issue24817.go
Normal file
64
test/fixedbugs/issue24817.go
Normal file
@ -0,0 +1,64 @@
|
||||
// run
|
||||
|
||||
// Copyright 2018 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 all ways to compare a non-constant string to the empty string.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
s = "abc"
|
||||
e = ""
|
||||
failed bool
|
||||
)
|
||||
|
||||
func main() {
|
||||
want(true, "" < s, `"" < s`)
|
||||
want(false, s < "", `s < ""`)
|
||||
want(false, "" < e, `"" < e`)
|
||||
want(false, e < "", `e < ""`)
|
||||
|
||||
want(true, "" <= s, `"" <= s`)
|
||||
want(false, s <= "", `s <= ""`)
|
||||
want(true, "" <= e, `"" <= e`)
|
||||
want(true, e <= "", `e <= ""`)
|
||||
|
||||
want(false, "" > s, `"" > s`)
|
||||
want(true, s > "", `s > ""`)
|
||||
want(false, "" > e, `"" > e`)
|
||||
want(false, e > "", `e > ""`)
|
||||
|
||||
want(false, "" >= s, `"" >= s`)
|
||||
want(true, s >= "", `s >= ""`)
|
||||
want(true, "" >= e, `"" >= e`)
|
||||
want(true, e >= "", `e >= ""`)
|
||||
|
||||
want(false, "" == s, `"" == s`)
|
||||
want(false, s == "", `s == ""`)
|
||||
want(true, "" == e, `"" == e`)
|
||||
want(true, e == "", `e == ""`)
|
||||
|
||||
want(true, "" != s, `"" != s`)
|
||||
want(true, s != "", `s != ""`)
|
||||
want(false, "" != e, `"" != e`)
|
||||
want(false, e != "", `e != ""`)
|
||||
|
||||
if failed {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func want(b bool, have bool, msg string) {
|
||||
if b != have {
|
||||
fmt.Println(msg)
|
||||
failed = true
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user