use anon structs and unions for a much better debug experience (#10055)

This commit is contained in:
Andreas Rumpf 2018-12-20 11:44:26 +01:00 • committed by GitHub
commit 2fd522cf58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 39 deletions

View file

@ -436,30 +436,25 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
if result == nil: internalError(m.config, field.info, "mangleRecFieldName") if result == nil: internalError(m.config, field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode, proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: Rope, rectype: PType, rectype: PType,
check: var IntSet): Rope = check: var IntSet): Rope =
result = nil result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check)) add(result, genRecordFieldsAux(m, n.sons[i], rectype, check))
of nkRecCase: of nkRecCase:
if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux") if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check)) add(result, genRecordFieldsAux(m, n.sons[0], rectype, check))
# prefix mangled name with "_U" to avoid clashes with other field names, # prefix mangled name with "_U" to avoid clashes with other field names,
# since identifiers are not allowed to start with '_' # since identifiers are not allowed to start with '_'
let uname = rope("_U" & mangle(n.sons[0].sym.name.s))
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname]
else: uname
var unionBody: Rope = nil var unionBody: Rope = nil
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind case n.sons[i].kind
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
let k = lastSon(n.sons[i]) let k = lastSon(n.sons[i])
if k.kind != nkSym: if k.kind != nkSym:
let sname = "S" & rope(i) let a = genRecordFieldsAux(m, k, rectype, check)
let a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
check)
if a != nil: if a != nil:
if tfPacked notin rectype.flags: if tfPacked notin rectype.flags:
add(unionBody, "struct {") add(unionBody, "struct {")
@ -469,22 +464,20 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
else: else:
addf(unionBody, "#pragma pack(push, 1)$nstruct{", []) addf(unionBody, "#pragma pack(push, 1)$nstruct{", [])
add(unionBody, a) add(unionBody, a)
addf(unionBody, "} $1;$n", [sname]) addf(unionBody, "};$n", [])
if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props: if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
addf(unionBody, "#pragma pack(pop)$n", []) addf(unionBody, "#pragma pack(pop)$n", [])
else: else:
add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check)) add(unionBody, genRecordFieldsAux(m, k, rectype, check))
else: internalError(m.config, "genRecordFieldsAux(record case branch)") else: internalError(m.config, "genRecordFieldsAux(record case branch)")
if unionBody != nil: if unionBody != nil:
addf(result, "union{$n$1} $2;$n", [unionBody, uname]) addf(result, "union{$n$1};$n", [unionBody])
of nkSym: of nkSym:
let field = n.sym let field = n.sym
if field.typ.kind == tyVoid: return if field.typ.kind == tyVoid: return
#assert(field.ast == nil) #assert(field.ast == nil)
let sname = mangleRecFieldName(m, field) let sname = mangleRecFieldName(m, field)
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname] fillLoc(field.loc, locField, n, sname, OnUnknown)
else: sname
fillLoc(field.loc, locField, n, ae, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't # for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code: # with heavily templatized C++ code:
@ -505,7 +498,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
else: internalError(m.config, n.info, "genRecordFieldsAux()") else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
result = genRecordFieldsAux(m, typ.n, nil, typ, check) result = genRecordFieldsAux(m, typ.n, typ, check)
proc fillObjectFields*(m: BModule; typ: PType) = proc fillObjectFields*(m: BModule; typ: PType) =
# sometimes generic objects are not consistently merged. We patch over # sometimes generic objects are not consistently merged. We patch over

View file

@ -36,27 +36,24 @@ macro testSizeAlignOf(args: varargs[untyped]): untyped =
if nim_size != c_size or nim_align != c_align: if nim_size != c_size or nim_align != c_align:
var msg = strAlign(`arg`.type.name & ": ") var msg = strAlign(`arg`.type.name & ": ")
if nim_size != c_size: if nim_size != c_size:
msg.add " size(got, expected): " & $nim_size & " != " & $c_size msg.add " size(got, expected): " & $nim_size & " != " & $c_size
if nim_align != c_align: if nim_align != c_align:
msg.add " align(get, expected): " & $nim_align & " != " & $c_align msg.add " align(get, expected): " & $nim_align & " != " & $c_align
echo msg echo msg
failed = true failed = true
macro testOffsetOf(a,b1,b2: untyped): untyped = macro testOffsetOf(a, b: untyped): untyped =
let typeName = newLit(a.repr) let typeName = newLit(a.repr)
let member = newLit(b2.repr) let member = newLit(b.repr)
result = quote do: result = quote do:
let let
c_offset = c_offsetof(`a`,`b1`) c_offset = c_offsetof(`a`,`b`)
nim_offset = offsetof(`a`,`b2`) nim_offset = offsetof(`a`,`b`)
if c_offset != nim_offset: if c_offset != nim_offset:
echo `typeName`, ".", `member`, " offsetError, C: ", c_offset, " nim: ", nim_offset echo `typeName`, ".", `member`, " offsetError, C: ", c_offset, " nim: ", nim_offset
failed = true failed = true
template testOffsetOf(a,b: untyped): untyped =
testOffsetOf(a,b,b)
proc strAlign(arg: string): string = proc strAlign(arg: string): string =
const minLen = 22 const minLen = 22
result = arg result = arg
@ -337,16 +334,16 @@ testinstance:
testOffsetOf(AlignAtEnd, b) testOffsetOf(AlignAtEnd, b)
testOffsetOf(AlignAtEnd, c) testOffsetOf(AlignAtEnd, c)
testOffsetOf(SimpleBranch, "_Ukind", a) testOffsetOf(SimpleBranch, a)
testOffsetOf(SimpleBranch, "_Ukind", b) testOffsetOf(SimpleBranch, b)
testOffsetOf(SimpleBranch, "_Ukind", c) testOffsetOf(SimpleBranch, c)
testOffsetOf(PaddingBeforeBranchA, cause) testOffsetOf(PaddingBeforeBranchA, cause)
testOffsetOf(PaddingBeforeBranchA, "_Ukind", a) testOffsetOf(PaddingBeforeBranchA, a)
testOffsetOf(PaddingBeforeBranchB, cause) testOffsetOf(PaddingBeforeBranchB, cause)
testOffsetOf(PaddingBeforeBranchB, "_Ukind", a) testOffsetOf(PaddingBeforeBranchB, a)
testOffsetOf(PaddingAfterBranch, "_Ukind", a) testOffsetOf(PaddingAfterBranch, a)
testOffsetOf(PaddingAfterBranch, cause) testOffsetOf(PaddingAfterBranch, cause)
testOffsetOf(Foobar, c) testOffsetOf(Foobar, c)
@ -367,15 +364,15 @@ testinstance:
testOffsetOf(EnumObjectB, d) testOffsetOf(EnumObjectB, d)
testOffsetOf(RecursiveStuff, kind) testOffsetOf(RecursiveStuff, kind)
testOffsetOf(RecursiveStuff, "_Ukind.S1.a", a) testOffsetOf(RecursiveStuff, a)
testOffsetOf(RecursiveStuff, "_Ukind.S2.b", b) testOffsetOf(RecursiveStuff, b)
testOffsetOf(RecursiveStuff, "_Ukind.S3.kind2", kind2) testOffsetOf(RecursiveStuff, kind2)
testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S1.ca1", ca1) testOffsetOf(RecursiveStuff, ca1)
testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S1.ca2", ca2) testOffsetOf(RecursiveStuff, ca2)
testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S2.cb", cb) testOffsetOf(RecursiveStuff, cb)
testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S3.cc", cc) testOffsetOf(RecursiveStuff, cc)
testOffsetOf(RecursiveStuff, "_Ukind.S3.d1", d1) testOffsetOf(RecursiveStuff, d1)
testOffsetOf(RecursiveStuff, "_Ukind.S3.d2", d2) testOffsetOf(RecursiveStuff, d2)
main() main()