Merge "[dev.typeparams] all: merge master (798ec73) into dev.typeparams" into dev.typeparams

This commit is contained in:
Gerrit Code Review 2021-07-22 20:59:40 +00:00
commit 244267e8c4
13 changed files with 138 additions and 19 deletions

View file

@ -80,6 +80,7 @@ pkg net/url, method (Values) Has(string) bool
pkg reflect, func VisibleFields(Type) []StructField pkg reflect, func VisibleFields(Type) []StructField
pkg reflect, method (Method) IsExported() bool pkg reflect, method (Method) IsExported() bool
pkg reflect, method (StructField) IsExported() bool pkg reflect, method (StructField) IsExported() bool
pkg reflect, method (Value) CanConvert(Type) bool
pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete() pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete()
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{} pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{}

View file

@ -989,6 +989,18 @@ func Foo() bool {
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt> <dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
<dd> <dd>
<p><!-- CL 334669 -->
The new
<a href="/pkg/reflect/#Value.CanConvert"><code>Value.CanConvert</code></a>
method reports whether a value can be converted to a type.
This may be used to avoid a panic when converting a slice to an
array pointer type if the slice is too short.
Previously it was sufficient to use
<a href="/pkg/reflect/#Type.ConvertibleTo"><code>Type.ConvertibleTo</code></a>
for this, but the newly permitted conversion from slice to array
pointer type can panic even if the types are convertible.
</p>
<p><!-- CL 266197 --> <p><!-- CL 266197 -->
The new The new
<a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a> <a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a>

View file

@ -2850,3 +2850,35 @@ func TestExecInDeletedDir(t *testing.T) {
// `go version` should not fail // `go version` should not fail
tg.run("version") tg.run("version")
} }
// A missing C compiler should not force the net package to be stale.
// Issue 47215.
func TestMissingCC(t *testing.T) {
if !canCgo {
t.Skip("test is only meaningful on systems with cgo")
}
cc := os.Getenv("CC")
if cc == "" {
cc = "gcc"
}
if filepath.IsAbs(cc) {
t.Skipf(`"CC" (%s) is an absolute path`, cc)
}
_, err := exec.LookPath(cc)
if err != nil {
t.Skipf(`"CC" (%s) not on PATH`, cc)
}
tg := testgo(t)
defer tg.cleanup()
netStale, _ := tg.isStale("net")
if netStale {
t.Skip(`skipping test because "net" package is currently stale`)
}
tg.setenv("PATH", "") // No C compiler on PATH.
netStale, _ = tg.isStale("net")
if netStale {
t.Error(`clearing "PATH" causes "net" to be stale`)
}
}

View file

@ -252,8 +252,15 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
ccExe := b.ccExe() ccExe := b.ccExe()
fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags) fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags)
if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil { // Include the C compiler tool ID so that if the C
fmt.Fprintf(h, "CC ID=%q\n", ccID) // compiler changes we rebuild the package.
// But don't do that for standard library packages like net,
// so that the prebuilt .a files from a Go binary install
// don't need to be rebuilt with the local compiler.
if !p.Standard {
if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil {
fmt.Fprintf(h, "CC ID=%q\n", ccID)
}
} }
if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 { if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 {
cxxExe := b.cxxExe() cxxExe := b.cxxExe()

View file

@ -4305,6 +4305,9 @@ func TestConvert(t *testing.T) {
// vout1 represents the in value converted to the in type. // vout1 represents the in value converted to the in type.
v1 := tt.in v1 := tt.in
if !v1.CanConvert(t1) {
t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t1)
}
vout1 := v1.Convert(t1) vout1 := v1.Convert(t1)
out1 := vout1.Interface() out1 := vout1.Interface()
if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) { if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) {
@ -4312,6 +4315,9 @@ func TestConvert(t *testing.T) {
} }
// vout2 represents the in value converted to the out type. // vout2 represents the in value converted to the out type.
if !v1.CanConvert(t2) {
t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t2)
}
vout2 := v1.Convert(t2) vout2 := v1.Convert(t2)
out2 := vout2.Interface() out2 := vout2.Interface()
if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) { if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) {
@ -4372,6 +4378,9 @@ func TestConvertPanic(t *testing.T) {
if !v.Type().ConvertibleTo(pt) { if !v.Type().ConvertibleTo(pt) {
t.Errorf("[]byte should be convertible to *[8]byte") t.Errorf("[]byte should be convertible to *[8]byte")
} }
if v.CanConvert(pt) {
t.Errorf("slice with length 4 should not be convertible to *[8]byte")
}
shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() { shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() {
_ = v.Convert(pt) _ = v.Convert(pt)
}) })

View file

