summary refs log tree commit diff stats
path: root/compiler/ccgstmts.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ccgstmts.nim')
-rw-r--r--compiler/ccgstmts.nim346
1 files changed, 163 insertions, 183 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 36816cc2c..91a3add70 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -16,13 +16,17 @@ const
     # above X strings a hash-switch for strings is generated
 
 proc registerGcRoot(p: BProc, v: PSym) =
-  if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
+  if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
       containsGarbageCollectedRef(v.loc.t):
     # we register a specialized marked proc here; this has the advantage
     # that it works out of the box for thread local storage then :-)
     let prc = genTraverseProcForGlobal(p.module, v, v.info)
-    appcg(p.module, p.module.initProc.procSec(cpsInit),
-      "#nimRegisterGlobalMarker($1);$n", [prc])
+    if sfThread in v.flags:
+      appcg(p.module, p.module.initProc.procSec(cpsInit),
+        "#nimRegisterThreadLocalMarker($1);$n", [prc])
+    else:
+      appcg(p.module, p.module.initProc.procSec(cpsInit),
+        "#nimRegisterGlobalMarker($1);$n", [prc])
 
 proc isAssignedImmediately(n: PNode): bool {.inline.} =
   if n.kind == nkEmpty: return false
@@ -33,15 +37,19 @@ proc isAssignedImmediately(n: PNode): bool {.inline.} =
     return false
   result = true
 
+proc inExceptBlockLen(p: BProc): int =
+  for x in p.nestedTryStmts:
+    if x.inExcept: result.inc
+
 proc genVarTuple(p: BProc, n: PNode) =
   var tup, field: TLoc
-  if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
+  if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
   var L = sonsLen(n)
 
   # if we have a something that's been captured, use the lowering instead:
   for i in countup(0, L-3):
     if n[i].kind != nkSym:
-      genStmts(p, lowerTupleUnpacking(n, p.prc))
+      genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc))
       return
 
   genLineDir(p, n)
@@ -62,7 +70,7 @@ proc genVarTuple(p: BProc, n: PNode) =
     if t.kind == tyTuple:
       field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
     else:
-      if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
+      if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
       field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
     putLocIntoDest(p, v.loc, field)
 
@@ -92,7 +100,7 @@ proc startBlock(p: BProc, start: FormatStr = "{$n",
   setLen(p.blocks, result + 1)
   p.blocks[result].id = p.labels
   p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
-  p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
+  p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16
 
 proc assignLabel(b: var TBlock): Rope {.inline.} =
   b.label = "LA" & b.id.rope
@@ -117,7 +125,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
 proc endBlock(p: BProc) =
   let topBlock = p.blocks.len - 1
   var blockEnd = if p.blocks[topBlock].label != nil:
-      rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
+      ropecg(p.module, "} $1: ;$n", p.blocks[topBlock].label)
     else:
       ~"}$n"
   let frameLen = p.blocks[topBlock].frameLen
@@ -141,7 +149,7 @@ template preserveBreakIdx(body: untyped): untyped =
   p.breakIdx = oldBreakIdx
 
 proc genState(p: BProc, n: PNode) =
-  internalAssert n.len == 1
+  internalAssert p.config, n.len == 1
   let n0 = n[0]
   if n0.kind == nkIntLit:
     let idx = n.sons[0].intVal
@@ -149,6 +157,39 @@ proc genState(p: BProc, n: PNode) =
   elif n0.kind == nkStrLit:
     linefmt(p, cpsStmts, "$1: ;$n", n0.strVal.rope)
 
+proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
+  # Called by return and break stmts.
+  # Deals with issues faced when jumping out of try/except/finally stmts,
+
+  var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
+
+  for i in countup(1, howManyTrys):
+    let tryStmt = p.nestedTryStmts.pop
+    if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
+      # Pop safe points generated by try
+      if not tryStmt.inExcept:
+        linefmt(p, cpsStmts, "#popSafePoint();$n")
+
+    # Pop this try-stmt of the list of nested trys
+    # so we don't infinite recurse on it in the next step.
+    stack.add(tryStmt)
+
+    # Find finally-stmt for this try-stmt
+    # and generate a copy of its sons
+    var finallyStmt = lastSon(tryStmt.n)
+    if finallyStmt.kind == nkFinally:
+      genStmts(p, finallyStmt.sons[0])
+
+  # push old elements again:
+  for i in countdown(howManyTrys-1, 0):
+    p.nestedTryStmts.add(stack[i])
+
+  if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
+    # Pop exceptions that was handled by the
+    # except-blocks we are in
+    for i in countdown(howManyExcepts-1, 0):
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+
 proc genGotoState(p: BProc, n: PNode) =
   # we resist the temptation to translate it into duff's device as it later
   # will be translated into computed gotos anyway for GCC at least:
@@ -159,7 +200,11 @@ proc genGotoState(p: BProc, n: PNode) =
   initLocExpr(p, n.sons[0], a)
   lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
   p.beforeRetNeeded = true
-  lineF(p, cpsStmts, "case -1: goto BeforeRet_;$n", [])
+  lineF(p, cpsStmts, "case -1:$n", [])
+  blockLeaveActions(p,
+    howManyTrys    = p.nestedTryStmts.len,
+    howManyExcepts = p.inExceptBlockLen)
+  lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
   var statesCounter = lastOrd(n.sons[0].typ)
   if n.len >= 2 and n[1].kind == nkIntLit:
     statesCounter = n[1].intVal
@@ -169,23 +214,21 @@ proc genGotoState(p: BProc, n: PNode) =
     lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
   lineF(p, cpsStmts, "}$n", [])
 
-proc genBreakState(p: BProc, n: PNode) =
+proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
+  initLoc(d, locExpr, n, OnUnknown)
+
   if n.sons[0].kind == nkClosure:
-    # XXX this produces quite inefficient code!
     initLocExpr(p, n.sons[0].sons[1], a)
-    lineF(p, cpsStmts, "if (((NI*) $1)[1] < 0) break;$n", [rdLoc(a)])
+    d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
   else:
     initLocExpr(p, n.sons[0], a)
     # the environment is guaranteed to contain the 'state' field at offset 1:
-    lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[1]) < 0) break;$n", [rdLoc(a)])
-  #  lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
-
-proc genVarPrototypeAux(m: BModule, n: PNode)
+    d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
 
 proc genGotoVar(p: BProc; value: PNode) =
   if value.kind notin {nkCharLit..nkUInt64Lit}:
-    localError(value.info, "'goto' target must be a literal value")
+    localError(p.config, value.info, "'goto' target must be a literal value")
   else:
     lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
 
@@ -217,7 +260,7 @@ proc genSingleVar(p: BProc, a: PNode) =
     # Alternative construction using default constructor (which may zeromem):
     # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
     if sfExportc in v.flags and p.module.g.generatedHeader != nil:
-      genVarPrototypeAux(p.module.g.generatedHeader, vn)
+      genVarPrototype(p.module.g.generatedHeader, vn)
     registerGcRoot(p, v)
   else:
     let value = a.sons[2]
@@ -239,7 +282,10 @@ proc genSingleVar(p: BProc, a: PNode) =
           if params != nil: params.add(~", ")
           assert(sonsLen(typ) == sonsLen(typ.n))
           add(params, genOtherArg(p, value, i, typ))
-        lineF(p, cpsStmts, "$#($#);$n", [decl, params])
+        if params == nil:
+          lineF(p, cpsStmts, "$#;$n", [decl])
+        else:
+          lineF(p, cpsStmts, "$#($#);$n", [decl, params])
       else:
         initLocExprSingleUse(p, value, tmp)
         lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
@@ -260,28 +306,16 @@ proc genClosureVar(p: BProc, a: PNode) =
     loadInto(p, a.sons[0], a.sons[2], v)
 
 proc genVarStmt(p: BProc, n: PNode) =
-  for i in countup(0, sonsLen(n) - 1):
-    var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue
-    if a.kind == nkIdentDefs:
+  for it in n.sons:
+    if it.kind == nkCommentStmt: continue
+    if it.kind == nkIdentDefs:
       # can be a lifted var nowadays ...
-      if a.sons[0].kind == nkSym:
-        genSingleVar(p, a)
+      if it.sons[0].kind == nkSym:
+        genSingleVar(p, it)
       else:
-        genClosureVar(p, a)
+        genClosureVar(p, it)
     else:
-      genVarTuple(p, a)
-
-proc genConstStmt(p: BProc, t: PNode) =
-  for i in countup(0, sonsLen(t) - 1):
-    var it = t.sons[i]
-    if it.kind == nkCommentStmt: continue
-    if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
-    var c = it.sons[0].sym
-    if c.typ.containsCompileTimeOnly: continue
-    elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
-        c.ast.len != 0:
-      if not emitLazily(c): requestConstImpl(p, c)
+      genVarTuple(p, it)
 
 proc genIf(p: BProc, n: PNode, d: var TLoc) =
   #
@@ -302,10 +336,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
     getTemp(p, n.typ, d)
   genLineDir(p, n)
   let lend = getLabel(p)
-  for i in countup(0, sonsLen(n) - 1):
+  for it in n.sons:
     # bug #4230: avoid false sharing between branches:
     if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
-    let it = n.sons[i]
     if it.len == 2:
       when newScopeForIf: startBlock(p)
       initLocExprSingleUse(p, it.sons[0], a)
@@ -329,47 +362,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
       startBlock(p)
       expr(p, it.sons[0], d)
       endBlock(p)
-    else: internalError(n.info, "genIf()")
+    else: internalError(p.config, n.info, "genIf()")
   if sonsLen(n) > 1: fixLabel(p, lend)
 
-
-proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
-  # Called by return and break stmts.
-  # Deals with issues faced when jumping out of try/except/finally stmts,
-
-  var stack: seq[PNode]
-  newSeq(stack, 0)
-
-  var alreadyPoppedCnt = p.inExceptBlock
-  for i in countup(1, howManyTrys):
-    if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
-      # Pop safe points generated by try
-      if alreadyPoppedCnt > 0:
-        dec alreadyPoppedCnt
-      else:
-        linefmt(p, cpsStmts, "#popSafePoint();$n")
-
-    # Pop this try-stmt of the list of nested trys
-    # so we don't infinite recurse on it in the next step.
-    var tryStmt = p.nestedTryStmts.pop
-    stack.add(tryStmt)
-
-    # Find finally-stmt for this try-stmt
-    # and generate a copy of its sons
-    var finallyStmt = lastSon(tryStmt)
-    if finallyStmt.kind == nkFinally:
-      genStmts(p, finallyStmt.sons[0])
-
-  # push old elements again:
-  for i in countdown(howManyTrys-1, 0):
-    p.nestedTryStmts.add(stack[i])
-
-  if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
-    # Pop exceptions that was handled by the
-    # except-blocks we are in
-    for i in countdown(howManyExcepts-1, 0):
-      linefmt(p, cpsStmts, "#popCurrentException();$n")
-
 proc genReturnStmt(p: BProc, t: PNode) =
   if nfPreventCg in t.flags: return
   p.beforeRetNeeded = true
@@ -377,7 +372,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
   if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
   blockLeaveActions(p,
     howManyTrys    = p.nestedTryStmts.len,
-    howManyExcepts = p.inExceptBlock)
+    howManyExcepts = p.inExceptBlockLen)
   if (p.finallySafePoints.len > 0):
     # If we're in a finally block, and we came here by exception
     # consume it before we return.
@@ -391,7 +386,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
     let it = caseStmt.sons[i]
     for j in 0 .. it.len-2:
       if it.sons[j].kind == nkRange:
-        localError(it.info, "range notation not available for computed goto")
+        localError(p.config, it.info, "range notation not available for computed goto")
         return
       let val = getOrdValue(it.sons[j])
       lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
@@ -406,19 +401,19 @@ proc genComputedGoto(p: BProc; n: PNode) =
     let it = n.sons[i]
     if it.kind == nkCaseStmt:
       if lastSon(it).kind != nkOfBranch:
-        localError(it.info,
+        localError(p.config, it.info,
             "case statement must be exhaustive for computed goto"); return
       casePos = i
       let aSize = lengthOrd(it.sons[0].typ)
       if aSize > 10_000:
-        localError(it.info,
+        localError(p.config, it.info,
             "case statement has too many cases for computed goto"); return
       arraySize = aSize.int
       if firstOrd(it.sons[0].typ) != 0:
-        localError(it.info,
+        localError(p.config, it.info,
             "case statement has to start at 0 for computed goto"); return
   if casePos < 0:
-    localError(n.info, "no case statement found for computed goto"); return
+    localError(p.config, n.info, "no case statement found for computed goto"); return
   var id = p.labels+1
   inc p.labels, arraySize+1
   let tmp = "TMP$1_" % [id.rope]
@@ -452,7 +447,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
     let it = caseStmt.sons[i]
     for j in 0 .. it.len-2:
       if it.sons[j].kind == nkRange:
-        localError(it.info, "range notation not available for computed goto")
+        localError(p.config, it.info, "range notation not available for computed goto")
         return
       let val = getOrdValue(it.sons[j])
       lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
@@ -556,33 +551,38 @@ proc genBreakStmt(p: BProc, t: PNode) =
     # an unnamed 'break' can only break a loop after 'transf' pass:
     while idx >= 0 and not p.blocks[idx].isLoop: dec idx
     if idx < 0 or not p.blocks[idx].isLoop:
-      internalError(t.info, "no loop to break")
+      internalError(p.config, t.info, "no loop to break")
   let label = assignLabel(p.blocks[idx])
   blockLeaveActions(p,
     p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
-    p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
+    p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts)
   genLineDir(p, t)
   lineF(p, cpsStmts, "goto $1;$n", [label])
 
 proc genRaiseStmt(p: BProc, t: PNode) =
-  if p.inExceptBlock > 0:
+  if p.module.compileToCpp:
+    discard cgsym(p.module, "popCurrentExceptionEx")
+  if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
     # if the current try stmt have a finally block,
     # we must execute it before reraising
-    var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
+    var finallyBlock = p.nestedTryStmts[^1].n[^1]
     if finallyBlock.kind == nkFinally:
-      genSimpleBlock(p, finallyBlock.sons[0])
-  if t.sons[0].kind != nkEmpty:
+      genSimpleBlock(p, finallyBlock[0])
+  if t[0].kind != nkEmpty:
     var a: TLoc
-    initLocExpr(p, t.sons[0], a)
+    initLocExprSingleUse(p, t[0], a)
     var e = rdLoc(a)
-    var typ = skipTypes(t.sons[0].typ, abstractPtrs)
+    var typ = skipTypes(t[0].typ, abstractPtrs)
     genLineDir(p, t)
-    lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
-        [e, makeCString(typ.sym.name.s)])
+    if isImportedException(typ, p.config):
+      lineF(p, cpsStmts, "throw $1;$n", [e])
+    else:
+      lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
+          [e, makeCString(typ.sym.name.s)])
   else:
     genLineDir(p, t)
     # reraise the last exception:
-    if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
+    if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
       line(p, cpsStmts, ~"throw;$n")
     else:
       linefmt(p, cpsStmts, "#reraiseException();$n")
@@ -775,91 +775,75 @@ 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
+  #   } catch (NimExceptionType2&) {
+  #      finallyPart()
+  #      raise;
+  #   }
+  #   catch(...) {
+  #     general_handler_body
+  #   }
+  #   finallyPart();
+
+  template genExceptBranchBody(body: PNode) {.dirty.} =
+    if optStackTrace in p.options:
+      linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
+    expr(p, body, d)
+
   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")
-  add(p.nestedTryStmts, t)
+  discard cgsym(p.module, "popCurrentExceptionEx")
+  add(p.nestedTryStmts, (t, false))
   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)
+
   var catchAllPresent = false
-  while (i < length) and (t.sons[i].kind == nkExceptBranch):
+
+  p.nestedTryStmts[^1].inExcept = true
+  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")
+      startBlock(p, "catch (...) {$n")
+      genExceptBranchBody(t[i][0])
       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")
-      endBlock(p)
-    inc(i)
+      for j in 0..t[i].len-2:
+        if t[i][j].isInfixAs():
+          let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
+          fillLoc(exvar.sym.loc, locTemp, exvar, mangleLocalName(p, exvar.sym), OnUnknown)
+          startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc))
+        else:
+          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)
 
-  # 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])
+  discard pop(p.nestedTryStmts)
 
+  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
-
-  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:
@@ -895,23 +879,20 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   p.module.includeHeader("<setjmp.h>")
   genLineDir(p, t)
   var safePoint = getTempName(p.module)
