aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/mips64/ssa.go5
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM.rules4
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64.rules10
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64Ops.go4
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARMOps.go2
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM.go144
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM64.go160
-rw-r--r--src/cmd/go/internal/modfetch/coderepo.go216
-rw-r--r--src/cmd/go/internal/modfetch/coderepo_test.go301
-rw-r--r--src/cmd/go/internal/vcs/vcs.go54
-rw-r--r--src/cmd/go/internal/vcs/vcs_test.go7
-rw-r--r--src/cmd/go/testdata/script/mod_invalid_version.txt10
-rw-r--r--src/cmd/link/internal/ld/lib.go5
13 files changed, 301 insertions, 621 deletions
diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go
index 2727c4d8a8..b0e0165ad8 100644
--- a/src/cmd/compile/internal/mips64/ssa.go
+++ b/src/cmd/compile/internal/mips64/ssa.go
@@ -321,7 +321,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg {
a = a.Args[0]
}
- if a.Op == ssa.OpLoadReg {
+ if a.Op == ssa.OpLoadReg && mips.REG_R0 <= a.Reg() && a.Reg() <= mips.REG_R31 {
+ // LoadReg from a narrower type does an extension, except loading
+ // to a floating point register. So only eliminate the extension
+ // if it is loaded to an integer register.
t := a.Type
switch {
case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(),
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index 69989b0c45..2a30f9c342 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -1263,8 +1263,8 @@
(SRLconst (SLLconst x [c]) [d]) && objabi.GOARM==7 && uint64(d)>=uint64(c) && uint64(d)<=31 => (BFXU [(d-c)|(32-d)<<8] x)
// comparison simplification
-((LT|LE|EQ|NE|GE|GT) (CMP x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMN x y)) // sense of carry bit not preserved
-((LT|LE|EQ|NE|GE|GT) (CMN x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMP x y)) // sense of carry bit not preserved
+((EQ|NE) (CMP x (RSBconst [0] y))) => ((EQ|NE) (CMN x y)) // sense of carry bit not preserved; see also #50854
+((EQ|NE) (CMN x (RSBconst [0] y))) => ((EQ|NE) (CMP x y)) // sense of carry bit not preserved; see also #50864
(EQ (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (EQ (CMP x y) yes no)
(EQ (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (EQ (CMP a (MUL <x.Type> x y)) yes no)
(EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (EQ (CMPconst [c] x) yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 80b4005df1..3c66494ab5 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -643,19 +643,13 @@
(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMNW x y) yes no)
(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMNW x y) yes no)
+// CMP(x,-y) -> CMN(x,y) is only valid for unordered comparison, if y can be -1<<63
(EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
(NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
-(LT (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (LT (CMN x y) yes no)
-(LE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (LE (CMN x y) yes no)
-(GT (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (GT (CMN x y) yes no)
-(GE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (GE (CMN x y) yes no)
+// CMPW(x,-y) -> CMNW(x,y) is only valid for unordered comparison, if y can be -1<<31
(EQ (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMNW x y) yes no)
(NE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMNW x y) yes no)
-(LT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (LT (CMNW x y) yes no)
-(LE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (LE (CMNW x y) yes no)
-(GT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (GT (CMNW x y) yes no)
-(GE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (GE (CMNW x y) yes no)
(EQ (CMPconst [0] x) yes no) => (Z x yes no)
(NE (CMPconst [0] x) yes no) => (NZ x yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index 4d1d14e18b..fc3dcce629 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -281,9 +281,9 @@ func init() {
{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to auxInt
{name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1, 32 bit
{name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit
- {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1
+ {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1, provided arg1 is not 1<<63
{name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"}, // arg0 compare to -auxInt
- {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit
+ {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit, provided arg1 is not 1<<31
{name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit
{name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0
{name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int64", typ: "Flags"}, // arg0 & auxInt compare to 0
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
index 1a7eefa50a..7516c4ffe9 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -329,7 +329,7 @@ func init() {
// comparisons
{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt
- {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1
+ {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1, provided arg1 is not 1<<63
{name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt
{name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0
{name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int32", typ: "Flags"}, // arg0 & auxInt compare to 0
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 1f25005eb7..8da5b40cf5 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -17123,42 +17123,6 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMLE, cmp)
return true
}
- // match: (GE (CMP x (RSBconst [0] y)))
- // result: (GE (CMN x y))
- for b.Controls[0].Op == OpARMCMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- break
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
- return true
- }
- // match: (GE (CMN x (RSBconst [0] y)))
- // result: (GE (CMP x y))
- for b.Controls[0].Op == OpARMCMN {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- v_0_0 := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
- x := v_0_0
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- continue
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
- return true
- }
- break
- }
// match: (GE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (GEnoov (CMP x y) yes no)
@@ -18039,42 +18003,6 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMLT, cmp)
return true
}
- // match: (GT (CMP x (RSBconst [0] y)))
- // result: (GT (CMN x y))
- for b.Controls[0].Op == OpARMCMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- break
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
- return true
- }
- // match: (GT (CMN x (RSBconst [0] y)))
- // result: (GT (CMP x y))
- for b.Controls[0].Op == OpARMCMN {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- v_0_0 := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
- x := v_0_0
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- continue
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
- return true
- }
- break
- }
// match: (GT (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (GTnoov (CMP x y) yes no)
@@ -19046,42 +18974,6 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGE, cmp)
return true
}
- // match: (LE (CMP x (RSBconst [0] y)))
- // result: (LE (CMN x y))
- for b.Controls[0].Op == OpARMCMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- break
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
- return true
- }
- // match: (LE (CMN x (RSBconst [0] y)))
- // result: (LE (CMP x y))
- for b.Controls[0].Op == OpARMCMN {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- v_0_0 := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
- x := v_0_0
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- continue
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
- return true
- }
- break
- }
// match: (LE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (LEnoov (CMP x y) yes no)
@@ -19962,42 +19854,6 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGT, cmp)
return true
}
- // match: (LT (CMP x (RSBconst [0] y)))
- // result: (LT (CMN x y))
- for b.Controls[0].Op == OpARMCMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- break
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
- return true
- }
- // match: (LT (CMN x (RSBconst [0] y)))
- // result: (LT (CMP x y))
- for b.Controls[0].Op == OpARMCMN {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- v_0_0 := v_0.Args[0]
- v_0_1 := v_0.Args[1]
- for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
- x := v_0_0
- if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
- continue
- }
- y := v_0_1.Args[0]
- v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
- return true
- }
- break
- }
// match: (LT (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (LTnoov (CMP x y) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index e61d89992d..5afccf163d 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -26214,46 +26214,6 @@ func rewriteBlockARM64(b *Block) bool {
}
break
}
- // match: (GE (CMP x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (GE (CMN x y) yes no)
- for b.Controls[0].Op == OpARM64CMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GE, v0)
- return true
- }
- // match: (GE (CMPW x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (GE (CMNW x y) yes no)
- for b.Controls[0].Op == OpARM64CMPW {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GE, v0)
- return true
- }
// match: (GE (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
// result: (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
@@ -26650,46 +26610,6 @@ func rewriteBlockARM64(b *Block) bool {
}
break
}
- // match: (GT (CMP x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (GT (CMN x y) yes no)
- for b.Controls[0].Op == OpARM64CMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GT, v0)
- return true
- }
- // match: (GT (CMPW x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (GT (CMNW x y) yes no)
- for b.Controls[0].Op == OpARM64CMPW {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GT, v0)
- return true
- }
// match: (GT (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
// result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
@@ -27182,46 +27102,6 @@ func rewriteBlockARM64(b *Block) bool {
}
break
}
- // match: (LE (CMP x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (LE (CMN x y) yes no)
- for b.Controls[0].Op == OpARM64CMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LE, v0)
- return true
- }
- // match: (LE (CMPW x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (LE (CMNW x y) yes no)
- for b.Controls[0].Op == OpARM64CMPW {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LE, v0)
- return true
- }
// match: (LE (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
// result: (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
@@ -27594,46 +27474,6 @@ func rewriteBlockARM64(b *Block) bool {
}
break
}
- // match: (LT (CMP x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (LT (CMN x y) yes no)
- for b.Controls[0].Op == OpARM64CMP {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LT, v0)
- return true
- }
- // match: (LT (CMPW x z:(NEG y)) yes no)
- // cond: z.Uses == 1
- // result: (LT (CMNW x y) yes no)
- for b.Controls[0].Op == OpARM64CMPW {
- v_0 := b.Controls[0]
- _ = v_0.Args[1]
- x := v_0.Args[0]
- z := v_0.Args[1]
- if z.Op != OpARM64NEG {
- break
- }
- y := z.Args[0]
- if !(z.Uses == 1) {
- break
- }
- v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
- v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LT, v0)
- return true
- }
// match: (LT (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
// result: (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
index 2dcbb99b18..db7496faf6 100644
--- a/src/cmd/go/internal/modfetch/coderepo.go
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -298,16 +298,13 @@ func (r *codeRepo) Latest() (*RevInfo, error) {
// If statVers is a valid module version, it is used for the Version field.
// Otherwise, the Version is derived from the passed-in info and recent tags.
func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) {
- info2 := &RevInfo{
- Name: info.Name,
- Short: info.Short,
- Time: info.Time,
- }
-
// If this is a plain tag (no dir/ prefix)
// and the module path is unversioned,
// and if the underlying file tree has no go.mod,
// then allow using the tag with a +incompatible suffix.
+ //
+ // (If the version is +incompatible, then the go.mod file must not exist:
+ // +incompatible is not an ongoing opt-out from semantic import versioning.)
var canUseIncompatible func() bool
canUseIncompatible = func() bool {
var ok bool
@@ -321,19 +318,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
return ok
}
- invalidf := func(format string, args ...interface{}) error {
- return &module.ModuleError{
- Path: r.modPath,
- Err: &module.InvalidVersionError{
- Version: info2.Version,
- Err: fmt.Errorf(format, args...),
- },
- }
- }
-
- // checkGoMod verifies that the go.mod file for the module exists or does not
- // exist as required by info2.Version and the module path represented by r.
- checkGoMod := func() (*RevInfo, error) {
+ // checkCanonical verifies that the canonical version v is compatible with the
+ // module path represented by r, adding a "+incompatible" suffix if needed.
+ //
+ // If statVers is also canonical, checkCanonical also verifies that v is
+ // either statVers or statVers with the added "+incompatible" suffix.
+ checkCanonical := func(v string) (*RevInfo, error) {
// If r.codeDir is non-empty, then the go.mod file must exist: the module
// author — not the module consumer, — gets to decide how to carve up the repo
// into modules.
@@ -344,73 +334,91 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
// r.findDir verifies both of these conditions. Execute it now so that
// r.Stat will correctly return a notExistError if the go.mod location or
// declared module path doesn't match.
- _, _, _, err := r.findDir(info2.Version)
+ _, _, _, err := r.findDir(v)
if err != nil {
// TODO: It would be nice to return an error like "not a module".
// Right now we return "missing go.mod", which is a little confusing.
return nil, &module.ModuleError{
Path: r.modPath,
Err: &module.InvalidVersionError{
- Version: info2.Version,
+ Version: v,
Err: notExistError{err: err},
},
}
}
- // If the version is +incompatible, then the go.mod file must not exist:
- // +incompatible is not an ongoing opt-out from semantic import versioning.
- if strings.HasSuffix(info2.Version, "+incompatible") {
- if !canUseIncompatible() {
+ invalidf := func(format string, args ...interface{}) error {
+ return &module.ModuleError{
+ Path: r.modPath,
+ Err: &module.InvalidVersionError{
+ Version: v,
+ Err: fmt.Errorf(format, args...),
+ },
+ }
+ }
+
+ // Add the +incompatible suffix if needed or requested explicitly, and
+ // verify that its presence or absence is appropriate for this version
+ // (which depends on whether it has an explicit go.mod file).
+
+ if v == strings.TrimSuffix(statVers, "+incompatible") {
+ v = statVers
+ }
+ base := strings.TrimSuffix(v, "+incompatible")
+ var errIncompatible error
+ if !module.MatchPathMajor(base, r.pathMajor) {
+ if canUseIncompatible() {
+ v = base + "+incompatible"
+ } else {
if r.pathMajor != "" {
- return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match")
+ errIncompatible = invalidf("module path includes a major version suffix, so major version must match")
} else {
- return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required")
+ errIncompatible = invalidf("module contains a go.mod file, so module path must match major version (%q)", path.Join(r.pathPrefix, semver.Major(v)))
}
}
+ } else if strings.HasSuffix(v, "+incompatible") {
+ errIncompatible = invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(v))
+ }
- if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil {
- return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version))
+ if statVers != "" && statVers == module.CanonicalVersion(statVers) {
+ // Since the caller-requested version is canonical, it would be very
+ // confusing to resolve it to anything but itself, possibly with a
+ // "+incompatible" suffix. Error out explicitly.
+ if statBase := strings.TrimSuffix(statVers, "+incompatible"); statBase != base {
+ return nil, &module.ModuleError{
+ Path: r.modPath,
+ Err: &module.InvalidVersionError{
+ Version: statVers,
+ Err: fmt.Errorf("resolves to version %v (%s is not a tag)", v, statBase),
+ },
+ }
}
}
- return info2, nil
+ if errIncompatible != nil {
+ return nil, errIncompatible
+ }
+
+ return &RevInfo{
+ Name: info.Name,
+ Short: info.Short,
+ Time: info.Time,
+ Version: v,
+ }, nil
}
// Determine version.
- //
- // If statVers is canonical, then the original call was repo.Stat(statVers).
- // Since the version is canonical, we must not resolve it to anything but
- // itself, possibly with a '+incompatible' annotation: we do not need to do
- // the work required to look for an arbitrary pseudo-version.
- if statVers != "" && statVers == module.CanonicalVersion(statVers) {
- info2.Version = statVers
-
- if IsPseudoVersion(info2.Version) {
- if err := r.validatePseudoVersion(info, info2.Version); err != nil {
- return nil, err
- }
- return checkGoMod()
- }
- if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil {
- if canUseIncompatible() {
- info2.Version += "+incompatible"
- return checkGoMod()
- } else {
- if vErr, ok := err.(*module.InvalidVersionError); ok {
- // We're going to describe why the version is invalid in more detail,
- // so strip out the existing “invalid version” wrapper.
- err = vErr.Err
- }
- return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err)
- }
+ if IsPseudoVersion(statVers) {
+ if err := r.validatePseudoVersion(info, statVers); err != nil {
+ return nil, err
}
-
- return checkGoMod()
+ return checkCanonical(statVers)
}
- // statVers is empty or non-canonical, so we need to resolve it to a canonical
- // version or pseudo-version.
+ // statVers is not a pseudo-version, so we need to either resolve it to a
+ // canonical version or verify that it is already a canonical tag
+ // (not a branch).
// Derive or verify a version from a code repo tag.
// Tag must have a prefix matching codeDir.
@@ -441,71 +449,62 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
if v == "" || !strings.HasPrefix(trimmed, v) {
return "", false // Invalid or incomplete version (just vX or vX.Y).
}
- if isRetracted(v) {
- return "", false
- }
if v == trimmed {
tagIsCanonical = true
}
-
- if err := module.CheckPathMajor(v, r.pathMajor); err != nil {
- if canUseIncompatible() {
- return v + "+incompatible", tagIsCanonical
- }
- return "", false
- }
-
return v, tagIsCanonical
}
// If the VCS gave us a valid version, use that.
if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical {
- info2.Version = v
- return checkGoMod()
+ if info, err := checkCanonical(v); err == nil {
+ return info, err
+ }
}
// Look through the tags on the revision for either a usable canonical version
// or an appropriate base for a pseudo-version.
- var pseudoBase string
+ var (
+ highestCanonical string
+ pseudoBase string
+ )
for _, pathTag := range info.Tags {
v, tagIsCanonical := tagToVersion(pathTag)
- if tagIsCanonical {
- if statVers != "" && semver.Compare(v, statVers) == 0 {
- // The user requested a non-canonical version, but the tag for the
- // canonical equivalent refers to the same revision. Use it.
- info2.Version = v
- return checkGoMod()
+ if statVers != "" && semver.Compare(v, statVers) == 0 {
+ // The tag is equivalent to the version requested by the user.
+ if tagIsCanonical {
+ // This tag is the canonical form of the requested version,
+ // not some other form with extra build metadata.
+ // Use this tag so that the resolved version will match exactly.
+ // (If it isn't actually allowed, we'll error out in checkCanonical.)
+ return checkCanonical(v)
} else {
- // Save the highest canonical tag for the revision. If we don't find a
- // better match, we'll use it as the canonical version.
+ // The user explicitly requested something equivalent to this tag. We
+ // can't use the version from the tag directly: since the tag is not
+ // canonical, it could be ambiguous. For example, tags v0.0.1+a and
+ // v0.0.1+b might both exist and refer to different revisions.
//
- // NOTE: Do not replace this with semver.Max. Despite the name,
- // semver.Max *also* canonicalizes its arguments, which uses
- // semver.Canonical instead of module.CanonicalVersion and thereby
- // strips our "+incompatible" suffix.
- if semver.Compare(info2.Version, v) < 0 {
- info2.Version = v
- }
+ // The tag is otherwise valid for the module, so we can at least use it as
+ // the base of an unambiguous pseudo-version.
+ //
+ // If multiple tags match, tagToVersion will canonicalize them to the same
+ // base version.
+ pseudoBase = v
+ }
+ }
+ // Save the highest non-retracted canonical tag for the revision.
+ // If we don't find a better match, we'll use it as the canonical version.
+ if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) {
+ if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() {
+ highestCanonical = v
}
- } else if v != "" && semver.Compare(v, statVers) == 0 {
- // The user explicitly requested something equivalent to this tag. We
- // can't use the version from the tag directly: since the tag is not
- // canonical, it could be ambiguous. For example, tags v0.0.1+a and
- // v0.0.1+b might both exist and refer to different revisions.
- //
- // The tag is otherwise valid for the module, so we can at least use it as
- // the base of an unambiguous pseudo-version.
- //
- // If multiple tags match, tagToVersion will canonicalize them to the same
- // base version.
- pseudoBase = v
}
}
- // If we found any canonical tag for the revision, return it.
+ // If we found a valid canonical tag for the revision, return it.
// Even if we found a good pseudo-version base, a canonical version is better.
- if info2.Version != "" {
- return checkGoMod()
+ if highestCanonical != "" {
+ return checkCanonical(highestCanonical)
}
// Find the highest tagged version in the revision's history, subject to
@@ -528,11 +527,10 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0"))
}
}
- pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid
+ pseudoBase, _ = tagToVersion(tag)
}
- info2.Version = PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short)
- return checkGoMod()
+ return checkCanonical(PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short))
}
// validatePseudoVersion checks that version has a major version compatible with
@@ -556,10 +554,6 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
}
}()
- if err := module.CheckPathMajor(version, r.pathMajor); err != nil {
- return err
- }
-
rev, err := PseudoVersionRev(version)
if err != nil {
return err
diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go
index 02e399f352..d98ea87da2 100644
--- a/src/cmd/go/internal/modfetch/coderepo_test.go
+++ b/src/cmd/go/internal/modfetch/coderepo_test.go
@@ -418,171 +418,204 @@ var codeRepoTests = []codeRepoTest{
zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=",
zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5",
},
+ {
+ // Git branch with a semver name, +incompatible version, and no go.mod file.
+ vcs: "git",
+ path: "vcs-test.golang.org/go/mod/gitrepo1",
+ rev: "v2.3.4+incompatible",
+ err: `resolves to version v2.0.1+incompatible (v2.3.4 is not a tag)`,
+ },
+ {
+ // Git branch with a semver name, matching go.mod file, and compatible version.
+ vcs: "git",
+ path: "vcs-test.golang.org/git/semver-branch.git",
+ rev: "v1.0.0",
+ err: `resolves to version v0.1.1-0.20220202191944-09c4d8f6938c (v1.0.0 is not a tag)`,
+ },
+ {
+ // Git branch with a semver name, matching go.mod file, and disallowed +incompatible version.
+ // The version/tag mismatch takes precedence over the +incompatible mismatched.
+ vcs: "git",
+ path: "vcs-test.golang.org/git/semver-branch.git",
+ rev: "v2.0.0+incompatible",
+ err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
+ },
+ {
+ // Git branch with a semver name, matching go.mod file, and mismatched version.
+ // The version/tag mismatch takes precedence over the +incompatible mismatched.
+ vcs: "git",
+ path: "vcs-test.golang.org/git/semver-branch.git",
+ rev: "v2.0.0",
+ err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`,
+ },
+ {
+ // v3.0.0-devel is the same as tag v4.0.0-beta.1, but v4.0.0-beta.1 would
+ // not be allowed because it is incompatible and a go.mod file exists.
+ // The error message should refer to a valid pseudo-version, not the
+ // unusable semver tag.
+ vcs: "git",
+ path: "vcs-test.golang.org/git/semver-branch.git",
+ rev: "v3.0.0-devel",
+ err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
+ },
}
func TestCodeRepo(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
+ tmpdir := t.TempDir()
- tmpdir, err := os.MkdirTemp("", "modfetch-test-")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmpdir)
+ for _, tt := range codeRepoTests {
+ f := func(tt codeRepoTest) func(t *testing.T) {
+ return func(t *testing.T) {
+ t.Parallel()
+ if tt.vcs != "mod" {
+ testenv.MustHaveExecPath(t, tt.vcs)
+ }
- t.Run("parallel", func(t *testing.T) {
- for _, tt := range codeRepoTests {
- f := func(tt codeRepoTest) func(t *testing.T) {
- return func(t *testing.T) {
- t.Parallel()
- if tt.vcs != "mod" {
- testenv.MustHaveExecPath(t, tt.vcs)
- }
+ repo := Lookup("direct", tt.path)
- repo := Lookup("direct", tt.path)
+ if tt.mpath == "" {
+ tt.mpath = tt.path
+ }
+ if mpath := repo.ModulePath(); mpath != tt.mpath {
+ t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
+ }
- if tt.mpath == "" {
- tt.mpath = tt.path
- }
- if mpath := repo.ModulePath(); mpath != tt.mpath {
- t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
+ info, err := repo.Stat(tt.rev)
+ if err != nil {
+ if tt.err != "" {
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
+ }
+ return
}
+ t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
+ }
+ if tt.err != "" {
+ t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
+ }
+ if info.Version != tt.version {
+ t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
+ }
+ if info.Name != tt.name {
+ t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
+ }
+ if info.Short != tt.short {
+ t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
+ }
+ if !info.Time.Equal(tt.time) {
+ t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
+ }
- info, err := repo.Stat(tt.rev)
- if err != nil {
- if tt.err != "" {
- if !strings.Contains(err.Error(), tt.err) {
- t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
- }
- return
+ if tt.gomod != "" || tt.gomodErr != "" {
+ data, err := repo.GoMod(tt.version)
+ if err != nil && tt.gomodErr == "" {
+ t.Errorf("repo.GoMod(%q): %v", tt.version, err)
+ } else if err != nil && tt.gomodErr != "" {
+ if err.Error() != tt.gomodErr {
+ t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
}
- t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
- }
- if tt.err != "" {
- t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
- }
- if info.Version != tt.version {
- t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
+ } else if tt.gomodErr != "" {
+ t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
+ } else if string(data) != tt.gomod {
+ t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
}
- if info.Name != tt.name {
- t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
- }
- if info.Short != tt.short {
- t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
+ }
+
+ needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
+ if tt.zip != nil || tt.zipErr != "" || needHash {
+ f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
+ if err != nil {
+ t.Fatalf("os.CreateTemp: %v", err)
}
- if !info.Time.Equal(tt.time) {
- t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
+ zipfile := f.Name()
+ defer func() {
+ f.Close()
+ os.Remove(zipfile)
+ }()
+
+ var w io.Writer
+ var h hash.Hash
+ if needHash {
+ h = sha256.New()
+ w = io.MultiWriter(f, h)
+ } else {
+ w = f
}
-
- if tt.gomod != "" || tt.gomodErr != "" {
- data, err := repo.GoMod(tt.version)
- if err != nil && tt.gomodErr == "" {
- t.Errorf("repo.GoMod(%q): %v", tt.version, err)
- } else if err != nil && tt.gomodErr != "" {
- if err.Error() != tt.gomodErr {
- t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr)
+ err = repo.Zip(w, tt.version)
+ f.Close()
+ if err != nil {
+ if tt.zipErr != "" {
+ if err.Error() == tt.zipErr {
+ return
}
- } else if tt.gomodErr != "" {
- t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr)
- } else if string(data) != tt.gomod {
- t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
+ t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
}
+ t.Fatalf("repo.Zip(%q): %v", tt.version, err)
+ }
+ if tt.zipErr != "" {
+ t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
}
- needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "")
- if tt.zip != nil || tt.zipErr != "" || needHash {
- f, err := os.CreateTemp(tmpdir, tt.version+".zip.")
+ if tt.zip != nil {
+ prefix := tt.path + "@" + tt.version + "/"
+ z, err := zip.OpenReader(zipfile)
if err != nil {
- t.Fatalf("os.CreateTemp: %v", err)
+ t.Fatalf("open zip %s: %v", zipfile, err)
}
- zipfile := f.Name()
- defer func() {
- f.Close()
- os.Remove(zipfile)
- }()
-
- var w io.Writer
- var h hash.Hash
- if needHash {
- h = sha256.New()
- w = io.MultiWriter(f, h)
- } else {
- w = f
- }
- err = repo.Zip(w, tt.version)
- f.Close()
- if err != nil {
- if tt.zipErr != "" {
- if err.Error() == tt.zipErr {
- return
- }
- t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr)
+ var names []string
+ for _, file := range z.File {
+ if !strings.HasPrefix(file.Name, prefix) {
+ t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
+ continue
}
- t.Fatalf("repo.Zip(%q): %v", tt.version, err)
- }
- if tt.zipErr != "" {
- t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr)
+ names = append(names, file.Name[len(prefix):])
}
-
- if tt.zip != nil {
- prefix := tt.path + "@" + tt.version + "/"
- z, err := zip.OpenReader(zipfile)
- if err != nil {
- t.Fatalf("open zip %s: %v", zipfile, err)
- }
- var names []string
- for _, file := range z.File {
- if !strings.HasPrefix(file.Name, prefix) {
- t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
- continue
- }
- names = append(names, file.Name[len(prefix):])
- }
- z.Close()
- if !reflect.DeepEqual(names, tt.zip) {
- t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
- }
+ z.Close()
+ if !reflect.DeepEqual(names, tt.zip) {
+ t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
}
+ }
- if needHash {
- sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
- if err != nil {
- t.Errorf("repo.Zip(%q): %v", tt.version, err)
- } else if sum != tt.zipSum {
- t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
- } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
- t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
- }
+ if needHash {
+ sum, err := dirhash.HashZip(zipfile, dirhash.Hash1)
+ if err != nil {
+ t.Errorf("repo.Zip(%q): %v", tt.version, err)
+ } else if sum != tt.zipSum {
+ t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum)
+ } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash {
+ t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash)
}
}
}
}
- t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
- if strings.HasPrefix(tt.path, vgotest1git) {
- for vcs, alt := range altVgotests {
- altTest := tt
- altTest.vcs = vcs
- altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
- if strings.HasPrefix(altTest.mpath, vgotest1git) {
- altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
- }
- var m map[string]string
- if alt == vgotest1hg {
- m = hgmap
- }
- altTest.version = remap(altTest.version, m)
- altTest.name = remap(altTest.name, m)
- altTest.short = remap(altTest.short, m)
- altTest.rev = remap(altTest.rev, m)
- altTest.err = remap(altTest.err, m)
- altTest.gomodErr = remap(altTest.gomodErr, m)
- altTest.zipErr = remap(altTest.zipErr, m)
- altTest.zipSum = ""
- altTest.zipFileHash = ""
- t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
+ }
+ t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
+ if strings.HasPrefix(tt.path, vgotest1git) {
+ for vcs, alt := range altVgotests {
+ altTest := tt
+ altTest.vcs = vcs
+ altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git)
+ if strings.HasPrefix(altTest.mpath, vgotest1git) {
+ altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git)
+ }
+ var m map[string]string
+ if alt == vgotest1hg {
+ m = hgmap
}
+ altTest.version = remap(altTest.version, m)
+ altTest.name = remap(altTest.name, m)
+ altTest.short = remap(altTest.short, m)
+ altTest.rev = remap(altTest.rev, m)
+ altTest.err = remap(altTest.err, m)
+ altTest.gomodErr = remap(altTest.gomodErr, m)
+ altTest.zipErr = remap(altTest.zipErr, m)
+ altTest.zipSum = ""
+ altTest.zipFileHash = ""
+ t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest))
}
}
- })
+ }
}
var hgmap = map[string]string{
diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go
index 9feffe0765..ecc42262de 100644
--- a/src/cmd/go/internal/vcs/vcs.go
+++ b/src/cmd/go/internal/vcs/vcs.go
@@ -5,7 +5,6 @@
package vcs
import (
- "encoding/json"
"errors"
"fmt"
exec "internal/execabs"
@@ -1189,8 +1188,9 @@ var vcsPaths = []*vcsPath{
{
pathPrefix: "bitbucket.org",
regexp: lazyregexp.New(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`),
+ vcs: "git",
repo: "https://{root}",
- check: bitbucketVCS,
+ check: noVCSSuffix,
},
// IBM DevOps Services (JazzHub)
@@ -1262,56 +1262,6 @@ func noVCSSuffix(match map[string]string) error {
return nil
}
-// bitbucketVCS determines the version control system for a
-// Bitbucket repository, by using the Bitbucket API.
-func bitbucketVCS(match map[string]string) error {
- if err := noVCSSuffix(match); err != nil {
- return err
- }
-
- var resp struct {
- SCM string `json:"scm"`
- }
- url := &urlpkg.URL{
- Scheme: "https",
- Host: "api.bitbucket.org",
- Path: expand(match, "/2.0/repositories/{bitname}"),
- RawQuery: "fields=scm",
- }
- data, err := web.GetBytes(url)
- if err != nil {
- if httpErr, ok := err.(*web.HTTPError); ok && httpErr.StatusCode == 403 {
- // this may be a private repository. If so, attempt to determine which
- // VCS it uses. See issue 5375.
- root := match["root"]
- for _, vcs := range []string{"git", "hg"} {
- if vcsByCmd(vcs).Ping("https", root) == nil {
- resp.SCM = vcs
- break
- }
- }
- }
-
- if resp.SCM == "" {
- return err
- }
- } else {
- if err := json.Unmarshal(data, &resp); err != nil {
- return fmt.Errorf("decoding %s: %v", url, err)
- }
- }
-
- if vcsByCmd(resp.SCM) != nil {
- match["vcs"] = resp.SCM
- if resp.SCM == "git" {
- match["repo"] += ".git"
- }
- return nil
- }
-
- return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
-}
-
// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
// "foo" could be a series name registered in Launchpad with its own branch,
// and it could also be the name of a directory within the main project
diff --git a/src/cmd/go/internal/vcs/vcs_test.go b/src/cmd/go/internal/vcs/vcs_test.go
index c5c7a3283b..a4fec3f8f8 100644
--- a/src/cmd/go/internal/vcs/vcs_test.go
+++ b/src/cmd/go/internal/vcs/vcs_test.go
@@ -183,6 +183,13 @@ func TestRepoRootForImportPath(t *testing.T) {
"chiselapp.com/user/kyle/fossilgg",
nil,
},
+ {
+ "bitbucket.org/workspace/pkgname",
+ &RepoRoot{
+ VCS: vcsGit,
+ Repo: "https://bitbucket.org/workspace/pkgname",
+ },
+ },
}
for _, test := range tests {
diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt
index 43b9564356..361d99373f 100644
--- a/src/cmd/go/testdata/script/mod_invalid_version.txt
+++ b/src/cmd/go/testdata/script/mod_invalid_version.txt
@@ -194,10 +194,10 @@ cp go.mod.orig go.mod
go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible
cd outside
! go list -m github.com/pierrec/lz4
-stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
cd ..
! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go: github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
# A +incompatible pseudo-version is valid for a revision of the module
# that lacks a go.mod file.
@@ -222,7 +222,7 @@ stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible'
# not resolve to a pseudo-version with a different major version.
cp go.mod.orig go.mod
! go get -d github.com/pierrec/lz4@v2.0.8
-stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2'
+stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
# An invalid +incompatible suffix for a canonical version should error out,
# not resolve to a pseudo-version.
@@ -233,10 +233,10 @@ cp go.mod.orig go.mod
go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible
cd outside
! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
cd ..
! go list -m github.com/pierrec/lz4
-stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$'
-- go.mod.orig --
module example.com
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index f7a32aebae..81efc8f4a0 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1270,7 +1270,10 @@ func (ctxt *Link) hostlink() {
if ctxt.DynlinkingGo() && objabi.GOOS != "ios" {
// -flat_namespace is deprecated on iOS.
// It is useful for supporting plugins. We don't support plugins on iOS.
- argv = append(argv, "-Wl,-flat_namespace")
+ // -flat_namespace may cause the dynamic linker to hang at forkExec when
+ // resolving a lazy binding. See issue 38824.
+ // Force eager resolution to work around.
+ argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
}
if !combineDwarf {
argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols