--- /dev/null
+// Copyright 2025 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 dwarfgen
+
+import (
+ "debug/dwarf"
+ "internal/platform"
+ "internal/testenv"
+ "io"
+ "runtime"
+ "testing"
+)
+
+func TestIssue75249(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+ t.Parallel()
+
+ if !platform.ExecutableHasDWARF(runtime.GOOS, runtime.GOARCH) {
+ t.Skipf("skipping on %s/%s: no DWARF symbol table in executables", runtime.GOOS, runtime.GOARCH)
+ }
+
+ code := `
+package main
+
+type Data struct {
+ Field1 int
+ Field2 *int
+ Field3 int
+ Field4 *int
+ Field5 int
+ Field6 *int
+ Field7 int
+ Field8 *int
+}
+
+//go:noinline
+func InitializeData(d *Data) {
+ d.Field1++ // line 16
+ d.Field2 = d.Field4
+ d.Field3++
+ d.Field4 = d.Field6
+ d.Field5++
+ d.Field6 = d.Field8
+ d.Field7++
+ d.Field8 = d.Field2 // line 23
+}
+
+func main() {
+ var data Data
+ InitializeData(&data)
+}
+`
+
+ _, f := gobuild(t, t.TempDir(), true, []testline{{line: code}})
+ defer f.Close()
+
+ dwarfData, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ dwarfReader := dwarfData.Reader()
+
+ for {
+ entry, err := dwarfReader.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if entry == nil {
+ break
+ }
+ if entry.Tag != dwarf.TagCompileUnit {
+ continue
+ }
+ name := entry.AttrField(dwarf.AttrName)
+ if name == nil || name.Class != dwarf.ClassString || name.Val != "main" {
+ continue
+ }
+ lr, err := dwarfData.LineReader(entry)
+ if err != nil {
+ t.Fatal(err)
+ }
+ stmts := map[int]bool{}
+ for {
+ var le dwarf.LineEntry
+ err := lr.Next(&le)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !le.IsStmt {
+ continue
+ }
+ stmts[le.Line] = true
+ }
+ for i := 16; i <= 23; i++ {
+ if !stmts[i] {
+ t.Errorf("missing statement at line %d", i)
+ }
+ }
+ }
+}
for _, e := range partition {
slices.SortFunc(e, func(v, w *Value) int {
c := cmp.Compare(sdom.domorder(v.Block), sdom.domorder(w.Block))
- if v.Op != OpLocalAddr || c != 0 {
+ if c != 0 {
return c
}
- // compare the memory args for OpLocalAddrs in the same block
- vm := v.Args[1]
- wm := w.Args[1]
- if vm == wm {
- return 0
- }
- // if the two OpLocalAddrs are in the same block, and one's memory
- // arg also in the same block, but the other one's memory arg not,
- // the latter must be in an ancestor block
- if vm.Block != v.Block {
- return -1
+ if v.Op == OpLocalAddr {
+ // compare the memory args for OpLocalAddrs in the same block
+ vm := v.Args[1]
+ wm := w.Args[1]
+ if vm == wm {
+ return 0
+ }
+ // if the two OpLocalAddrs are in the same block, and one's memory
+ // arg also in the same block, but the other one's memory arg not,
+ // the latter must be in an ancestor block
+ if vm.Block != v.Block {
+ return -1
+ }
+ if wm.Block != w.Block {
+ return +1
+ }
+ // use store order if the memory args are in the same block
+ vs := storeOrdering(vm, o)
+ ws := storeOrdering(wm, o)
+ if vs <= 0 {
+ f.Fatalf("unable to determine the order of %s", vm.LongString())
+ }
+ if ws <= 0 {
+ f.Fatalf("unable to determine the order of %s", wm.LongString())
+ }
+ return cmp.Compare(vs, ws)
}
- if wm.Block != w.Block {
+ vStmt := v.Pos.IsStmt() == src.PosIsStmt
+ wStmt := w.Pos.IsStmt() == src.PosIsStmt
+ if vStmt != wStmt {
+ if vStmt {
+ return -1
+ }
return +1
}
- // use store order if the memory args are in the same block
- vs := storeOrdering(vm, o)
- ws := storeOrdering(wm, o)
- if vs <= 0 {
- f.Fatalf("unable to determine the order of %s", vm.LongString())
- }
- if ws <= 0 {
- f.Fatalf("unable to determine the order of %s", wm.LongString())
- }
- return cmp.Compare(vs, ws)
+ return 0
})
for i := 0; i < len(e)-1; i++ {