-  if getCompilerProc("Exception") != nil:
-    discard cgsym(p.module, "Exception")
-  else:
-    discard cgsym(p.module, "E_Base")
+  discard cgsym(p.module, "Exception")
   linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
   linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
-  if isDefined("nimStdSetjmp"):
+  if isDefined(p.config, "nimStdSetjmp"):
     linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
-  elif isDefined("nimSigSetjmp"):
+  elif isDefined(p.config, "nimSigSetjmp"):
     linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
-  elif isDefined("nimRawSetjmp"):
+  elif isDefined(p.config, "nimRawSetjmp"):
     linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
   else:
     linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
   startBlock(p, "if ($1.status == 0) {$n", [safePoint])
   var length = sonsLen(t)
-  add(p.nestedTryStmts, t)
+  add(p.nestedTryStmts, (t, false))
   expr(p, t.sons[0], d)
   linefmt(p, cpsStmts, "#popSafePoint();$n")
   endBlock(p)
@@ -919,7 +900,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   linefmt(p, cpsStmts, "#popSafePoint();$n")
   if optStackTrace in p.options:
     linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
-  inc p.inExceptBlock
+  p.nestedTryStmts[^1].inExcept = true
   var i = 1
   while (i < length) and (t.sons[i].kind == nkExceptBranch):
     # bug #4230: avoid false sharing between branches:
@@ -950,7 +931,6 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
       linefmt(p, cpsStmts, "#popCurrentException();$n")
       endBlock(p)
     inc(i)
-  dec p.inExceptBlock
   discard pop(p.nestedTryStmts)
   endBlock(p) # end of else block
   if i < length and t.sons[i].kind == nkFinally:
@@ -961,19 +941,20 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
 
 proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
   var res = ""
-  for i in countup(0, sonsLen(t) - 1):
-    case t.sons[i].kind
+  for it in t.sons:
+    case it.kind
     of nkStrLit..nkTripleStrLit:
-      res.add(t.sons[i].strVal)
+      res.add(it.strVal)
     of nkSym:
-      var sym = t.sons[i].sym
+      var sym = it.sym
       if sym.kind in {skProc, skFunc, skIterator, skMethod}:
         var a: TLoc
-        initLocExpr(p, t.sons[i], a)
+        initLocExpr(p, it, a)
         res.add($rdLoc(a))
       elif sym.kind == skType:
         res.add($getTypeDesc(p.module, sym.typ))
       else:
+        discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs))
         var r = sym.loc.r
         if r == nil:
           # if no name has already been given,
@@ -982,12 +963,12 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
           sym.loc.r = r       # but be consequent!
         res.add($r)
     of nkTypeOfExpr:
-      res.add($getTypeDesc(p.module, t.sons[i].typ))
+      res.add($getTypeDesc(p.module, it.typ))
     else:
+      discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
       var a: TLoc
-      initLocExpr(p, t.sons[i], a)
+      initLocExpr(p, it, a)
       res.add($a.rdLoc)
-      #internalError(t.sons[i].info, "genAsmOrEmitStmt()")
 
   if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
     for x in splitLines(res):
@@ -1032,7 +1013,7 @@ proc genEmit(p: BProc, t: PNode) =
   if p.prc == nil:
     # top level emit pragma?
     let section = determineSection(t[1])
-    genCLineDir(p.module.s[section], t.info)
+    genCLineDir(p.module.s[section], t.info, p.config)
     add(p.module.s[section], s)
   else:
     genLineDir(p, t)
@@ -1063,8 +1044,7 @@ proc genWatchpoint(p: BProc, n: PNode) =
         genTypeInfo(p.module, typ, n.info)])
 
 proc genPragma(p: BProc, n: PNode) =
-  for i in countup(0, sonsLen(n) - 1):
-    var it = n.sons[i]
+  for it in n.sons:
     case whichPragma(it)
     of wEmit: genEmit(p, it)
     of wBreakpoint: genBreakPoint(p, it)
@@ -1159,4 +1139,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
 proc genStmts(p: BProc, t: PNode) =
   var a: TLoc
   expr(p, t, a)
-  internalAssert a.k in {locNone, locTemp, locLocalVar}
+  internalAssert p.config, a.k in {locNone, locTemp, locLocalVar}