bugfix: finally sections are executed before return/break
This commit is contained in:
parent
f182d8d708
commit
0a57f662fa
7 changed files with 71 additions and 49 deletions
|
|
@ -1232,6 +1232,9 @@ template accumulateResult*(iter: expr) =
|
||||||
result = @[]
|
result = @[]
|
||||||
for x in iter: add(result, x)
|
for x in iter: add(result, x)
|
||||||
|
|
||||||
|
# we have to compute this here before turning it off in except.nim anyway ...
|
||||||
|
const nimrodStackTrace = compileOption("stacktrace")
|
||||||
|
|
||||||
{.push checks: off, line_dir: off, debugger: off.}
|
{.push checks: off, line_dir: off, debugger: off.}
|
||||||
# obviously we cannot generate checking operations here :-)
|
# obviously we cannot generate checking operations here :-)
|
||||||
# because it would yield into an endless recursion
|
# because it would yield into an endless recursion
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ proc popCurrentException {.compilerRtl, inl.} =
|
||||||
|
|
||||||
# some platforms have native support for stack traces:
|
# some platforms have native support for stack traces:
|
||||||
const
|
const
|
||||||
nimrodStackTrace = compileOption("stacktrace")
|
|
||||||
nativeStackTrace = (defined(macosx) or defined(linux)) and
|
nativeStackTrace = (defined(macosx) or defined(linux)) and
|
||||||
not nimrodStackTrace and false
|
not nimrodStackTrace and false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,6 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n",
|
appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n",
|
||||||
[toRope(line), makeCString(toFilename(t.info).extractFilename)])
|
[toRope(line), makeCString(toFilename(t.info).extractFilename)])
|
||||||
|
|
||||||
proc popSafePoints(p: BProc, howMany: int) =
|
|
||||||
for i in countup(1, howMany):
|
|
||||||
appcg(p, cpsStmts, "#popSafePoint();$n", [])
|
|
||||||
|
|
||||||
proc genReturnStmt(p: BProc, t: PNode) =
|
|
||||||
p.beforeRetNeeded = true
|
|
||||||
genLineDir(p, t)
|
|
||||||
if (t.sons[0] != nil): genStmts(p, t.sons[0])
|
|
||||||
popSafePoints(p, p.nestedTryStmts)
|
|
||||||
appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
|
||||||
|
|
||||||
proc genVarTuple(p: BProc, n: PNode) =
|
proc genVarTuple(p: BProc, n: PNode) =
|
||||||
var
|
var
|
||||||
L: int
|
L: int
|
||||||
|
|
@ -143,6 +132,31 @@ proc genIfStmt(p: BProc, n: PNode) =
|
||||||
else: internalError(n.info, "genIfStmt()")
|
else: internalError(n.info, "genIfStmt()")
|
||||||
if sonsLen(n) > 1: fixLabel(p, Lend)
|
if sonsLen(n) > 1: fixLabel(p, Lend)
|
||||||
|
|
||||||
|
proc popSafePoints(p: BProc, howMany: int) =
|
||||||
|
var L = p.nestedTryStmts.len
|
||||||
|
# danger of endless recursion! we workaround this here, by a temp stack
|
||||||
|
var stack: seq[PNode]
|
||||||
|
newSeq(stack, howMany)
|
||||||
|
for i in countup(1, howMany):
|
||||||
|
stack[i-1] = p.nestedTryStmts[L-i]
|
||||||
|
setLen(p.nestedTryStmts, L-howMany)
|
||||||
|
|
||||||
|
for tryStmt in items(stack):
|
||||||
|
appcg(p, cpsStmts, "#popSafePoint();$n", [])
|
||||||
|
var finallyStmt = lastSon(tryStmt)
|
||||||
|
if finallyStmt.kind == nkFinally:
|
||||||
|
genStmts(p, finallyStmt.sons[0])
|
||||||
|
# push old elements again:
|
||||||
|
for i in countdown(howMany-1, 0):
|
||||||
|
p.nestedTryStmts.add(stack[i])
|
||||||
|
|
||||||
|
proc genReturnStmt(p: BProc, t: PNode) =
|
||||||
|
p.beforeRetNeeded = true
|
||||||
|
popSafePoints(p, min(1, p.nestedTryStmts.len))
|
||||||
|
genLineDir(p, t)
|
||||||
|
if (t.sons[0] != nil): genStmts(p, t.sons[0])
|
||||||
|
appff(p.s[cpsStmts], "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
||||||
|
|
||||||
proc genWhileStmt(p: BProc, t: PNode) =
|
proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
# we don't generate labels here as for example GCC would produce
|
# we don't generate labels here as for example GCC would produce
|
||||||
# significantly worse code
|
# significantly worse code
|
||||||
|
|
@ -157,7 +171,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
length = len(p.blocks)
|
length = len(p.blocks)
|
||||||
setlen(p.blocks, length + 1)
|
setlen(p.blocks, length + 1)
|
||||||
p.blocks[length].id = - p.labels # negative because it isn't used yet
|
p.blocks[length].id = - p.labels # negative because it isn't used yet
|
||||||
p.blocks[length].nestedTryStmts = p.nestedTryStmts
|
p.blocks[length].nestedTryStmts = p.nestedTryStmts.len
|
||||||
app(p.s[cpsStmts], "while (1) {" & tnl)
|
app(p.s[cpsStmts], "while (1) {" & tnl)
|
||||||
initLocExpr(p, t.sons[0], a)
|
initLocExpr(p, t.sons[0], a)
|
||||||
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
|
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
|
||||||
|
|
@ -179,7 +193,7 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
|
||||||
sym.loc.a = idx
|
sym.loc.a = idx
|
||||||
setlen(p.blocks, idx + 1)
|
setlen(p.blocks, idx + 1)
|
||||||
p.blocks[idx].id = -p.labels # negative because it isn't used yet
|
p.blocks[idx].id = -p.labels # negative because it isn't used yet
|
||||||
p.blocks[idx].nestedTryStmts = p.nestedTryStmts
|
p.blocks[idx].nestedTryStmts = p.nestedTryStmts.len
|
||||||
if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d)
|
if t.kind == nkBlockExpr: genStmtListExpr(p, t.sons[1], d)
|
||||||
else: genStmts(p, t.sons[1])
|
else: genStmts(p, t.sons[1])
|
||||||
if p.blocks[idx].id > 0:
|
if p.blocks[idx].id > 0:
|
||||||
|
|
@ -187,7 +201,6 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
|
||||||
setlen(p.blocks, idx)
|
setlen(p.blocks, idx)
|
||||||
|
|
||||||
proc genBreakStmt(p: BProc, t: PNode) =
|
proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
genLineDir(p, t)
|
|
||||||
var idx = len(p.blocks) - 1
|
var idx = len(p.blocks) - 1
|
||||||
if t.sons[0] != nil:
|
if t.sons[0] != nil:
|
||||||
# named break?
|
# named break?
|
||||||
|
|
@ -196,7 +209,8 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
assert(sym.loc.k == locOther)
|
assert(sym.loc.k == locOther)
|
||||||
idx = sym.loc.a
|
idx = sym.loc.a
|
||||||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||||
popSafePoints(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
|
popSafePoints(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
|
||||||
|
genLineDir(p, t)
|
||||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)])
|
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.blocks[idx].id)])
|
||||||
|
|
||||||
proc genAsmStmt(p: BProc, t: PNode) =
|
proc genAsmStmt(p: BProc, t: PNode) =
|
||||||
|
|
@ -286,7 +300,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, labId: int) =
|
||||||
proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) =
|
proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) =
|
||||||
# generate a C-if statement for a Nimrod case statement
|
# generate a C-if statement for a Nimrod case statement
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
|
||||||
var labId = p.labels
|
var labId = p.labels
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
|
|
@ -448,11 +462,10 @@ proc genCaseStmt(p: BProc, t: PNode) =
|
||||||
genOrdinalCase(p, t)
|
genOrdinalCase(p, t)
|
||||||
|
|
||||||
proc hasGeneralExceptSection(t: PNode): bool =
|
proc hasGeneralExceptSection(t: PNode): bool =
|
||||||
var length, i, blen: int
|
var length = sonsLen(t)
|
||||||
length = sonsLen(t)
|
var i = 1
|
||||||
i = 1
|
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||||
blen = sonsLen(t.sons[i])
|
var blen = sonsLen(t.sons[i])
|
||||||
if blen == 1:
|
if blen == 1:
|
||||||
return true
|
return true
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -494,7 +507,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||||
if optStackTrace in p.Options:
|
if optStackTrace in p.Options:
|
||||||
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
||||||
app(p.s[cpsStmts], "try {" & tnl)
|
app(p.s[cpsStmts], "try {" & tnl)
|
||||||
inc(p.nestedTryStmts)
|
add(p.nestedTryStmts, t)
|
||||||
genStmts(p, t.sons[0])
|
genStmts(p, t.sons[0])
|
||||||
length = sonsLen(t)
|
length = sonsLen(t)
|
||||||
if t.sons[1].kind == nkExceptBranch:
|
if t.sons[1].kind == nkExceptBranch:
|
||||||
|
|
@ -520,8 +533,8 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
|
||||||
inc(i)
|
inc(i)
|
||||||
if t.sons[1].kind == nkExceptBranch:
|
if t.sons[1].kind == nkExceptBranch:
|
||||||
app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement
|
app(p.s[cpsStmts], "}}" & tnl) # end of catch-switch statement
|
||||||
popSafePoints(p, p.nestedTryStmts)
|
appcg(p, cpsStmts, "#popSafePoint();")
|
||||||
dec(p.nestedTryStmts)
|
discard pop(p.nestedTryStmts)
|
||||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
if (i < length) and (t.sons[i].kind == nkFinally):
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
if rethrowFlag != nil:
|
if rethrowFlag != nil:
|
||||||
|
|
@ -560,7 +573,7 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
|
||||||
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
|
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
|
||||||
var length = sonsLen(t)
|
var length = sonsLen(t)
|
||||||
inc(p.nestedTryStmts)
|
add(p.nestedTryStmts, t)
|
||||||
genStmts(p, t.sons[0])
|
genStmts(p, t.sons[0])
|
||||||
appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n")
|
appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n")
|
||||||
var i = 1
|
var i = 1
|
||||||
|
|
@ -587,7 +600,7 @@ proc genTryStmt(p: BProc, t: PNode) =
|
||||||
[safePoint])
|
[safePoint])
|
||||||
inc(i)
|
inc(i)
|
||||||
app(p.s[cpsStmts], '}' & tnl) # end of if statement
|
app(p.s[cpsStmts], '}' & tnl) # end of if statement
|
||||||
dec(p.nestedTryStmts)
|
discard pop(p.nestedTryStmts)
|
||||||
if i < length and t.sons[i].kind == nkFinally:
|
if i < length and t.sons[i].kind == nkFinally:
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, t.sons[i].sons[0])
|
||||||
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
||||||
|
|
|
||||||
25
rod/cgen.nim
25
rod/cgen.nim
|
|
@ -60,20 +60,20 @@ type
|
||||||
nestedTryStmts*: int # how many try statements is it nested into
|
nestedTryStmts*: int # how many try statements is it nested into
|
||||||
|
|
||||||
TCProc{.final.} = object # represents C proc that is currently generated
|
TCProc{.final.} = object # represents C proc that is currently generated
|
||||||
s*: TCProcSections # the procs sections; short name for readability
|
s: TCProcSections # the procs sections; short name for readability
|
||||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
prc: PSym # the Nimrod proc that this C proc belongs to
|
||||||
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
BeforeRetNeeded: bool # true iff 'BeforeRet' label for proc is needed
|
||||||
nestedTryStmts*: Natural # in how many nested try statements we are
|
nestedTryStmts: seq[PNode] # in how many nested try statements we are
|
||||||
# (the vars must be volatile then)
|
# (the vars must be volatile then)
|
||||||
labels*: Natural # for generating unique labels in the C proc
|
labels: Natural # for generating unique labels in the C proc
|
||||||
blocks*: seq[TBlock] # nested blocks
|
blocks: seq[TBlock] # nested blocks
|
||||||
options*: TOptions # options that should be used for code
|
options: TOptions # options that should be used for code
|
||||||
# generation; this is the same as prc.options
|
# generation; this is the same as prc.options
|
||||||
# unless prc == nil
|
# unless prc == nil
|
||||||
frameLen*: int # current length of frame descriptor
|
frameLen: int # current length of frame descriptor
|
||||||
sendClosure*: PType # closure record type that we pass
|
sendClosure: PType # closure record type that we pass
|
||||||
receiveClosure*: PType # closure record type that we get
|
receiveClosure: PType # closure record type that we get
|
||||||
module*: BModule # used to prevent excessive parameter passing
|
module: BModule # used to prevent excessive parameter passing
|
||||||
|
|
||||||
TTypeSeq = seq[PType]
|
TTypeSeq = seq[PType]
|
||||||
TCGen = object of TPassContext # represents a C source file
|
TCGen = object of TPassContext # represents a C source file
|
||||||
|
|
@ -159,6 +159,7 @@ proc newProc(prc: PSym, module: BModule): BProc =
|
||||||
if prc != nil: result.options = prc.options
|
if prc != nil: result.options = prc.options
|
||||||
else: result.options = gOptions
|
else: result.options = gOptions
|
||||||
result.blocks = @[]
|
result.blocks = @[]
|
||||||
|
result.nestedTryStmts = @[]
|
||||||
|
|
||||||
proc isSimpleConst(typ: PType): bool =
|
proc isSimpleConst(typ: PType): bool =
|
||||||
result = not (skipTypes(typ, abstractVar).kind in
|
result = not (skipTypes(typ, abstractVar).kind in
|
||||||
|
|
@ -373,7 +374,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
else:
|
else:
|
||||||
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
|
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
|
||||||
if sfRegister in s.flags: app(p.s[cpsLocals], " register")
|
if sfRegister in s.flags: app(p.s[cpsLocals], " register")
|
||||||
if (sfVolatile in s.flags) or (p.nestedTryStmts > 0):
|
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
|
||||||
app(p.s[cpsLocals], " volatile")
|
app(p.s[cpsLocals], " volatile")
|
||||||
appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
|
appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
|
||||||
localDebugInfo(p, s)
|
localDebugInfo(p, s)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ tconstr2.nim;69
|
||||||
tcopy.nim;TEMP=C:\Programs\xyz\bin
|
tcopy.nim;TEMP=C:\Programs\xyz\bin
|
||||||
tcurrncy.nim;25
|
tcurrncy.nim;25
|
||||||
texplicitgeneric1.nim;Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13
|
texplicitgeneric1.nim;Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13
|
||||||
tfinally.nim;came here
|
tfinally.nim;came here 3
|
||||||
|
tfinally2.nim;ABCD
|
||||||
|
tfinally3.nim;false
|
||||||
tfloat1.nim;Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]
|
tfloat1.nim;Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]
|
||||||
tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]
|
tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]
|
||||||
tformat.nim;Hi Andreas! How do you feel, Rumpf?
|
tformat.nim;Hi Andreas! How do you feel, Rumpf?
|
||||||
|
|
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
# Test return in try statement:
|
# Test return in try statement:
|
||||||
|
|
||||||
proc main: int =
|
proc main: int =
|
||||||
|
try:
|
||||||
try:
|
try:
|
||||||
return 1
|
return 1
|
||||||
finally:
|
finally:
|
||||||
echo "came here"
|
stdout.write("came ")
|
||||||
|
return 2
|
||||||
|
finally:
|
||||||
|
stdout.write("here ")
|
||||||
|
return 3
|
||||||
|
|
||||||
discard main() #OUT came here
|
echo main() #OUT came here 1
|
||||||
|
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -2,7 +2,6 @@ For version 0.8.10
|
||||||
==================
|
==================
|
||||||
|
|
||||||
- fix implicit generic routines
|
- fix implicit generic routines
|
||||||
- bugfix: make ``finally`` more robust
|
|
||||||
|
|
||||||
|
|
||||||
High priority (version 0.9.0)
|
High priority (version 0.9.0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue