return func() {
d.once.Do(func() {
defer func() {
+ d.f = nil // Do not keep f alive after invoking it.
d.p = recover()
if !d.valid {
// Re-panic immediately so on the first
}
}()
d.f()
- d.f = nil // Do not keep f alive after invoking it.
d.valid = true // Set only if f does not panic.
})
if !d.valid {
return func() T {
d.once.Do(func() {
defer func() {
+ d.f = nil
d.p = recover()
if !d.valid {
panic(d.p)
}
}()
d.result = d.f()
- d.f = nil
d.valid = true
})
if !d.valid {
return func() (T1, T2) {
d.once.Do(func() {
defer func() {
+ d.f = nil
d.p = recover()
if !d.valid {
panic(d.p)
}
}()
d.r1, d.r2 = d.f()
- d.f = nil
d.valid = true
})
if !d.valid {
f := sync.OnceValues(func() (any, any) { buf[0] = 1; return nil, nil })
return func() { f() }
},
+ "OnceFunc panic": func(buf []byte) func() {
+ return sync.OnceFunc(func() { buf[0] = 1; panic("test panic") })
+ },
+ "OnceValue panic": func(buf []byte) func() {
+ f := sync.OnceValue(func() any { buf[0] = 1; panic("test panic") })
+ return func() { f() }
+ },
+ "OnceValues panic": func(buf []byte) func() {
+ f := sync.OnceValues(func() (any, any) { buf[0] = 1; panic("test panic") })
+ return func() { f() }
+ },
}
for n, fn := range fns {
t.Run(n, func(t *testing.T) {
if gc.Load() != false {
t.Fatal("wrapped function garbage collected too early")
}
- f()
+ func() {
+ defer func() { recover() }()
+ f()
+ }()
gcwaitfin()
if gc.Load() != true {
// Even if f is still alive, the function passed to Once(Func|Value|Values)
// is not kept alive after the first call to f.
t.Fatal("wrapped function should be garbage collected, but still live")
}
- f()
+ func() {
+ defer func() { recover() }()
+ f()
+ }()
})
}
}