summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ccgexprs.nim21
-rw-r--r--compiler/ccgstmts.nim4
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/destroyer.nim47
-rw-r--r--compiler/dfa.nim1
-rw-r--r--compiler/docgen.nim12
-rw-r--r--compiler/passes.nim25
-rw-r--r--compiler/pragmas.nim5
-rw-r--r--compiler/sem.nim12
-rw-r--r--compiler/semasgn.nim3
-rw-r--r--compiler/semfold.nim5
-rw-r--r--compiler/semgnrc.nim10
-rw-r--r--compiler/semstmts.nim6
-rw-r--r--compiler/suggest.nim31
-rw-r--r--compiler/transf.nim8
-rw-r--r--compiler/vmgen.nim6
17 files changed, 136 insertions, 63 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index fbedf6cc6..1789ce4f1 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1732,7 +1732,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
       initLocExpr(p, e.sons[1], a)
       initLocExpr(p, e.sons[2], b)
-      if d.k == locNone: getTemp(p, a.t, d)
+      if d.k == locNone: getTemp(p, setType, d)
       lineF(p, cpsStmts,
            "for ($1 = 0; $1 < $2; $1++) $n" &
            "  $3[$1] = $4[$1] $6 $5[$1];$n", [
@@ -1864,6 +1864,23 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   else:
     binaryArith(p, e, d, m)
 
+proc skipAddr(n: PNode): PNode =
+  result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n
+
+proc genWasMoved(p: BProc; n: PNode) =
+  var a: TLoc
+  initLocExpr(p, n[1].skipAddr, a)
+  resetLoc(p, a)
+  #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
+  #  addrLoc(p.config, a), getTypeDesc(p.module, a.t))
+
+proc genMove(p: BProc; n: PNode; d: var TLoc) =
+  if d.k == locNone: getTemp(p, n.typ, d)
+  var a: TLoc
+  initLocExpr(p, n[1].skipAddr, a)
+  genAssignment(p, d, a, {})
+  resetLoc(p, a)
+
 proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   case op
   of mOr, mAnd: genAndOr(p, e, d, op)
@@ -1991,6 +2008,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     initLocExpr(p, e.sons[2], b)
     genDeepCopy(p, a, b)
   of mDotDot, mEqCString: genCall(p, e, d)
+  of mWasMoved: genWasMoved(p, e)
+  of mMove: genMove(p, e, d)
   else:
     when defined(debugMagics):
       echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 69e6558bb..df8f95b75 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -277,7 +277,7 @@ proc genSingleVar(p: BProc, a: PNode) =
         not containsHiddenPointer(v.typ):
       # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
       # parameterless constructor followed by an assignment operator. So we
-      # generate better code here:
+      # generate better code here: 'Foo f = x;'
       genLineDir(p, a)
       let decl = localVarDecl(p, vn)
       var tmp: TLoc
@@ -1159,4 +1159,4 @@ proc genStmts(p: BProc, t: PNode) =
   if isPush: pushInfoContext(p.config, t.info)
   expr(p, t, a)
   if isPush: popInfoContext(p.config)
-  internalAssert p.config, a.k in {locNone, locTemp, locLocalVar}
+  internalAssert p.config, a.k in {locNone, locTemp, locLocalVar, locExpr}
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 52a4a72f2..3c7a0d26e 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -1206,7 +1206,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
       let x = fakeClosureType(m, t.owner)
       genTupleInfo(m, x, x, result, info)
   of tySequence:
-    if tfHasAsgn notin t.flags:
+    if m.config.selectedGC != gcDestructors:
       genTypeInfoAux(m, t, t, result, info)
       if m.config.selectedGC >= gcMarkAndSweep:
         let markerProc = genTraverseProc(m, origType, sig)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index a22b613f0..62c55de3d 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -81,6 +81,7 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimAshr")
   defineSymbol("nimNoNilSeqs")
   defineSymbol("nimNoNilSeqs2")
+  defineSymbol("nimHasUserErrors")
 
   defineSymbol("nimHasNilSeqs")
   for f in low(Feature)..high(Feature):
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index bd735560a..fc8e760bc 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -181,7 +181,7 @@ proc isHarmlessVar*(s: PSym; c: Con): bool =
       if c.g[i].sym == s:
         if defsite < 0: defsite = i
         else: return false
-    of use:
+    of use, useWithinCall:
       if c.g[i].sym == s:
         if defsite < 0: return false
         for j in defsite .. i:
@@ -190,10 +190,11 @@ proc isHarmlessVar*(s: PSym; c: Con): bool =
         # if we want to die after the first 'use':
         if usages > 1: return false
         inc usages
-    of useWithinCall:
-      if c.g[i].sym == s: return false
+    #of useWithinCall:
+    #  if c.g[i].sym == s: return false
     of goto, fork:
       discard "we do not perform an abstract interpretation yet"
+  result = usages <= 1
 
 template interestingSym(s: PSym): bool =
   s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
@@ -222,26 +223,35 @@ proc patchHead(s: PSym) =
   if sfFromGeneric in s.flags:
     patchHead(s.ast[bodyPos])
 
-template genOp(opr, opname) =
+proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
+  var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
+  if opname == "=" and ri != nil:
+    m.add "; requires a copy because it's not the last read of '"
+    m.add renderTree(ri)
+    m.add '\''
+  localError(c.graph.config, ri.info, errGenerated, m)
+
+template genOp(opr, opname, ri) =
   let op = opr
   if op == nil:
     globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
   elif op.ast[genericParamsPos].kind != nkEmpty:
     globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
   patchHead op
+  if sfError in op.flags: checkForErrorPragma(c, t, ri, opname)
   result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
 
-proc genSink(c: Con; t: PType; dest: PNode): PNode =
+proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  genOp(if t.sink != nil: t.sink else: t.assignment, "=sink")
+  genOp(if t.sink != nil: t.sink else: t.assignment, "=sink", ri)
 
-proc genCopy(c: Con; t: PType; dest: PNode): PNode =
+proc genCopy(c: Con; t: PType; dest, ri: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  genOp(t.assignment, "=")
+  genOp(t.assignment, "=", ri)
 
 proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  genOp(t.destructor, "=destroy")
+  genOp(t.destructor, "=destroy", nil)
 
 proc addTopVar(c: var Con; v: PNode) =
   c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
@@ -291,33 +301,33 @@ proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
 
 proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
   if ri.kind in constrExprs:
-    result = genSink(c, ri.typ, dest)
+    result = genSink(c, dest.typ, dest, ri)
     # watch out and no not transform 'ri' twice if it's a call:
     let ri2 = copyNode(ri)
     recurse(ri, ri2)
     result.add ri2
-  elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
+  elif ri.kind == nkSym and ri.sym.kind != skParam and isHarmlessVar(ri.sym, c):
     # Rule 3: `=sink`(x, z); wasMoved(z)
-    var snk = genSink(c, ri.typ, dest)
+    var snk = genSink(c, dest.typ, dest, ri)
     snk.add p(ri, c)
     result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
   elif ri.kind == nkSym and isSinkParam(ri.sym):
-    result = genSink(c, ri.typ, dest)
+    result = genSink(c, dest.typ, dest, ri)
     result.add destructiveMoveSink(ri, c)
   else:
-    result = genCopy(c, ri.typ, dest)
+    result = genCopy(c, dest.typ, dest, ri)
     result.add p(ri, c)
 
 proc passCopyToSink(n: PNode; c: var Con): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let tmp = getTemp(c, n.typ, n.info)
   if hasDestructor(n.typ):
-    var m = genCopy(c, n.typ, tmp)
+    var m = genCopy(c, n.typ, tmp, n)
     m.add p(n, c)
     result.add m
     message(c.graph.config, n.info, hintPerformance,
-      "passing '$1' to a sink parameter introduces an implicit copy; " &
-      "use 'move($1)' to prevent it" % $n)
+      ("passing '$1' to a sink parameter introduces an implicit copy; " &
+      "use 'move($1)' to prevent it") % $n)
   else:
     result.add newTree(nkAsgn, tmp, p(n, c))
   result.add tmp
@@ -331,6 +341,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
 
   var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.owner, n.info)
+  temp.typ = n.typ
   var v = newNodeI(nkLetSection, n.info)
   let tempAsNode = newSymNode(temp)
 
@@ -410,7 +421,7 @@ proc p(n: PNode; c: var Con): PNode =
       discard "produce temp creation"
       result = newNodeIT(nkStmtListExpr, n.info, n.typ)
       let tmp = getTemp(c, n.typ, n.info)
-      var sinkExpr = genSink(c, n.typ, tmp)
+      var sinkExpr = genSink(c, n.typ, tmp, n)
       sinkExpr.add n
       result.add sinkExpr
       result.add tmp
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 013242f62..44c89b881 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -442,4 +442,5 @@ proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
 proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
   ## constructs a control flow graph for ``body``.
   var c = Con(code: @[], blocks: @[])
+  gen(c, body)
   shallowCopy(result, c.code)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 83dd5de2a..e815bf7a1 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -112,7 +112,7 @@ proc getOutFile2(conf: ConfigRef; filename: RelativeFile,
   else:
     result = getOutFile(conf, filename, ext)
 
-proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef): PDoc =
+proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, outExt: string = HtmlExt): PDoc =
   declareClosures()
   new(result)
   result.conf = conf
@@ -146,7 +146,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef):
                warnUser, "only 'rst2html' supports the ':test:' attribute")
   result.emitted = initIntSet()
   result.destFile = getOutFile2(conf, relativeTo(filename, conf.projectPath),
-                                HtmlExt, RelativeDir"htmldocs", false)
+                                outExt, RelativeDir"htmldocs", false)
   result.thisDir = result.destFile.splitFile.dir
 
 proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
@@ -304,7 +304,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
           d.target == outHtml:
         let external = externalDep(d, s.owner)
         result.addf "<a href=\"$1#$2\"><span class=\"Identifier\">$3</span></a>",
-          [rope changeFileExt(external, "html").string, rope literal,
+          [rope changeFileExt(external, "html"), rope literal,
            rope(esc(d.target, literal))]
       else:
         dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
@@ -610,7 +610,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
   var seeSrcRope: Rope = nil
   let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
   if docItemSeeSrc.len > 0:
-    let path = relativeTo(AbsoluteFile toFullPath(d.conf, n.info), d.conf.projectPath, '/')
+    let path = relativeTo(AbsoluteFile toFullPath(d.conf, n.info), AbsoluteDir getCurrentDir(), '/')
     when false:
       let cwd = canonicalizePath(d.conf, getCurrentDir())
       var path = toFullPath(d.conf, n.info)
@@ -711,7 +711,7 @@ proc exportSym(d: PDoc; s: PSym) =
           "<a class=\"reference external\" href=\"$2\">$1</a>",
           "$1", [rope esc(d.target, changeFileExt(external, "")),
           rope changeFileExt(external, "html")])