@ -2807,6 +2807,26 @@ func (v Value) Convert(t Type) Value {
return op(v, t) return op(v, t)
} }
// CanConvert reports whether the value v can be converted to type t.
// If v.CanConvert(t) returns true then v.Convert(t) will not panic.
func (v Value) CanConvert(t Type) bool {
vt := v.Type()
if !vt.ConvertibleTo(t) {
return false
}
// Currently the only conversion that is OK in terms of type
// but that can panic depending on the value is converting
// from slice to pointer-to-array.
if vt.Kind() == Slice && t.Kind() == Ptr && t.Elem().Kind() == Array {
n := t.Elem().Len()
h := (*unsafeheader.Slice)(v.ptr)
if n > h.Len {
return false
}
}
return true
}
// convertOp returns the function to convert a value of type src // convertOp returns the function to convert a value of type src
// to a value of type dst. If the conversion is illegal, convertOp returns nil. // to a value of type dst. If the conversion is illegal, convertOp returns nil.
func convertOp(dst, src *rtype) func(Value, Type) Value { func convertOp(dst, src *rtype) func(Value, Type) Value {

View file

@ -1,3 +1,7 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflect package reflect
// VisibleFields returns all the visible fields in t, which must be a // VisibleFields returns all the visible fields in t, which must be a

View file

@ -1,3 +1,7 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflect_test package reflect_test
import ( import (

View file

@ -24,6 +24,9 @@ func TestPanicOnFault(t *testing.T) {
if runtime.GOOS == "ios" { if runtime.GOOS == "ios" {
t.Skip("iOS doesn't provide fault addresses") t.Skip("iOS doesn't provide fault addresses")
} }
if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm" {
t.Skip("netbsd-arm doesn't provide fault address (golang.org/issue/45026)")
}
m, err := syscall.Mmap(-1, 0, 0x1000, syscall.PROT_READ /* Note: no PROT_WRITE */, syscall.MAP_SHARED|syscall.MAP_ANON) m, err := syscall.Mmap(-1, 0, 0x1000, syscall.PROT_READ /* Note: no PROT_WRITE */, syscall.MAP_SHARED|syscall.MAP_ANON)
if err != nil { if err != nil {
t.Fatalf("can't map anonymous memory: %s", err) t.Fatalf("can't map anonymous memory: %s", err)

View file

@ -1126,13 +1126,21 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
msanmalloc(x, size) msanmalloc(x, size)
} }
if rate := MemProfileRate; rate > 0 {
// Note cache c only valid while m acquired; see #47302
if rate != 1 && size < c.nextSample {
c.nextSample -= size
} else {
profilealloc(mp, x, size)
}
}
mp.mallocing = 0 mp.mallocing = 0
releasem(mp) releasem(mp)
// Pointerfree data can be zeroed late in a context where preemption can occur. // Pointerfree data can be zeroed late in a context where preemption can occur.
// x will keep the memory alive. // x will keep the memory alive.
if !isZeroed && needzero { if !isZeroed && needzero {
memclrNoHeapPointersChunked(size, x) memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302
} }
if debug.malloc { if debug.malloc {
@ -1146,16 +1154,6 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
} }
} }
if rate := MemProfileRate; rate > 0 {
if rate != 1 && size < c.nextSample {
c.nextSample -= size
} else {
mp := acquirem()
profilealloc(mp, x, size)
releasem(mp)
}
}
if assistG != nil { if assistG != nil {
// Account for internal fragmentation in the assist // Account for internal fragmentation in the assist
// debt now that we know it. // debt now that we know it.

View file

@ -681,7 +681,7 @@ type p struct {
// timerModifiedEarlier status. Because the timer may have been // timerModifiedEarlier status. Because the timer may have been
// modified again, there need not be any timer with this value. // modified again, there need not be any timer with this value.
// This is updated using atomic functions. // This is updated using atomic functions.
// This is 0 if the value is unknown. // This is 0 if there are no timerModifiedEarlier timers.
timerModifiedEarliest uint64 timerModifiedEarliest uint64
// Per-P GC state // Per-P GC state

View file

@ -669,11 +669,6 @@ func adjusttimers(pp *p, now int64) {
if verifyTimers { if verifyTimers {
verifyTimerHeap(pp) verifyTimerHeap(pp)
} }
// There are no timers to adjust, so it is safe to clear
// timerModifiedEarliest. Do so in case it is stale.
// Everything will work if we don't do this,
// but clearing here may save future calls to adjusttimers.
atomic.Store64(&pp.timerModifiedEarliest, 0)
return return
} }

View file

@ -527,6 +527,40 @@ func TestZeroTimer(t *testing.T) {
} }
} }
// Test that rapidly moving a timer earlier doesn't cause it to get dropped.
// Issue 47329.
func TestTimerModifiedEarlier(t *testing.T) {
past := Until(Unix(0, 0))
count := 1000
fail := 0
for i := 0; i < count; i++ {
timer := NewTimer(Hour)
for j := 0; j < 10; j++ {
if !timer.Stop() {
<-timer.C
}
timer.Reset(past)
}
deadline := NewTimer(10 * Second)
defer deadline.Stop()
now := Now()
select {
case <-timer.C:
if since := Since(now); since > 8*Second {
t.Errorf("timer took too long (%v)", since)
fail++
}
case <-deadline.C:
t.Error("deadline expired")
}
}
if fail > 0 {
t.Errorf("%d failures", fail)
}
}
// Benchmark timer latency when the thread that creates the timer is busy with // Benchmark timer latency when the thread that creates the timer is busy with
// other work and the timers must be serviced by other threads. // other work and the timers must be serviced by other threads.
// https://golang.org/issue/38860 // https://golang.org/issue/38860