diff --git a/cl/_testdata/varinit/in.go b/cl/_testdata/varinit/in.go index 15b17d7ebd..3f3a4e1501 100644 --- a/cl/_testdata/varinit/in.go +++ b/cl/_testdata/varinit/in.go @@ -8,7 +8,6 @@ var a = 100 // CHECK-NEXT: %0 = load i64, ptr @main.a, align 8 // CHECK-NEXT: %1 = add i64 %0, 1 // CHECK-NEXT: store i64 %1, ptr @main.a, align 8 -// CHECK-NEXT: %2 = load i64, ptr @main.a, align 8 // CHECK-NEXT: ret void // CHECK-NEXT: } func main() { diff --git a/cl/_testrt/cvar/in.go b/cl/_testrt/cvar/in.go index 2a7b0a0d97..7a8416a18d 100644 --- a/cl/_testrt/cvar/in.go +++ b/cl/_testrt/cvar/in.go @@ -20,8 +20,6 @@ var barY struct { // CHECK-LABEL: define void @main.main(){{.*}} { // CHECK-NEXT: _llgo_0: -// CHECK-NEXT: %0 = load { [16 x i8], [2 x ptr] }, ptr @_bar_x, align 8 -// CHECK-NEXT: %1 = load { [16 x i8] }, ptr @_bar_y, align 1 // CHECK-NEXT: ret void // CHECK-NEXT: } func main() { diff --git a/cl/compile.go b/cl/compile.go index 6ea1569324..e8cae83b5c 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -1331,28 +1331,17 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue b.AssertNilDeref(x) } if refs, ok := nonDebugReferrers(v); ok && len(refs) == 0 { - if t := p.type_(v.Type(), llssa.InGo); t.RawType() != nil { - if p.isLargeNonPointerValue(t) { - x := p.compileValue(b, v.X) - p.recordPanicLocation(b, v.Pos()) - p.assertNilDerefBase(b, v.X) - b.AssertNilDeref(x) - return - } - } if skipUnusedArrayDeref(v) { p.compileValue(b, v.X) return } - if _, ok := types.Unalias(v.Type()).Underlying().(*types.Slice); ok { - // Zero-length slice-to-array conversions can leave only - // an unused slice deref; preserve its required nil check. - x := p.compileValue(b, v.X) - p.recordPanicLocation(b, v.Pos()) - p.assertNilDerefBase(b, v.X) - b.AssertNilDeref(x) - return - } + // LLVM may eliminate an unused load, but evaluating a Go + // dereference must still panic when its pointer is nil. + x := p.compileValue(b, v.X) + p.recordPanicLocation(b, v.Pos()) + p.assertNilDerefBase(b, v.X) + b.AssertNilDeref(x) + return } if refs, ok := nonDebugReferrers(v); ok && len(refs) == 1 { if _, ok := refs[0].(*ssa.MakeInterface); ok { diff --git a/cl/zero_size_deref_test.go b/cl/zero_size_deref_test.go index 48de2b8d67..a84cccc06f 100644 --- a/cl/zero_size_deref_test.go +++ b/cl/zero_size_deref_test.go @@ -71,3 +71,24 @@ func keepPointer(pointer *struct{}) func() bool { }) } } + +func TestUnusedDerefEmitsNilGuard(t *testing.T) { + const src = `package unusedderef +func LoadArrayElement() { + var values [2]*int + _ = *values[1] +} +func LoadPointer(p *int) { + _ = *p +} +` + ir := compileWithRewrites(t, src, nil) + arrayLoad := llvmFunction(t, ir, "unusedderef.LoadArrayElement") + if !strings.Contains(arrayLoad, "AssertNilDeref") { + t.Fatalf("unused array-element dereference should retain a nil guard:\n%s", arrayLoad) + } + directLoad := llvmFunction(t, ir, "unusedderef.LoadPointer") + if !strings.Contains(directLoad, "AssertNilDeref") { + t.Fatalf("unused direct dereference should retain a nil guard:\n%s", directLoad) + } +} diff --git a/test/go/nil_deref_address_test.go b/test/go/nil_deref_address_test.go index e2a9506b3d..c02f966f53 100644 --- a/test/go/nil_deref_address_test.go +++ b/test/go/nil_deref_address_test.go @@ -47,6 +47,33 @@ func TestNilDerefAddressOperationsPanic(t *testing.T) { } } +func TestUnusedNilDerefOperationsPanic(t *testing.T) { + tests := []struct { + name string + f func() + }{ + { + name: "direct pointer", + f: func() { + var p *int + _ = *p + }, + }, + { + name: "pointer loaded from array", + f: func() { + var values [2]*int + _ = *values[1] + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expectNilDerefAddressPanic(t, tt.f) + }) + } +} + func TestNilDerefPrintedCompositeLoadsPanic(t *testing.T) { tests := []struct { name string diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index 46da01411a..6e6b54b778 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -1559,14 +1559,6 @@ xfails: directive: run case: fixedbugs/issue57823.go reason: go1.26 goroot run failure on linux/amd64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/issue38496.go - reason: current main goroot run failure on darwin/arm64 - - platform: linux/amd64 - directive: run - case: fixedbugs/issue38496.go - reason: current main goroot run failure on linux/amd64 - platform: linux/amd64 directive: run case: nilptr.go