-  elif s.owner != nil:
+  elif s.kind != skModule and s.owner != nil:
     let module = originatingModule(s)
     if belongsToPackage(d.conf, module):
       let external = externalDep(d, module)
@@ -960,7 +960,7 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) =
 proc commandRstAux(cache: IdentCache, conf: ConfigRef;
                    filename: AbsoluteFile, outExt: string) =
   var filen = addFileExt(filename, "txt")
-  var d = newDocumentor(filen, cache, conf)
+  var d = newDocumentor(filen, cache, conf, outExt)
   d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string;
                           status: int; content: string) =
     var outp: AbsoluteFile
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 365731669..718b42c2a 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -125,6 +125,11 @@ proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKi
       importStmt.addSon str
       if not processTopLevelStmt(importStmt, a): break
 
+const
+  imperativeCode = {low(TNodeKind)..high(TNodeKind)} - {nkTemplateDef, nkProcDef, nkMethodDef,
+    nkMacroDef, nkConverterDef, nkIteratorDef, nkFuncDef, nkPragma,
+    nkExportStmt, nkExportExceptStmt, nkFromStmt, nkImportStmt, nkImportExceptStmt}
+
 proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} =
   if graph.stopCompile(): return true
   var
@@ -191,7 +196,25 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
             sl = reorder(graph, sl, module)
           discard processTopLevelStmt(sl, a)
           break
-        elif not processTopLevelStmt(n, a): break
+        elif n.kind in imperativeCode:
+          # read everything until the next proc declaration etc.
+          var sl = newNodeI(nkStmtList, n.info)
+          sl.add n
+          var rest: PNode = nil
+          while true:
+            var n = parseTopLevelStmt(p)
+            if n.kind == nkEmpty or n.kind notin imperativeCode:
+              rest = n
+              break
+            sl.add n
+          #echo "-----\n", sl
+          if not processTopLevelStmt(sl, a): break
+          if rest != nil:
+            #echo "-----\n", rest
+            if not processTopLevelStmt(rest, a): break
+        else:
+          #echo "----- single\n", n
+          if not processTopLevelStmt(n, a): break
       closeParsers(p)
       if s.kind != llsStdIn: break
     closePasses(graph, a)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 36c79bc9e..94790440f 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -954,13 +954,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         recordPragma(c, it, "warning", s)
         message(c.config, it.info, warnUser, s)
       of wError:
-        if sym != nil and sym.isRoutine:
+        if sym != nil and (sym.isRoutine or sym.kind == skType):
           # This is subtle but correct: the error *statement* is only
           # allowed for top level statements. Seems to be easier than
           # distinguishing properly between
           # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
-          noVal(c, it)
+          if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
           incl(sym.flags, sfError)
+          excl(sym.flags, sfForward)
         else:
           let s = expectStrLit(c, it)
           recordPragma(c, it, "error", s)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 5e5205c20..dbc174d50 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -542,12 +542,20 @@ proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
         return true
   else: discard
 
+proc isEmptyTree(n: PNode): bool =
+  case n.kind
+  of nkStmtList:
+    for it in n:
+      if not isEmptyTree(it): return false
+    result = true
+  of nkEmpty, nkCommentStmt: result = true
+  else: result = false
+
 proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
   if n.kind == nkDefer:
     localError(c.config, n.info, "defer statement not supported at top level")
   if c.topStmts == 0 and not isImportSystemStmt(c.graph, n):
-    if sfSystemModule notin c.module.flags and
-        n.kind notin {nkEmpty, nkCommentStmt}:
+    if sfSystemModule notin c.module.flags and not isEmptyTree(n):
       c.importTable.addSym c.graph.systemModule # import the "System" identifier
       importAllSymbols(c, c.graph.systemModule)
       inc c.topStmts
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 8b2e20efc..f781972a5 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -216,7 +216,8 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
     if c.c.config.selectedGC == gcDestructors:
       discard considerOverloadedOp(c, t, body, x, y)
     elif tfHasAsgn in t.flags:
-      body.add newSeqCall(c.c, x, y)
+      if c.kind != attachedDestructor:
+        body.add newSeqCall(c.c, x, y)
       let i = declareCounter(c, body, firstOrd(c.c.config, t))
       let whileLoop = genWhileLoop(c, i, x)
       let elemType = t.lastSon
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 0018f0755..627877cbe 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -37,10 +37,7 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
 
 proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
   result = newFloatNode(nkFloatLit, floatVal)
-  if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
-    result.typ = getFloatLitType(g, result)
-  else:
-    result.typ = n.typ
+  result.typ = n.typ
   result.info = n.info
 
 proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 7be0610a2..e1a8390e1 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -225,7 +225,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     var mixinContext = false
     if s != nil:
       incl(s.flags, sfUsed)
-      mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mRunnableExamples}
+      mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
       let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
       case s.kind
       of skMacro:
@@ -255,11 +255,11 @@ proc semGenericStmt(c: PContext, n: PNode,
         discard
       of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
         result.sons[0] = sc
-        # do not check of 's.magic==mRoof' here because it might be some
-        # other '^' but after overload resolution the proper one:
-        if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
-          result.add ctx.bracketExpr
         first = 1
+        # We're not interested in the example code during this pass so let's
+        # skip it
+        if s.magic == mRunnableExamples:
+          inc first
       of skGenericParam:
         result.sons[0] = newSymNodeTypeDesc(s, fn.info)
         styleCheckUse(fn.info, s)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 75a4198a5..f2cb2dcb3 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -114,7 +114,7 @@ const
   skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
     nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
     nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr,
-    nkHiddenStdConv}
+    nkHiddenStdConv, nkHiddenDeref}
 
 proc implicitlyDiscardable(n: PNode): bool =
   var n = n
@@ -601,6 +601,8 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
   inc(c.p.nestedLoopCounter)
   openScope(c)
   n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
+  if efInTypeof notin flags:
+    discardCheck(c, n.sons[length-1], flags)
   closeScope(c)
   dec(c.p.nestedLoopCounter)
 
@@ -1675,7 +1677,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   else:
     if s.kind == skMethod: semMethodPrototype(c, s, n)
     if proto != nil: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
-    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
+    if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone:
       incl(s.flags, sfForward)
     elif sfBorrow in s.flags: semBorrow(c, n, s)
   sideEffectsCheck(c, s)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index b6b8d713c..b264415d8 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -33,7 +33,7 @@
 # included from sigmatch.nim
 
 import algorithm, prefixmatches, lineinfos, pathutils
-from wordrecg import wDeprecated
+from wordrecg import wDeprecated, wError
 
 when defined(nimsuggest):
   import passes, tables # importer
@@ -453,33 +453,42 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym;
         isDecl:
       suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
 
-proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
-  var pragmaNode: PNode
-
+proc extractPragma(s: PSym): PNode =
   if s.kind in routineKinds:
-    pragmaNode = s.ast[pragmasPos]
+    result = s.ast[pragmasPos]
   elif s.kind in {skType}:
     # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
-    pragmaNode = s.ast[0][1]
-
-  doAssert pragmaNode == nil or pragmaNode.kind == nkPragma
+    result = s.ast[0][1]
+  doAssert result == nil or result.kind == nkPragma
 
+proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
+  let pragmaNode = extractPragma(s)
   if pragmaNode != nil:
     for it in pragmaNode:
       if whichPragma(it) == wDeprecated and it.safeLen == 2 and
-        it[1].kind in {nkStrLit..nkTripleStrLit}:
+          it[1].kind in {nkStrLit..nkTripleStrLit}:
         message(conf, info, warnDeprecated, it[1].strVal & "; " & s.name.s)
         return
-
   message(conf, info, warnDeprecated, s.name.s)
 
+proc userError(conf: ConfigRef; info: TLineInfo; s: PSym) =
+  let pragmaNode = extractPragma(s)
+
+  if pragmaNode != nil:
+    for it in pragmaNode:
+      if whichPragma(it) == wError and it.safeLen == 2 and
+          it[1].kind in {nkStrLit..nkTripleStrLit}:
+        localError(conf, info, it[1].strVal & "; usage of '$1' is a user-defined error" % s.name.s)
+        return
+  localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s)
+
 proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
   incl(s.flags, sfUsed)
   if s.kind == skEnumField and s.owner != nil:
     incl(s.owner.flags, sfUsed)
   if {sfDeprecated, sfError} * s.flags != {}:
     if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s)
-    if sfError in s.flags: localError(conf, info,  "usage of '$1' is a user-defined error" % s.name.s)
+    if sfError in s.flags: userError(conf, info, s)
   when defined(nimsuggest):
     suggestSym(conf, info, s, usageSym, false)
 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index b31be71a3..83e66a069 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -1054,8 +1054,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     when useEffectSystem: trackTopLevelStmt(g, module, result)
     #if n.info ?? "temp.nim":
     #  echo renderTree(result, {renderIds})
-    #if c.needsDestroyPass:
-    #  result = injectDestructorCalls(g, module, result)
+    if c.needsDestroyPass:
+      result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
 
 proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
@@ -1067,6 +1067,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     liftDefer(c, result)
     # expressions are not to be injected with destructor calls as that
     # the list of top level statements needs to be collected before.
-    #if c.needsDestroyPass:
-    #  result = injectDestructorCalls(g, module, result)
+    if c.needsDestroyPass:
+      result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index b6b5bf4f2..e612d7a2a 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1529,7 +1529,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
 
 template needsRegLoad(): untyped =
   {gfNode, gfNodeAddr} * flags == {} and
-    fitsRegister(n.typ.skipTypes({tyVar, tyLent}))
+    fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic}))
 
 proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
                    flags: TGenFlags) =
@@ -1590,7 +1590,7 @@ proc getNullValueAux(obj: PNode, result: PNode; conf: ConfigRef) =
   else: globalError(conf, result.info, "cannot create null element for: " & $obj)
 
 proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
-  var t = skipTypes(typ, abstractRange-{tyTypeDesc})
+  var t = skipTypes(typ, abstractRange+{tyStatic}-{tyTypeDesc})
   case t.kind
   of tyBool, tyEnum, tyChar, tyInt..tyInt64:
     result = newNodeIT(nkIntLit, info, t)
@@ -1602,7 +1602,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
     result = newNodeIT(nkStrLit, info, t)
     result.strVal = ""
   of tyVar, tyLent, tyPointer, tyPtr, tyExpr,
-     tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
+     tyStmt, tyTypeDesc, tyRef, tyNil:
     result = newNodeIT(nkNilLit, info, t)
   of tyProc:
     if t.callConv != ccClosure: