} else {
decls, vars, selected = createSimpleVars(fnsym, apDecls)
}
+ if fn.DebugInfo != nil {
+ // Recover zero sized variables eliminated by the stackframe pass
+ for _, n := range fn.DebugInfo.(*ssa.FuncDebug).OptDcl {
+ if n.Class != ir.PAUTO {
+ continue
+ }
+ types.CalcSize(n.Type())
+ if n.Type().Size() == 0 {
+ decls = append(decls, n)
+ vars = append(vars, createSimpleVar(fnsym, n))
+ vars[len(vars)-1].StackOffset = 0
+ fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
+ }
+ }
+ }
dcl := apDecls
if fnsym.WasInlined() {
// Register-resident output parameters for the function. This is filled in at
// SSA generation time.
RegOutputParams []*ir.Name
+ // Variable declarations that were removed during optimization
+ OptDcl []*ir.Name
// Filled in by the user. Translates Block and Value ID to PC.
GetPC func(ID, ID) int64
t.Errorf("no LPT entries for test.go")
}
}
+
+func TestZeroSizedVariable(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+ t.Parallel()
+
+ // This test verifies that the compiler emits DIEs for zero sized variables
+ // (for example variables of type 'struct {}').
+ // See go.dev/issues/54615.
+
+ const prog = `
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ zeroSizedVariable := struct{}{}
+ fmt.Println(zeroSizedVariable)
+}
+`
+
+ for _, opt := range []string{NoOpt, DefaultOpt} {
+ dir := t.TempDir()
+ f := gobuild(t, dir, prog, opt)
+ defer f.Close()
+ defer os.RemoveAll(dir)
+
+ d, err := f.DWARF()
+ if err != nil {
+ t.Fatalf("error reading DWARF: %v", err)
+ }
+
+ rdr := d.Reader()
+ ex := dwtest.Examiner{}
+ if err := ex.Populate(rdr); err != nil {
+ t.Fatalf("error reading DWARF: %v", err)
+ }
+
+ // Locate the main.zeroSizedVariable DIE
+ abcs := ex.Named("zeroSizedVariable")
+ if len(abcs) == 0 {
+ t.Fatalf("unable to locate DIE for zeroSizedVariable")
+ }
+ if len(abcs) != 1 {
+ t.Fatalf("more than one zeroSizedVariable DIE")
+ }
+ }
+}