The real world code that inspired this fix,
from runtime/pprof/map.go:
// Compute hash of (stk, tag).
h := uintptr(0)
for _, x := range stk {
h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
h += uintptr(x) * 41
}
h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
h += uintptr(tag) * 41
Change-Id: I99a95b97cba73811faedb0b9a1b9b54e9a1784a3
Reviewed-on: https://go-review.googlesource.com/37574
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
// like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
return
}
+
+ // Ignore shifts where the shift amount is calculated using unsafe.
+ // These are used for bit-twiddling tricks.
+ var hasUnsafe bool
+ ast.Inspect(y, func(n ast.Node) bool {
+ sel, ok := n.(*ast.SelectorExpr)
+ if !ok {
+ return true
+ }
+ pkg, ok := sel.X.(*ast.Ident)
+ if !ok {
+ return true
+ }
+ if pkg.Name == "unsafe" {
+ hasUnsafe = true
+ return false
+ }
+ return true
+ })
+ if hasUnsafe {
+ return
+ }
+
v := f.pkg.types[y].Value
if v == nil {
return
package testdata
+import "unsafe"
+
func ShiftTest() {
var i8 int8
_ = i8 << 7
p >>= 32 // ERROR "p might be too small for shift of 32"
const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks
+
+ var h uintptr
+ h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) // shifts by unsafe amounts are safe
}