diff options
-rw-r--r-- | compiler/ast.nim | 14 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 142 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 2 | ||||
-rw-r--r-- | compiler/cgen.nim | 5 | ||||
-rw-r--r-- | compiler/semstmts.nim | 14 | ||||
-rw-r--r-- | lib/nimbase.h | 7 | ||||
-rw-r--r-- | lib/system/excpt.nim | 2 | ||||
-rw-r--r-- | tests/exception/tdont_overwrite_typename.nim | 1 | ||||
-rw-r--r-- | tests/exception/texcas.nim | 1 | ||||
-rw-r--r-- | tests/exception/tnestedreturn.nim | 1 |
10 files changed, 110 insertions, 79 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 0639ebf8e..02f5ae67e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1657,6 +1657,20 @@ proc toObject*(typ: PType): PType = if result.kind == tyRef: result = result.lastSon +proc isException*(t: PType): bool = + # check if `y` is object type and it inherits from Exception + assert(t != nil) + + if t.kind != tyObject: + return false + + var base = t + while base != nil: + if base.sym.magic == mException: + return true + base = base.lastSon + return false + proc findUnresolvedStatic*(n: PNode): PNode = if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil: return n diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index c085c82db..9c7bced33 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -779,91 +779,111 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) = else: genOrdinalCase(p, t, d) + proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # code to generate: # - # XXX: There should be a standard dispatch algorithm - # that's used both here and with multi-methods - # # try # { # myDiv(4, 9); - # } catch (NimException& exp) { - # if (isObj(exp, EIO) { - # ... - # } else if (isObj(exp, ESystem) { - # ... - # finallyPart() - # raise; - # } else { - # // general handler - # } - # } - # finallyPart(); + # } catch (NimExceptionType1&) { + # body + # goto LA_END; + # } catch (NimExceptionType2&) { + # finallyPart() + # raise; + # goto LA_END; + # } catch (NimExceptionType3&) {goto LA1;} + # } catch (NimExceptionType4&) {goto LA1;} + # } catch (NimExceptionType5&) {goto LA2;} + # } catch (NimExceptionType6&) {goto LA2;} + # catch(...) { + # // general handler + # goto LA_END; + # } + # {LA1: + # labeled_branch_body_LA1 + # goto LA_END; + # } + # {LA2: + # labeled_branch_body_LA2 + # finallyPart() + # raise; + # goto LA_END; + # } + # LA_END: + # finallyPart(); + + template genExceptBranchBody(body: PNode) {.dirty.} = + if optStackTrace in p.options: + linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + expr(p, body, d) + linefmt(p, cpsStmts, "#popCurrentException();$n") + linefmt(p, cpsStmts, "goto $1;$n", end_label) + + if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) genLineDir(p, t) - let exc = getTempName(p.module) - if getCompilerProc("Exception") != nil: - discard cgsym(p.module, "Exception") - else: - discard cgsym(p.module, "E_Base") + + discard cgsym(p.module, "Exception") add(p.nestedTryStmts, t) startBlock(p, "try {$n") - expr(p, t.sons[0], d) - let length = sonsLen(t) - endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc])) - if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") - inc p.inExceptBlock - var i = 1 + expr(p, t[0], d) + endBlock(p, ropecg(p.module, "}")) + + let end_label = getLabel(p) var catchAllPresent = false - while (i < length) and (t.sons[i].kind == nkExceptBranch): + var labeled_branches: seq[tuple[label: Rope, body: PNode]] = @[] # generated after labels discovered + + inc p.inExceptBlock + for i in 1..<t.len: + if t[i].kind != nkExceptBranch: break + # bug #4230: avoid false sharing between branches: if d.k == locTemp and isEmptyType(t.typ): d.k = locNone - let blen = sonsLen(t.sons[i]) - if i > 1: addf(p.s(cpsStmts), "else ", []) - if blen == 1: + + if t[i].len == 1: # general except section: catchAllPresent = true - startBlock(p) - expr(p, t.sons[i].sons[0], d) - linefmt(p, cpsStmts, "#popCurrentException();$n") - endBlock(p) - else: - var orExpr: Rope = nil - for j in countup(0, blen - 2): - assert(t.sons[i].sons[j].kind == nkType) - if orExpr != nil: add(orExpr, "||") - appcg(p.module, orExpr, - "#isObj($1.exp->m_type, $2)", - [exc, genTypeInfo(p.module, t[i][j].typ, t[i][j].info)]) - lineF(p, cpsStmts, "if ($1) ", [orExpr]) - startBlock(p) - expr(p, t.sons[i].sons[blen-1], d) - linefmt(p, cpsStmts, "#popCurrentException();$n") + startBlock(p, "catch (...) {$n") + genExceptBranchBody(t[i][0]) endBlock(p) - inc(i) - # reraise the exception if there was no catch all - # and none of the handlers matched - if not catchAllPresent: - if i > 1: lineF(p, cpsStmts, "else ", []) - startBlock(p) - var finallyBlock = t.lastSon - if finallyBlock.kind == nkFinally: - #expr(p, finallyBlock.sons[0], d) - genStmts(p, finallyBlock.sons[0]) + elif t[i].len == 2: + startBlock(p, "catch ($1*) {$n", getTypeDesc(p.module, t[i][0].typ)) + genExceptBranchBody(t[i][^1]) + endBlock(p) + else: + # cpp can't catch multiple types in one statement so we need a label and goto + let label = getLabel(p) + labeled_branches.add((label, t[i][^1])) + for j in 0..t[i].len-2: + assert(t[i][j].kind == nkType) + linefmt(p, cpsStmts, "catch ($1*) {goto $2;}$n", + [getTypeDesc(p.module, t[i][j].typ), label]) + + if not catchAllPresent and t[^1].kind == nkFinally: + # finally requires catch all presence + startBlock(p, "catch (...) {$n") + genSimpleBlock(p, t[^1][0]) line(p, cpsStmts, ~"throw;$n") endBlock(p) - lineF(p, cpsStmts, "}$n", []) # end of catch block - dec p.inExceptBlock + # generate labeled branches bodies + for label, body in labeled_branches.items(): + startBlock(p) + fixLabel(p, label) + genExceptBranchBody(body) + endBlock(p) + fixLabel(p, end_label) + dec p.inExceptBlock discard pop(p.nestedTryStmts) - if (i < length) and (t.sons[i].kind == nkFinally): - genSimpleBlock(p, t.sons[i].sons[0]) + + if t[^1].kind == nkFinally: + genSimpleBlock(p, t[^1][0]) proc genTry(p: BProc, t: PNode, d: var TLoc) = # code to generate: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 3a001ebf7..6f9da56e3 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -569,6 +569,8 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, elif m.compileToCpp: appcg(m, result, " : public $1 {$n", [getTypeDescAux(m, typ.sons[0].skipTypes(skipPtrs), check)]) + if typ.isException: + appcg(m, result, "virtual void raise() {throw this;}$n") # required for polymorphic exceptions hasField = true else: appcg(m, result, " {$n $1 Sup;$n", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ed9e4b7a4..8b3da223f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -260,6 +260,11 @@ proc rdCharLoc(a: TLoc): Rope = proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, takeAddr: bool) = + if p.module.compileToCpp and t.isException: + # init vtable in Exception object for polymorphic exceptions + includeHeader(p.module, "<new>") + linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t)) + case analyseObjectWithTypeField(t) of frNone: discard diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f0784021e..18b9a347b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -737,16 +737,10 @@ proc semRaise(c: PContext, n: PNode): PNode = localError(n.info, errExprCannotBeRaised) # check if the given object inherits from Exception - var base = typ.lastSon - while true: - if base.sym.magic == mException: - break - if base.lastSon == nil: - localError(n.info, - "raised object of type $1 does not inherit from Exception", - [typeToString(typ)]) - return - base = base.lastSon + if not typ.lastSon.isException(): + localError(n.info, "raised object of type $1 does not inherit from Exception", + [typeToString(typ)]) + proc addGenericParamListToScope(c: PContext, n: PNode) = if n.kind != nkGenericParams: illFormedAst(n) diff --git a/lib/nimbase.h b/lib/nimbase.h index 69699a2a4..a03407c4f 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -274,13 +274,6 @@ __clang__ # endif # define NIM_BOOL bool # define NIM_NIL 0 -struct NimException -{ - NimException(struct Exception* exp, const char* msg): exp(exp), msg(msg) {} - - struct Exception* exp; - const char* msg; -}; #else # ifdef bool # define NIM_BOOL bool diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 3d75a8704..476582af2 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -320,7 +320,7 @@ proc raiseExceptionAux(e: ref Exception) = quitOrDebug() else: pushCurrentException(e) - {.emit: "throw NimException(`e`, `e`->name);".} + {.emit: "`e`->raise();".} else: if excHandler != nil: if not excHandler.hasRaiseAction or excHandler.raiseAction(e): diff --git a/tests/exception/tdont_overwrite_typename.nim b/tests/exception/tdont_overwrite_typename.nim index 147ccc001..6e3ff816f 100644 --- a/tests/exception/tdont_overwrite_typename.nim +++ b/tests/exception/tdont_overwrite_typename.nim @@ -1,4 +1,5 @@ discard """ + targets: "c cpp" output: '''Check passed Check passed''' """ diff --git a/tests/exception/texcas.nim b/tests/exception/texcas.nim index fee45af3f..298aee707 100644 --- a/tests/exception/texcas.nim +++ b/tests/exception/texcas.nim @@ -1,4 +1,5 @@ discard """ + targets: "c cpp" output: '''Hello Hello ''' diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim index 1480764f1..bf26f4903 100644 --- a/tests/exception/tnestedreturn.nim +++ b/tests/exception/tnestedreturn.nim @@ -1,4 +1,5 @@ discard """ + targets: "c cpp" file: "tnestedreturn.nim" output: "A\nB\nC\n" """ |