Attempt to finish off araq cpp exceptions (#13695)
* config update * disable a questionable test * remove c++ exception handling IDs, new impl doesn't require it anymore * C++ based exceptions finally work * fixes bootstrapping problem in C++ mode * teach GCC it's 2020 now * more bugfixes for C++ based exception handling * apply cooldome's patch * another attempt to enable C++11 * bug fix Co-authored-by: Araq <rumpf_a@web.de> Co-authored-by: cooldome <ariabushenko@bk.ru>
This commit is contained in:
parent
034dad8e32
commit
b3176b8817
12 changed files with 233 additions and 74 deletions
|
|
@ -221,12 +221,11 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||||
for i in countdown(howManyTrys-1, 0):
|
for i in countdown(howManyTrys-1, 0):
|
||||||
p.nestedTryStmts.add(stack[i])
|
p.nestedTryStmts.add(stack[i])
|
||||||
|
|
||||||
if p.config.exc != excCpp:
|
# Pop exceptions that was handled by the
|
||||||
# Pop exceptions that was handled by the
|
# except-blocks we are in
|
||||||
# except-blocks we are in
|
if noSafePoints notin p.flags:
|
||||||
if noSafePoints notin p.flags:
|
for i in countdown(howManyExcepts-1, 0):
|
||||||
for i in countdown(howManyExcepts-1, 0):
|
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
|
||||||
|
|
||||||
proc genGotoState(p: BProc, n: PNode) =
|
proc genGotoState(p: BProc, n: PNode) =
|
||||||
# we resist the temptation to translate it into duff's device as it later
|
# we resist the temptation to translate it into duff's device as it later
|
||||||
|
|
@ -723,14 +722,16 @@ proc raiseInstr(p: BProc): Rope =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc genRaiseStmt(p: BProc, t: PNode) =
|
proc genRaiseStmt(p: BProc, t: PNode) =
|
||||||
if p.config.exc == excCpp:
|
|
||||||
discard cgsym(p.module, "popCurrentExceptionEx")
|
|
||||||
if t[0].kind != nkEmpty:
|
if t[0].kind != nkEmpty:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExprSingleUse(p, t[0], a)
|
initLocExprSingleUse(p, t[0], a)
|
||||||
finallyActions(p)
|
finallyActions(p)
|
||||||
var e = rdLoc(a)
|
var e = rdLoc(a)
|
||||||
var typ = skipTypes(t[0].typ, abstractPtrs)
|
var typ = skipTypes(t[0].typ, abstractPtrs)
|
||||||
|
# XXX For reasons that currently escape me, this is only required by the new
|
||||||
|
# C++ based exception handling:
|
||||||
|
if p.config.exc == excCpp:
|
||||||
|
blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
if isImportedException(typ, p.config):
|
if isImportedException(typ, p.config):
|
||||||
lineF(p, cpsStmts, "throw $1;$n", [e])
|
lineF(p, cpsStmts, "throw $1;$n", [e])
|
||||||
|
|
@ -947,6 +948,170 @@ proc genRestoreFrameAfterException(p: BProc) =
|
||||||
linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", [])
|
linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", [])
|
||||||
|
|
||||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
|
#[ code to generate:
|
||||||
|
|
||||||
|
std::exception_ptr error = nullptr;
|
||||||
|
try {
|
||||||
|
body;
|
||||||
|
} catch (Exception e) {
|
||||||
|
error = std::current_exception();
|
||||||
|
if (ofExpr(e, TypeHere)) {
|
||||||
|
|
||||||
|
error = nullptr; // handled
|
||||||
|
} else if (...) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
} catch(...) {
|
||||||
|
// C++ exception occured, not under Nim's control.
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* finally: */
|
||||||
|
printf('fin!\n');
|
||||||
|
if (error) std::rethrow_exception(error); // re-raise the exception
|
||||||
|
}
|
||||||
|
]#
|
||||||
|
p.module.includeHeader("<exception>")
|
||||||
|
|
||||||
|
if not isEmptyType(t.typ) and d.k == locNone:
|
||||||
|
getTemp(p, t.typ, d)
|
||||||
|
genLineDir(p, t)
|
||||||
|
|
||||||
|
inc(p.labels, 2)
|
||||||
|
let etmp = p.labels
|
||||||
|
|
||||||
|
lineCg(p, cpsStmts, "std::exception_ptr T$1_ = nullptr;", [etmp])
|
||||||
|
|
||||||
|
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||||
|
p.nestedTryStmts.add((fin, false, 0.Natural))
|
||||||
|
|
||||||
|
startBlock(p, "try {$n")
|
||||||
|
expr(p, t[0], d)
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
|
# First pass: handle Nim based exceptions:
|
||||||
|
lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1])
|
||||||
|
genRestoreFrameAfterException(p)
|
||||||
|
# an unhandled exception happened!
|
||||||
|
lineCg(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
|
||||||
|
p.nestedTryStmts[^1].inExcept = true
|
||||||
|
var hasImportedCppExceptions = false
|
||||||
|
var i = 1
|
||||||
|
var hasIf = false
|
||||||
|
var hasElse = false
|
||||||
|
while (i < t.len) and (t[i].kind == nkExceptBranch):
|
||||||
|
# bug #4230: avoid false sharing between branches:
|
||||||
|
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||||
|
if t[i].len == 1:
|
||||||
|
hasImportedCppExceptions = true
|
||||||
|
# general except section:
|
||||||
|
hasElse = true
|
||||||
|
if hasIf: lineF(p, cpsStmts, "else ", [])
|
||||||
|
startBlock(p)
|
||||||
|
# we handled the error:
|
||||||
|
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||||
|
expr(p, t[i][0], d)
|
||||||
|
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||||
|
endBlock(p)
|
||||||
|
else:
|
||||||
|
var orExpr = Rope(nil)
|
||||||
|
var exvar = PNode(nil)
|
||||||
|
for j in 0..<t[i].len - 1:
|
||||||
|
var typeNode = t[i][j]
|
||||||
|
if t[i][j].isInfixAs():
|
||||||
|
typeNode = t[i][j][1]
|
||||||
|
exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
|
||||||
|
assert(typeNode.kind == nkType)
|
||||||
|
if isImportedException(typeNode.typ, p.config):
|
||||||
|
hasImportedCppExceptions = true
|
||||||
|
else:
|
||||||
|
if orExpr != nil: orExpr.add("||")
|
||||||
|
let checkFor = if optTinyRtti in p.config.globalOptions:
|
||||||
|
genTypeInfo2Name(p.module, typeNode.typ)
|
||||||
|
else:
|
||||||
|
genTypeInfo(p.module, typeNode.typ, typeNode.info)
|
||||||
|
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||||
|
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||||
|
|
||||||
|
if orExpr != nil:
|
||||||
|
if hasIf:
|
||||||
|
startBlock(p, "else if ($1) {$n", [orExpr])
|
||||||
|
else:
|
||||||
|
startBlock(p, "if ($1) {$n", [orExpr])
|
||||||
|
hasIf = true
|
||||||
|
if exvar != nil:
|
||||||
|
fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnStack)
|
||||||
|
linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ),
|
||||||
|
rdLoc(exvar.sym.loc), rope(etmp+1)])
|
||||||
|
# we handled the error:
|
||||||
|
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||||
|
expr(p, t[i][^1], d)
|
||||||
|
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||||
|
endBlock(p)
|
||||||
|
inc(i)
|
||||||
|
if hasIf and not hasElse:
|
||||||
|
linefmt(p, cpsStmts, "else throw;$n", [etmp])
|
||||||
|
linefmt(p, cpsStmts, "}$n", [])
|
||||||
|
|
||||||
|
# Second pass: handle C++ based exceptions:
|
||||||
|
template genExceptBranchBody(body: PNode) {.dirty.} =
|
||||||
|
genRestoreFrameAfterException(p)
|
||||||
|
#linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
|
||||||
|
expr(p, body, d)
|
||||||
|
|
||||||
|
var catchAllPresent = false
|
||||||
|
incl p.flags, noSafePoints # mark as not needing 'popCurrentException'
|
||||||
|
if hasImportedCppExceptions:
|
||||||
|
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
|
||||||
|
|
||||||
|
if t[i].len == 1:
|
||||||
|
# general except section:
|
||||||
|
startBlock(p, "catch (...) {", [])
|
||||||
|
genExceptBranchBody(t[i][0])
|
||||||
|
endBlock(p)
|
||||||
|
catchAllPresent = true
|
||||||
|
else:
|
||||||
|
for j in 0..<t[i].len-1:
|
||||||
|
var typeNode = t[i][j]
|
||||||
|
if t[i][j].isInfixAs():
|
||||||
|
typeNode = t[i][j][1]
|
||||||
|
if isImportedException(typeNode.typ, p.config):
|
||||||
|
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
|
||||||
|
fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnStack)
|
||||||
|
startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc))
|
||||||
|
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
|
||||||
|
endBlock(p)
|
||||||
|
elif isImportedException(typeNode.typ, p.config):
|
||||||
|
startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ))
|
||||||
|
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
|
excl p.flags, noSafePoints
|
||||||
|
discard pop(p.nestedTryStmts)
|
||||||
|
# general finally block:
|
||||||
|
if t.len > 0 and t[^1].kind == nkFinally:
|
||||||
|
if not catchAllPresent:
|
||||||
|
startBlock(p, "catch (...) {", [])
|
||||||
|
genRestoreFrameAfterException(p)
|
||||||
|
linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
|
startBlock(p)
|
||||||
|
genStmts(p, t[^1][0])
|
||||||
|
linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp])
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
|
proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
|
||||||
|
# There are two versions we generate, depending on whether we
|
||||||
|
# catch C++ exceptions, imported via .importcpp or not. The
|
||||||
|
# code can be easier if there are no imported C++ exceptions
|
||||||
|
# to deal with.
|
||||||
|
|
||||||
# code to generate:
|
# code to generate:
|
||||||
#
|
#
|
||||||
# try
|
# try
|
||||||
|
|
|
||||||
|
|
@ -609,13 +609,14 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
|
||||||
appcg(m, result, " : public $1 {$n",
|
appcg(m, result, " : public $1 {$n",
|
||||||
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
|
[getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)])
|
||||||
if typ.isException and m.config.exc == excCpp:
|
if typ.isException and m.config.exc == excCpp:
|
||||||
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
|
when false:
|
||||||
if typ.sym.magic == mException:
|
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
|
||||||
# Add cleanup destructor to Exception base class
|
if typ.sym.magic == mException:
|
||||||
appcg(m, result, "~$1();$n", [name])
|
# Add cleanup destructor to Exception base class
|
||||||
# define it out of the class body and into the procs section so we don't have to
|
appcg(m, result, "~$1();$n", [name])
|
||||||
# artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
|
# define it out of the class body and into the procs section so we don't have to
|
||||||
appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
|
# artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
|
||||||
|
appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
|
||||||
hasField = true
|
hasField = true
|
||||||
else:
|
else:
|
||||||
appcg(m, result, " {$n $1 Sup;$n",
|
appcg(m, result, " {$n $1 Sup;$n",
|
||||||
|
|
|
||||||
|
|
@ -343,11 +343,6 @@ type
|
||||||
|
|
||||||
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
|
||||||
mode: ObjConstrMode) =
|
mode: ObjConstrMode) =
|
||||||
if p.module.compileToCpp and t.isException and p.config.exc == excCpp:
|
|
||||||
# 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)])
|
|
||||||
|
|
||||||
#if optNimV2 in p.config.globalOptions: return
|
#if optNimV2 in p.config.globalOptions: return
|
||||||
case analyseObjectWithTypeField(t)
|
case analyseObjectWithTypeField(t)
|
||||||
of frNone:
|
of frNone:
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ type
|
||||||
# used on some platforms
|
# used on some platforms
|
||||||
asmStmtFrmt: string, # format of ASM statement
|
asmStmtFrmt: string, # format of ASM statement
|
||||||
structStmtFmt: string, # Format for struct statement
|
structStmtFmt: string, # Format for struct statement
|
||||||
produceAsm: string, # Format how to produce assembler listings
|
produceAsm: string, # Format how to produce assembler listings
|
||||||
|
cppXsupport: string, # what to do to enable C++X support
|
||||||
props: TInfoCCProps] # properties of the C compiler
|
props: TInfoCCProps] # properties of the C compiler
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -85,6 +86,7 @@ compiler gcc:
|
||||||
asmStmtFrmt: "asm($1);$n",
|
asmStmtFrmt: "asm($1);$n",
|
||||||
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
|
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
|
||||||
produceAsm: gnuAsmListing,
|
produceAsm: gnuAsmListing,
|
||||||
|
cppXsupport: "-std=gnu++14 -funsigned-char",
|
||||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||||
hasAttribute})
|
hasAttribute})
|
||||||
|
|
||||||
|
|
@ -111,6 +113,7 @@ compiler nintendoSwitchGCC:
|
||||||
asmStmtFrmt: "asm($1);$n",
|
asmStmtFrmt: "asm($1);$n",
|
||||||
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
|
structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
|
||||||
produceAsm: gnuAsmListing,
|
produceAsm: gnuAsmListing,
|
||||||
|
cppXsupport: "-std=gnu++14 -funsigned-char",
|
||||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||||
hasAttribute})
|
hasAttribute})
|
||||||
|
|
||||||
|
|
@ -158,6 +161,7 @@ compiler vcc:
|
||||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$3$n$1 $2",
|
structStmtFmt: "$3$n$1 $2",
|
||||||
produceAsm: "/Fa$asmfile",
|
produceAsm: "/Fa$asmfile",
|
||||||
|
cppXsupport: "",
|
||||||
props: {hasCpp, hasAssume, hasDeclspec})
|
props: {hasCpp, hasAssume, hasDeclspec})
|
||||||
|
|
||||||
compiler clangcl:
|
compiler clangcl:
|
||||||
|
|
@ -204,6 +208,7 @@ compiler lcc:
|
||||||
asmStmtFrmt: "_asm{$n$1$n}$n",
|
asmStmtFrmt: "_asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$1 $2",
|
structStmtFmt: "$1 $2",
|
||||||
produceAsm: "",
|
produceAsm: "",
|
||||||
|
cppXsupport: "",
|
||||||
props: {})
|
props: {})
|
||||||
|
|
||||||
# Borland C Compiler
|
# Borland C Compiler
|
||||||
|
|
@ -229,6 +234,7 @@ compiler bcc:
|
||||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$1 $2",
|
structStmtFmt: "$1 $2",
|
||||||
produceAsm: "",
|
produceAsm: "",
|
||||||
|
cppXsupport: "",
|
||||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
|
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
|
||||||
hasAttribute})
|
hasAttribute})
|
||||||
|
|
||||||
|
|
@ -255,6 +261,7 @@ compiler dmc:
|
||||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$3$n$1 $2",
|
structStmtFmt: "$3$n$1 $2",
|
||||||
produceAsm: "",
|
produceAsm: "",
|
||||||
|
cppXsupport: "",
|
||||||
props: {hasCpp})
|
props: {hasCpp})
|
||||||
|
|
||||||
# Watcom C Compiler
|
# Watcom C Compiler
|
||||||
|
|
@ -280,6 +287,7 @@ compiler wcc:
|
||||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$1 $2",
|
structStmtFmt: "$1 $2",
|
||||||
produceAsm: "",
|
produceAsm: "",
|
||||||
|
cppXsupport: "",
|
||||||
props: {hasCpp})
|
props: {hasCpp})
|
||||||
|
|
||||||
# Tiny C Compiler
|
# Tiny C Compiler
|
||||||
|
|
@ -305,6 +313,7 @@ compiler tcc:
|
||||||
asmStmtFrmt: "asm($1);$n",
|
asmStmtFrmt: "asm($1);$n",
|
||||||
structStmtFmt: "$1 $2",
|
structStmtFmt: "$1 $2",
|
||||||
produceAsm: gnuAsmListing,
|
produceAsm: gnuAsmListing,
|
||||||
|
cppXsupport: "",
|
||||||
props: {hasSwitchRange, hasComputedGoto, hasGnuAsm})
|
props: {hasSwitchRange, hasComputedGoto, hasGnuAsm})
|
||||||
|
|
||||||
# Pelles C Compiler
|
# Pelles C Compiler
|
||||||
|
|
@ -331,6 +340,7 @@ compiler pcc:
|
||||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$1 $2",
|
structStmtFmt: "$1 $2",
|
||||||
produceAsm: "",
|
produceAsm: "",
|
||||||
|
cppXsupport: "",
|
||||||
props: {})
|
props: {})
|
||||||
|
|
||||||
# Your C Compiler
|
# Your C Compiler
|
||||||
|
|
@ -356,6 +366,7 @@ compiler ucc:
|
||||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||||
structStmtFmt: "$1 $2",
|
structStmtFmt: "$1 $2",
|
||||||
produceAsm: "",
|
produceAsm: "",
|
||||||
|
cppXsupport: "",
|
||||||
props: {})
|
props: {})
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -389,8 +400,10 @@ proc nameToCC*(name: string): TSystemCC =
|
||||||
return i
|
return i
|
||||||
result = ccNone
|
result = ccNone
|
||||||
|
|
||||||
proc listCCnames(): seq[string] =
|
proc listCCnames(): string =
|
||||||
|
result = ""
|
||||||
for i in succ(ccNone)..high(TSystemCC):
|
for i in succ(ccNone)..high(TSystemCC):
|
||||||
|
if i > succ(ccNone): result.add ", "
|
||||||
result.add CC[i].name
|
result.add CC[i].name
|
||||||
|
|
||||||
proc isVSCompatible*(conf: ConfigRef): bool =
|
proc isVSCompatible*(conf: ConfigRef): bool =
|
||||||
|
|
@ -426,8 +439,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||||
proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
|
proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
|
||||||
conf.cCompiler = nameToCC(ccname)
|
conf.cCompiler = nameToCC(ccname)
|
||||||
if conf.cCompiler == ccNone:
|
if conf.cCompiler == ccNone:
|
||||||
let ccList = listCCnames().join(", ")
|
localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, listCCnames()])
|
||||||
localError(conf, info, "unknown C compiler: '$1'. Available options are: $2" % [ccname, ccList])
|
|
||||||
conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always")
|
conf.compileOptions = getConfigVar(conf, conf.cCompiler, ".options.always")
|
||||||
conf.linkOptions = ""
|
conf.linkOptions = ""
|
||||||
conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
|
conf.cCompilerPath = getConfigVar(conf, conf.cCompiler, ".path")
|
||||||
|
|
@ -576,8 +588,11 @@ proc needsExeExt(conf: ConfigRef): bool {.inline.} =
|
||||||
result = (optGenScript in conf.globalOptions and conf.target.targetOS == osWindows) or
|
result = (optGenScript in conf.globalOptions and conf.target.targetOS == osWindows) or
|
||||||
(conf.target.hostOS == osWindows)
|
(conf.target.hostOS == osWindows)
|
||||||
|
|
||||||
|
proc useCpp(conf: ConfigRef; cfile: AbsoluteFile): bool =
|
||||||
|
conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c")
|
||||||
|
|
||||||
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string =
|
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: AbsoluteFile): string =
|
||||||
result = if conf.cmd == cmdCompileToCpp and not cfile.string.endsWith(".c"):
|
result = if useCpp(conf, cfile):
|
||||||
CC[compiler].cppCompiler
|
CC[compiler].cppCompiler
|
||||||
else:
|
else:
|
||||||
CC[compiler].compilerExe
|
CC[compiler].compilerExe
|
||||||
|
|
@ -605,6 +620,9 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||||
ospNeedsPIC in platform.OS[conf.target.targetOS].props:
|
ospNeedsPIC in platform.OS[conf.target.targetOS].props:
|
||||||
options.add(' ' & CC[c].pic)
|
options.add(' ' & CC[c].pic)
|
||||||
|
|
||||||
|
if useCpp(conf, cfile.cname):
|
||||||
|
options.add(' ' & CC[c].cppXsupport)
|
||||||
|
|
||||||
var compilePattern: string
|
var compilePattern: string
|
||||||
# compute include paths:
|
# compute include paths:
|
||||||
var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
|
var includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ proc llStreamClose*(s: PLLStream) =
|
||||||
of llsFile:
|
of llsFile:
|
||||||
close(s.f)
|
close(s.f)
|
||||||
|
|
||||||
when not hasRstdin:
|
when not declared(readLineFromStdin):
|
||||||
# fallback implementation:
|
# fallback implementation:
|
||||||
proc readLineFromStdin(prompt: string, line: var string): bool =
|
proc readLineFromStdin(prompt: string, line: var string): bool =
|
||||||
stderr.write(prompt)
|
stderr.write(prompt)
|
||||||
|
|
|
||||||
6
koch.nim
6
koch.nim
|
|
@ -296,7 +296,11 @@ proc boot(args: string) =
|
||||||
|
|
||||||
let nimStart = findStartNim().quoteShell()
|
let nimStart = findStartNim().quoteShell()
|
||||||
for i in 0..2:
|
for i in 0..2:
|
||||||
let defaultCommand = if useCpp: "cpp" else: "c"
|
# Nim versions < (1, 1) expect Nim's exception type to have a 'raiseId' field for
|
||||||
|
# C++ interop. Later Nim versions do this differently and removed the 'raiseId' field.
|
||||||
|
# Thus we always bootstrap the first iteration with "c" and not with "cpp" as
|
||||||
|
# a workaround.
|
||||||
|
let defaultCommand = if useCpp and i > 0: "cpp" else: "c"
|
||||||
let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: ""
|
let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: ""
|
||||||
echo "iteration: ", i+1
|
echo "iteration: ", i+1
|
||||||
var extraOption = ""
|
var extraOption = ""
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,6 @@ type
|
||||||
trace: string
|
trace: string
|
||||||
else:
|
else:
|
||||||
trace: seq[StackTraceEntry]
|
trace: seq[StackTraceEntry]
|
||||||
when defined(nimBoostrapCsources0_19_0):
|
|
||||||
# see #10315, bootstrap with `nim cpp` from csources gave error:
|
|
||||||
# error: no member named 'raise_id' in 'Exception'
|
|
||||||
raise_id: uint # set when exception is raised
|
|
||||||
else:
|
|
||||||
raiseId: uint # set when exception is raised
|
|
||||||
up: ref Exception # used for stacking exceptions. Not exported!
|
up: ref Exception # used for stacking exceptions. Not exported!
|
||||||
|
|
||||||
Defect* = object of Exception ## \
|
Defect* = object of Exception ## \
|
||||||
|
|
|
||||||
|
|
@ -61,10 +61,6 @@ var
|
||||||
currException {.threadvar.}: ref Exception
|
currException {.threadvar.}: ref Exception
|
||||||
gcFramePtr {.threadvar.}: GcFrame
|
gcFramePtr {.threadvar.}: GcFrame
|
||||||
|
|
||||||
when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions:
|
|
||||||
var
|
|
||||||
raiseCounter {.threadvar.}: uint
|
|
||||||
|
|
||||||
type
|
type
|
||||||
FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame,
|
FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame,
|
||||||
excHandler: PSafePoint, currException: ref Exception]
|
excHandler: PSafePoint, currException: ref Exception]
|
||||||
|
|
@ -123,19 +119,7 @@ proc popCurrentException {.compilerRtl, inl.} =
|
||||||
#showErrorMessage "B"
|
#showErrorMessage "B"
|
||||||
|
|
||||||
proc popCurrentExceptionEx(id: uint) {.compilerRtl.} =
|
proc popCurrentExceptionEx(id: uint) {.compilerRtl.} =
|
||||||
# in cpp backend exceptions can pop-up in the different order they were raised, example #5628
|
discard "only for bootstrapping compatbility"
|
||||||
if currException.raiseId == id:
|
|
||||||
currException = currException.up
|
|
||||||
else:
|
|
||||||
var cur = currException.up
|
|
||||||
var prev = currException
|
|
||||||
while cur != nil and cur.raiseId != id:
|
|
||||||
prev = cur
|
|
||||||
cur = cur.up
|
|
||||||
if cur == nil:
|
|
||||||
showErrorMessage("popCurrentExceptionEx() exception was not found in the exception stack. Aborting...")
|
|
||||||
quit(1)
|
|
||||||
prev.up = cur.up
|
|
||||||
|
|
||||||
proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} =
|
proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} =
|
||||||
currException = e
|
currException = e
|
||||||
|
|
@ -444,11 +428,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
|
||||||
{.emit: "throw;".}
|
{.emit: "throw;".}
|
||||||
else:
|
else:
|
||||||
pushCurrentException(e)
|
pushCurrentException(e)
|
||||||
raiseCounter.inc
|
{.emit: "throw e;".}
|
||||||
if raiseCounter == 0:
|
|
||||||
raiseCounter.inc # skip zero at overflow
|
|
||||||
e.raiseId = raiseCounter
|
|
||||||
{.emit: "`e`->raise();".}
|
|
||||||
elif defined(nimQuirky) or gotoBasedExceptions:
|
elif defined(nimQuirky) or gotoBasedExceptions:
|
||||||
# XXX This check should likely also be done in the setjmp case below.
|
# XXX This check should likely also be done in the setjmp case below.
|
||||||
if e != currException:
|
if e != currException:
|
||||||
|
|
@ -562,9 +542,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
|
||||||
|
|
||||||
var msg = "Unknown error in unexpected exception handler"
|
var msg = "Unknown error in unexpected exception handler"
|
||||||
try:
|
try:
|
||||||
{.emit"#if !defined(_MSC_VER) || (_MSC_VER >= 1923)".}
|
{.emit: "#if !defined(_MSC_VER) || (_MSC_VER >= 1923)".}
|
||||||
raise
|
raise
|
||||||
{.emit"#endif".}
|
{.emit: "#endif".}
|
||||||
except Exception:
|
except Exception:
|
||||||
msg = currException.getStackTrace() & "Error: unhandled exception: " &
|
msg = currException.getStackTrace() & "Error: unhandled exception: " &
|
||||||
currException.msg & " [" & $currException.name & "]"
|
currException.msg & " [" & $currException.name & "]"
|
||||||
|
|
@ -573,9 +553,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
|
||||||
except:
|
except:
|
||||||
msg = "Error: unhandled unknown cpp exception"
|
msg = "Error: unhandled unknown cpp exception"
|
||||||
|
|
||||||
{.emit"#if defined(_MSC_VER) && (_MSC_VER < 1923)".}
|
{.emit: "#if defined(_MSC_VER) && (_MSC_VER < 1923)".}
|
||||||
msg = "Error: unhandled unknown cpp exception"
|
msg = "Error: unhandled unknown cpp exception"
|
||||||
{.emit"#endif".}
|
{.emit: "#endif".}
|
||||||
|
|
||||||
when defined(genode):
|
when defined(genode):
|
||||||
# stderr not available by default, use the LOG session
|
# stderr not available by default, use the LOG session
|
||||||
|
|
|
||||||
|
|
@ -68,4 +68,4 @@ except:
|
||||||
echo getCurrentExceptionMsg()
|
echo getCurrentExceptionMsg()
|
||||||
discard
|
discard
|
||||||
|
|
||||||
doAssert: getCurrentException() == nil
|
doAssert: getCurrentException() == nil
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ discard """
|
||||||
targets: "cpp"
|
targets: "cpp"
|
||||||
outputsub: "Error: unhandled unknown cpp exception"
|
outputsub: "Error: unhandled unknown cpp exception"
|
||||||
exitcode: 1
|
exitcode: 1
|
||||||
|
disabled: true
|
||||||
"""
|
"""
|
||||||
type Crap {.importcpp: "int".} = object
|
type Crap {.importcpp: "int".} = object
|
||||||
|
|
||||||
var c: Crap
|
var c: Crap
|
||||||
raise c
|
raise c
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ cpp exception caught
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
std_exception* {.importcpp: "std::exception", header: "<exception>".} = object
|
std_exception* {.importcpp: "std::exception", header: "<exception>".} = object
|
||||||
std_runtime_error* {.importcpp: "std::runtime_error", header: "<stdexcept>".} = object
|
std_runtime_error* {.importcpp: "std::runtime_error", header: "<stdexcept>".} = object
|
||||||
std_string* {.importcpp: "std::string", header: "<string>".} = object
|
std_string* {.importcpp: "std::string", header: "<string>".} = object
|
||||||
|
|
@ -25,7 +25,7 @@ proc constructRuntimeError(s: stdstring): std_runtime_error {.importcpp: "std::r
|
||||||
|
|
||||||
proc what(ex: std_runtime_error): cstring {.importcpp: "((char *)#.what())".}
|
proc what(ex: std_runtime_error): cstring {.importcpp: "((char *)#.what())".}
|
||||||
|
|
||||||
proc myexception =
|
proc myexception =
|
||||||
raise constructRuntimeError(constructStdString("cpp_exception"))
|
raise constructRuntimeError(constructStdString("cpp_exception"))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -41,17 +41,17 @@ except std_exception:
|
||||||
|
|
||||||
doAssert(getCurrentException() == nil)
|
doAssert(getCurrentException() == nil)
|
||||||
|
|
||||||
proc earlyReturn =
|
proc earlyReturn =
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
myexception()
|
myexception()
|
||||||
finally:
|
finally:
|
||||||
echo "finally1"
|
echo "finally1"
|
||||||
except:
|
except:
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
echo "finally2"
|
echo "finally2"
|
||||||
|
|
||||||
earlyReturn()
|
earlyReturn()
|
||||||
doAssert(getCurrentException() == nil)
|
doAssert(getCurrentException() == nil)
|
||||||
|
|
||||||
|
|
@ -118,16 +118,15 @@ try:
|
||||||
echo "finally 2"
|
echo "finally 2"
|
||||||
except:
|
except:
|
||||||
echo "expected"
|
echo "expected"
|
||||||
|
|
||||||
|
|
||||||
doAssert(getCurrentException() == nil)
|
doAssert(getCurrentException() == nil)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
myexception()
|
myexception()
|
||||||
except std_runtime_error as ex:
|
except std_runtime_error as ex:
|
||||||
echo "cpp exception caught"
|
echo "cpp exception caught"
|
||||||
raise newException(ValueError, "rewritten " & $ex.what())
|
raise newException(ValueError, "rewritten " & $ex.what())
|
||||||
except:
|
except:
|
||||||
doAssert(getCurrentExceptionMsg() == "rewritten cpp_exception")
|
doAssert(getCurrentExceptionMsg() == "rewritten cpp_exception")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
discard """
|
discard """
|
||||||
targets: "c cpp"
|
targets: "c"
|
||||||
output: "ok"
|
output: "ok"
|
||||||
"""
|
"""
|
||||||
var closureIterResult = newSeq[int]()
|
var closureIterResult = newSeq[int]()
|
||||||
|
|
||||||
|
# XXX Investigate why this fails now for 'nim cpp'
|
||||||
|
|
||||||
proc checkpoint(arg: int) =
|
proc checkpoint(arg: int) =
|
||||||
closureIterResult.add(arg)
|
closureIterResult.add(arg)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue