make goto based exceptions available for 'nim cpp' (#13244)

* make goto based exceptions available for 'nim cpp'
* optimize seq.add to be comparable to C++'s emplace_back
This commit is contained in:
Andreas Rumpf 2020-01-25 20:00:13 +01:00 • committed by GitHub
commit 6efac70181
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 29 additions and 18 deletions

View file

@ -608,7 +608,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
elif m.compileToCpp: elif m.compileToCpp:
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: if typ.isException and m.config.exc == excCpp:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
if typ.sym.magic == mException: if typ.sym.magic == mException:
# Add cleanup destructor to Exception base class # Add cleanup destructor to Exception base class

View file

@ -342,7 +342,7 @@ 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 not isDefined(p.config, "noCppExceptions"): if p.module.compileToCpp and t.isException and p.config.exc == excCpp:
# init vtable in Exception object for polymorphic exceptions # init vtable in Exception object for polymorphic exceptions
includeHeader(p.module, "<new>") includeHeader(p.module, "<new>")
linefmt(p, section, "new ($1) $2;$n", [rdLoc(a), getTypeDesc(p.module, t)]) linefmt(p, section, "new ($1) $2;$n", [rdLoc(a), getTypeDesc(p.module, t)])

View file

@ -89,6 +89,13 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
# now process command line arguments again, because some options in the # now process command line arguments again, because some options in the
# command line can overwrite the config file's settings # command line can overwrite the config file's settings
extccomp.initVars(conf) extccomp.initVars(conf)
# XXX This is hacky. We need to find a better way.
case conf.command
of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp
else:
discard
self.processCmdLine(passCmd2, "", conf) self.processCmdLine(passCmd2, "", conf)
if conf.command == "": if conf.command == "":
rawMessage(conf, errGenerated, "command missing") rawMessage(conf, errGenerated, "command missing")

View file

@ -469,9 +469,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "gcmarkandsweep") defineSymbol(conf.symbols, "gcmarkandsweep")
of "destructors", "arc": of "destructors", "arc":
conf.selectedGC = gcArc conf.selectedGC = gcArc
when true: if conf.cmd != cmdCompileToCpp:
if conf.cmd != cmdCompileToCpp: conf.exc = excGoto
conf.exc = excGoto
defineSymbol(conf.symbols, "gcdestructors") defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "gcarc") defineSymbol(conf.symbols, "gcarc")
incl conf.globalOptions, optSeqDestructors incl conf.globalOptions, optSeqDestructors
@ -481,9 +480,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "nimV2") defineSymbol(conf.symbols, "nimV2")
of "orc": of "orc":
conf.selectedGC = gcOrc conf.selectedGC = gcOrc
when true: if conf.cmd != cmdCompileToCpp:
if conf.cmd != cmdCompileToCpp: conf.exc = excGoto
conf.exc = excGoto
defineSymbol(conf.symbols, "gcdestructors") defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "gcorc") defineSymbol(conf.symbols, "gcorc")
incl conf.globalOptions, optSeqDestructors incl conf.globalOptions, optSeqDestructors

View file

@ -185,11 +185,12 @@ proc mainCommand*(graph: ModuleGraph) =
of "c", "cc", "compile", "compiletoc": of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently # compile means compileToC currently
conf.cmd = cmdCompileToC conf.cmd = cmdCompileToC
if conf.exc == excNone: conf.exc = excSetjmp
defineSymbol(graph.config.symbols, "c") defineSymbol(graph.config.symbols, "c")
commandCompileToC(graph) commandCompileToC(graph)
of "cpp", "compiletocpp": of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp conf.cmd = cmdCompileToCpp
conf.exc = excCpp if conf.exc == excNone: conf.exc = excCpp
defineSymbol(graph.config.symbols, "cpp") defineSymbol(graph.config.symbols, "cpp")
commandCompileToC(graph) commandCompileToC(graph)
of "objc", "compiletooc": of "objc", "compiletooc":

View file

@ -159,6 +159,7 @@ type
ccTcc, ccPcc, ccUcc, ccIcl, ccIcc, ccClangCl ccTcc, ccPcc, ccUcc, ccIcl, ccIcc, ccClangCl
ExceptionSystem* = enum ExceptionSystem* = enum
excNone, # no exception system selected yet
excSetjmp, # setjmp based exception handling excSetjmp, # setjmp based exception handling
excCpp, # use C++'s native exception handling excCpp, # use C++'s native exception handling
excGoto, # exception handling based on goto (should become the new default for C) excGoto, # exception handling based on goto (should become the new default for C)

View file

@ -29,8 +29,8 @@ const
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy} wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy}
converterPragmas* = procPragmas - {wNoDestroy} converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp, wNoDestroy} methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty, templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
wDelegator, wExportNims, wUsed, wPragma} wDelegator, wExportNims, wUsed, wPragma}
macroPragmas* = declPragmas + {FirstCallConv..LastCallConv, macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,

View file

@ -2187,7 +2187,6 @@ proc evalConstExprAux(module: PSym;
setupGlobalCtx(module, g) setupGlobalCtx(module, g)
var c = PCtx g.vm var c = PCtx g.vm
let oldMode = c.mode let oldMode = c.mode
defer: c.mode = oldMode
c.mode = mode c.mode = mode
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt) let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info) if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)
@ -2198,6 +2197,7 @@ proc evalConstExprAux(module: PSym;
#for i in 0..<c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) #for i in 0..<c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode result = rawExecute(c, start, tos).regToNode
if result.info.col < 0: result.info = n.info if result.info.col < 0: result.info = n.info
c.mode = oldMode
proc evalConstExpr*(module: PSym; g: ModuleGraph; e: PNode): PNode = proc evalConstExpr*(module: PSym; g: ModuleGraph; e: PNode): PNode =
result = evalConstExprAux(module, g, nil, e, emConst) result = evalConstExprAux(module, g, nil, e, emConst)

View file

@ -61,7 +61,7 @@ var
currException {.threadvar.}: ref Exception currException {.threadvar.}: ref Exception
gcFramePtr {.threadvar.}: GcFrame gcFramePtr {.threadvar.}: GcFrame
when defined(cpp) and not defined(noCppExceptions): when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions:
var var
raiseCounter {.threadvar.}: uint raiseCounter {.threadvar.}: uint
@ -410,7 +410,7 @@ proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
discard() discard()
proc nimLeaveFinally() {.compilerRtl.} = proc nimLeaveFinally() {.compilerRtl.} =
when defined(cpp) and not defined(noCppExceptions): when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions:
{.emit: "throw;".} {.emit: "throw;".}
else: else:
if excHandler != nil: if excHandler != nil:
@ -439,7 +439,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
if not localRaiseHook(e): return if not localRaiseHook(e): return
if globalRaiseHook != nil: if globalRaiseHook != nil:
if not globalRaiseHook(e): return if not globalRaiseHook(e): return
when defined(cpp) and not defined(noCppExceptions): when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions:
if e == currException: if e == currException:
{.emit: "throw;".} {.emit: "throw;".}
else: else:
@ -544,7 +544,7 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} =
framePtr = s framePtr = s
if s.calldepth == nimCallDepthLimit: callDepthLimitReached() if s.calldepth == nimCallDepthLimit: callDepthLimitReached()
when defined(cpp) and appType != "lib" and when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
not defined(js) and not defined(nimscript) and not defined(js) and not defined(nimscript) and
hostOS != "standalone" and not defined(noCppExceptions): hostOS != "standalone" and not defined(noCppExceptions):

View file

@ -80,7 +80,7 @@ proc addEntry(entry: LogEntry) =
#inc gLog.count #inc gLog.count
#gLog.disabled = false #gLog.disabled = false
proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.compilerProc.} = proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.compilerproc.} =
addEntry LogEntry(op: "write", address: address, addEntry LogEntry(op: "write", address: address,
size: size, file: file, line: line, thread: myThreadId()) size: size, file: file, line: line, thread: myThreadId())

View file

@ -92,7 +92,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
for i in oldLen .. newLen-1: for i in oldLen .. newLen-1:
xu.p.data[i] = value xu.p.data[i] = value
proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffect.} = proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffect, nodestroy.} =
## Generic proc for adding a data item `y` to a container `x`. ## Generic proc for adding a data item `y` to a container `x`.
## ##
## For containers that have an order, `add` means *append*. New generic ## For containers that have an order, `add` means *append*. New generic
@ -104,6 +104,10 @@ proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffec
if xu.p == nil or xu.p.cap < oldLen+1: if xu.p == nil or xu.p.cap < oldLen+1:
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T))) xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T)))
xu.len = oldLen+1 xu.len = oldLen+1
# .nodestroy means `xu.p.data[oldLen] = value` is compiled into a
# copyMem(). This is fine as know by construction that
# in `xu.p.data[oldLen]` there is nothing to destroy.
# We also save the `wasMoved + destroy` pair for the sink parameter.
xu.p.data[oldLen] = value xu.p.data[oldLen] = value
proc setLen[T](s: var seq[T], newlen: Natural) = proc setLen[T](s: var seq[T], newlen: Natural) =