diff options
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/compile/internal/mips64/ssa.go | 5 | ||||
-rw-r--r-- | src/cmd/compile/internal/ssa/gen/ARM.rules | 4 | ||||
-rw-r--r-- | src/cmd/compile/internal/ssa/gen/ARM64.rules | 10 | ||||
-rw-r--r-- | src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 4 | ||||
-rw-r--r-- | src/cmd/compile/internal/ssa/gen/ARMOps.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/ssa/rewriteARM.go | 144 | ||||
-rw-r--r-- | src/cmd/compile/internal/ssa/rewriteARM64.go | 160 | ||||
-rw-r--r-- | src/cmd/go/internal/modfetch/coderepo.go | 216 | ||||
-rw-r--r-- | src/cmd/go/internal/modfetch/coderepo_test.go | 301 | ||||
-rw-r--r-- | src/cmd/go/internal/vcs/vcs.go | 54 | ||||
-rw-r--r-- | src/cmd/go/internal/vcs/vcs_test.go | 7 | ||||
-rw-r--r-- | src/cmd/go/testdata/script/mod_invalid_version.txt | 10 | ||||
-rw-r--r-- | src/cmd/link/internal/ld/lib.go | 5 |
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 |