src/cmd/compile/internal/noder/reader.go | 20 +++++++++++++++++++- src/cmd/compile/testdata/script/issue73947.txt | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/log/slog/json_handler.go | 4 +--- src/log/slog/text_handler.go | 4 +--- src/os/signal/doc.go | 7 ++++--- src/runtime/race_loong64.s | 7 ++++++- diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 2c3f7161a830faf5ae72ec57bf4f8512ee90777e..38b0bc1d8a41530fb710fdc7ad04cb683b27ba62 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1014,7 +1014,25 @@ // And if we're constructing a shaped object, then shapify all type // arguments. for i, targ := range dict.targs { basic := r.Bool() - if dict.shaped && !pr.reshaping { + isPointerShape := basic && targ.IsPtr() && !targ.Elem().NotInHeap() + // We should not do shapify during the reshaping process, see #71184. + // However, this only matters for shapify a pointer type, which will + // lose the original underlying type. + // + // Example with a pointer type: + // + // - First, shapifying *[]T -> *uint8 + // - During the reshaping process, *uint8 is shapified to *go.shape.uint8 + // - This ends up with a different type with the original *[]T + // + // For a non-pointer type: + // + // - int -> go.shape.int + // - go.shape.int -> go.shape.int + // + // We always end up with the identical type. + canShapify := !pr.reshaping || !isPointerShape + if dict.shaped && canShapify { dict.targs[i] = shapify(targ, basic) } } diff --git a/src/cmd/compile/testdata/script/issue73947.txt b/src/cmd/compile/testdata/script/issue73947.txt new file mode 100644 index 0000000000000000000000000000000000000000..f888ae2bfa5e04cf45f5463e2d5d1dd23349a618 --- /dev/null +++ b/src/cmd/compile/testdata/script/issue73947.txt @@ -0,0 +1,125 @@ +go build main.go +! stdout . +! stderr . + +-- main.go -- + +package main + +import ( + "p/b" +) + +func main() { + f() +} + +func f() { + typ := indexedPageType{newIndexedType(nil)} + page := newPage(typ.indexedType) + page.Data() +} + +func newPage(typ *indexedType) Page { + values := typ.NewValues(nil, nil) + return &indexedPage{ + typ: typ, + values: values.Int32(), + columnIndex: ^0, + } +} + +type Type interface { + NewPage(columnIndex, numValues int, data b.Values) Page + NewValues(values []byte, offsets []uint32) b.Values +} + +type Page interface { + Type() Type + Data() b.Values +} + +type indexedPage struct { + typ *indexedType + values []int32 + columnIndex int16 +} + +func (page *indexedPage) Type() Type { return indexedPageType{page.typ} } + +func (page *indexedPage) Data() b.Values { return b.Int32Values(page.values) } + +type indexedType struct { + Type +} + +func newIndexedType(typ Type) *indexedType { + return &indexedType{Type: typ} +} + +type indexedPageType struct{ *indexedType } + +func (t indexedPageType) NewValues(values []byte, _ []uint32) b.Values { + return b.Int32ValuesFromBytes(values) +} + +-- go.mod -- +module p + +go 1.24 + +-- internal/a/a.go -- +package a + +import "unsafe" + +type slice struct { + ptr unsafe.Pointer + len int + cap int +} + +func Slice[To, From any](data []From) []To { + // This function could use unsafe.Slice but it would drop the capacity + // information, so instead we implement the type conversion. + var zf From + var zt To + var s = slice{ + ptr: unsafe.Pointer(unsafe.SliceData(data)), + len: int((uintptr(len(data)) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt)), + cap: int((uintptr(cap(data)) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt)), + } + return *(*[]To)(unsafe.Pointer(&s)) +} + +-- b/b.go -- +package b + +import "p/internal/a" + +type Kind int32 + +const Int32 Kind = iota + 2 + +type Values struct { + kind Kind + size int32 + data []byte + offsets []uint32 +} + +func (v *Values) Int32() []int32 { + return a.Slice[int32](v.data) +} + +func makeValues[T any](kind Kind, values []T) Values { + return Values{kind: kind, data: a.Slice[byte](values)} +} + +func Int32Values(values []int32) Values { + return makeValues(Int32, values) +} + +func Int32ValuesFromBytes(values []byte) Values { + return Values{kind: Int32, data: values} +} diff --git a/src/log/slog/json_handler.go b/src/log/slog/json_handler.go index da3eae1a8ec0d35bd35548f794f1f22d4d3bc7c8..f139c5413912bf2610cf802e8e175d38256ca331 100644 --- a/src/log/slog/json_handler.go +++ b/src/log/slog/json_handler.go @@ -63,9 +63,7 @@ // If the Record's time is zero, the time is omitted. // Otherwise, the key is "time" // and the value is output as with json.Marshal. // -// If the Record's level is zero, the level is omitted. -// Otherwise, the key is "level" -// and the value of [Level.String] is output. +// The level's key is "level" and its value is the result of calling [Level.String]. // // If the AddSource option is set and source information is available, // the key is "source", and the value is a record of type [Source]. diff --git a/src/log/slog/text_handler.go b/src/log/slog/text_handler.go index 6819e633bb713f20bce1399a06cb773ffff51bc3..5a0d0a4a7ed42b5b0f42bdff8adbdc6b565fb02a 100644 --- a/src/log/slog/text_handler.go +++ b/src/log/slog/text_handler.go @@ -62,9 +62,7 @@ // If the Record's time is zero, the time is omitted. // Otherwise, the key is "time" // and the value is output in RFC3339 format with millisecond precision. // -// If the Record's level is zero, the level is omitted. -// Otherwise, the key is "level" -// and the value of [Level.String] is output. +// The level's key is "level" and its value is the result of calling [Level.String]. // // If the AddSource option is set and source information is available, // the key is "source" and the value is output as FILE:LINE. diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go index 1d3e6eb573a552e81b172e989776edbfe31d4358..df942b842898de8433ea363a24e08fae2c99ea8d 100644 --- a/src/os/signal/doc.go +++ b/src/os/signal/doc.go @@ -98,12 +98,13 @@ the behavior depends on the file descriptor number. A write to a broken pipe on file descriptors 1 or 2 (standard output or standard error) will cause the program to exit with a SIGPIPE signal. A write to a broken pipe on some other file descriptor will take no action on -the SIGPIPE signal, and the write will fail with an EPIPE error. +the SIGPIPE signal, and the write will fail with a [syscall.EPIPE] +error. If the program has called Notify to receive SIGPIPE signals, the file descriptor number does not matter. The SIGPIPE signal will be -delivered to the Notify channel, and the write will fail with an EPIPE -error. +delivered to the Notify channel, and the write will fail with a +[syscall.EPIPE] error. This means that, by default, command line programs will behave like typical Unix command line programs, while other programs will not diff --git a/src/runtime/race_loong64.s b/src/runtime/race_loong64.s index 597e0cc6b90ed35d5ce3a9ebc6a2a526711bd7d3..d731871d4494fe85c093cebae0159e7a10e61bd3 100644 --- a/src/runtime/race_loong64.s +++ b/src/runtime/race_loong64.s @@ -461,8 +461,13 @@ MOVV g_m(g), R12 // Switch to g0 stack. MOVV R3, R23 // callee-saved, preserved across the CALL MOVV R1, R24 // callee-saved, preserved across the CALL + + // Switch to g0 stack if we aren't already on g0 or gsignal. + MOVV m_gsignal(R12), R13 + BEQ R13, g, call + MOVV m_g0(R12), R13 - BEQ R13, g, call // already on g0 + BEQ R13, g, call MOVV (g_sched+gobuf_sp)(R13), R3 call: JAL (RCALL)