summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2017-12-27 10:34:31 +0100
committerAraq <rumpf_a@web.de>2017-12-27 10:34:31 +0100
commitb3732e23716166dfa7c77e8dc1ee9b4571853aed (patch)
tree39ad24fd1b3a69ce74d4e4a68c242d6d18f04c64 /compiler
parent5c08092b88c0b6399c52804fd6f2c1fc92c58a86 (diff)
parent53cf0b2c24e5adc4fa99e49ddf1834991d663846 (diff)
downloadNim-b3732e23716166dfa7c77e8dc1ee9b4571853aed.tar.gz
Merge branch 'devel' of github.com:nim-lang/Nim into devel
Diffstat (limited to 'compiler')
-rw-r--r--compiler/commands.nim2
-rw-r--r--compiler/dfa.nim26
-rw-r--r--compiler/main.nim7
-rw-r--r--compiler/msgs.nim6
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/sem.nim13
-rw-r--r--compiler/semstmts.nim24
7 files changed, 56 insertions, 24 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim
index de474c6e6..386d7bda8 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -611,7 +611,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
   of "skipparentcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipParentConfigFiles)
-  of "genscript":
+  of "genscript", "gendeps":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optGenScript)
   of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info)
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 66a71e839..6bb7a03a9 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -344,20 +344,20 @@ proc dfa(code: seq[Instr]) =
     case code[i].kind
     of use, useWithinCall: u[i].incl(code[i].sym.id)
     of def: d[i].incl(code[i].sym.id)
-    of fork:
+    of fork, goto:
       let d = i+code[i].dest
       backrefs.add(d, i)
-    of goto: discard
 
   var w = @[0]
   var maxIters = 50
   var someChange = true
-  while w.len > 0 and maxIters > 0 and someChange:
+  var takenGotos = initIntSet()
+  while w.len > 0 and maxIters > 0: # and someChange:
     dec maxIters
     var pc = w.pop() # w[^1]
     var prevPc = -1
     # this simulates a single linear control flow execution:
-    while pc < code.len and someChange:
+    while pc < code.len:
       # according to the paper, it is better to shrink the working set here
       # in this inner loop:
       #let widx = w.find(pc)
@@ -386,17 +386,21 @@ proc dfa(code: seq[Instr]) =
               if def notin d[prevPc]:
                 excl(intersect, def)
                 someChange = true
+                when defined(debugDfa):
+                  echo "Excluding ", pc, " prev ", prevPc
           assign d[pc], intersect
 
       # our interpretation ![I!]:
       prevPc = pc
+      when defined(debugDfa):
+        echo "looking at ", pc
       case code[pc].kind
       of goto:
         # we must leave endless loops eventually:
-        #if someChange:
-        pc = pc + code[pc].dest
-        #else:
-        #  inc pc
+        if not takenGotos.containsOrIncl(pc) or someChange:
+          pc = pc + code[pc].dest
+        else:
+          inc pc
       of fork:
         # we follow the next instruction but push the dest onto our "work" stack:
         #if someChange:
@@ -405,6 +409,10 @@ proc dfa(code: seq[Instr]) =
       of use, useWithinCall, def:
         inc pc
 
+  when defined(useDfa) and defined(debugDfa):
+    for i in 0..<code.len:
+      echo "PC ", i, ": defs: ", d[i], "; uses ", u[i]
+
   # now check the condition we're interested in:
   for i in 0..<code.len:
     case code[i].kind
@@ -508,7 +516,7 @@ proc dfaUnused(code: seq[Instr]) =
 proc dataflowAnalysis*(s: PSym; body: PNode) =
   var c = Con(code: @[], blocks: @[])
   gen(c, body)
-  #echoCfg(c.code)
+  when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
   dfa(c.code)
 
 proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
diff --git a/compiler/main.nim b/compiler/main.nim
index 1e94a6ca0..08fc4b138 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -16,7 +16,7 @@ import
   cgen, jsgen, json, nversion,
   platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
   docgen2, service, parser, modules, ccgutils, sigmatch, ropes,
-  modulegraphs
+  modulegraphs, tables
 
 from magicsys import systemModule, resetSysTypes
 
@@ -36,6 +36,9 @@ proc writeDepsFile(g: ModuleGraph; project: string) =
   for m in g.modules:
     if m != nil:
       f.writeLine(toFullPath(m.position.int32))
+  for k in g.inclToMod.keys:
+    if g.getModule(k).isNil:  # don't repeat includes which are also modules
+      f.writeLine(k.toFullPath)
   f.close()
 
 proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
@@ -77,6 +80,8 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
     let proj = changeFileExt(gProjectFull, "")
     extccomp.callCCompiler(proj)
     extccomp.writeJsonBuildInstructions(proj)
+    if optGenScript in gGlobalOptions:
+      writeDepsFile(graph, toGeneratedFile(proj, ""))
 
 proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) =
   let proj = changeFileExt(gProjectFull, "")
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 2668c72ae..4e6226122 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -26,7 +26,8 @@ type
     errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
     errExceptionExpected, errExceptionAlreadyHandled,
     errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
-    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
+    errInvalidNumberOfYieldExpr, errCannotReturnExpr, 
+    errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
     errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
     errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
     errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
@@ -179,8 +180,9 @@ const
     errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
     errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
     errCannotReturnExpr: "current routine cannot return an expression",
+    errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
     errAttemptToRedefine: "redefinition of \'$1\'",
-    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
+    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\', \'continue\' or proc call with noreturn pragma",
     errStmtExpected: "statement expected",
     errInvalidLabel: "\'$1\' is no label",
     errInvalidCmdLineOption: "invalid command line option: \'$1\'",
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index b598cadb2..02b57d5a3 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -771,6 +771,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
       of wNoreturn:
         noVal(it)
         incl(sym.flags, sfNoReturn)
+        if sym.typ[0] != nil:
+          localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed)
       of wDynlib:
         processDynLib(c, it, sym)
       of wCompilerproc:
diff --git a/compiler/sem.nim b/compiler/sem.nim
index bc994201d..ababbd303 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -165,6 +165,19 @@ proc commonType*(x, y: PType): PType =
         result = newType(k, r.owner)
         result.addSonSkipIntLit(r)
 
+proc endsInNoReturn(n: PNode): bool =
+  # check if expr ends in raise exception or call of noreturn proc
+  var it = n
+  while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: 
+    it = it.lastSon
+  result = it.kind == nkRaiseStmt or 
+    it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
+
+proc commonType*(x: PType, y: PNode): PType =
+  # ignore exception raising branches in case/if expressions
+  if endsInNoReturn(y): return x
+  commonType(x, y.typ)
+
 proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
   result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
   when defined(nimsuggest):
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 8ed120c98..b1fa8c19b 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -165,14 +165,14 @@ proc semIf(c: PContext, n: PNode): PNode =
       it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
       when not newScopeForIf: openScope(c)
       it.sons[1] = semExprBranch(c, it.sons[1])
-      typ = commonType(typ, it.sons[1].typ)
+      typ = commonType(typ, it.sons[1])
       closeScope(c)
     elif it.len == 1:
       hasElse = true
       it.sons[0] = semExprBranchScope(c, it.sons[0])
-      typ = commonType(typ, it.sons[0].typ)
+      typ = commonType(typ, it.sons[0])
     else: illFormedAst(it)
-  if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
+  if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
     for it in n: discardCheck(c, it.lastSon)
     result.kind = nkIfStmt
     # propagate any enforced VoidContext:
@@ -180,7 +180,8 @@ proc semIf(c: PContext, n: PNode): PNode =
   else:
     for it in n:
       let j = it.len-1
-      it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
+      if not endsInNoReturn(it.sons[j]):
+        it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
     result.kind = nkIfExpr
     result.typ = typ
 
@@ -213,7 +214,7 @@ proc semCase(c: PContext, n: PNode): PNode =
       semCaseBranch(c, n, x, i, covered)
       var last = sonsLen(x)-1
       x.sons[last] = semExprBranchScope(c, x.sons[last])
-      typ = commonType(typ, x.sons[last].typ)
+      typ = commonType(typ, x.sons[last])
     of nkElifBranch:
       chckCovered = false
       checkSonsLen(x, 2)
@@ -221,13 +222,13 @@ proc semCase(c: PContext, n: PNode): PNode =
       x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
       when not newScopeForIf: openScope(c)
       x.sons[1] = semExprBranch(c, x.sons[1])
-      typ = commonType(typ, x.sons[1].typ)
+      typ = commonType(typ, x.sons[1])
       closeScope(c)
     of nkElse:
       chckCovered = false
       checkSonsLen(x, 1)
       x.sons[0] = semExprBranchScope(c, x.sons[0])
-      typ = commonType(typ, x.sons[0].typ)
+      typ = commonType(typ, x.sons[0])
       hasElse = true
     else:
       illFormedAst(x)
@@ -237,7 +238,7 @@ proc semCase(c: PContext, n: PNode): PNode =
     else:
       localError(n.info, errNotAllCasesCovered)
   closeScope(c)
-  if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
+  if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
     for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
     # propagate any enforced VoidContext:
     if typ == enforceVoidContext:
@@ -246,7 +247,8 @@ proc semCase(c: PContext, n: PNode): PNode =
     for i in 1..n.len-1:
       var it = n.sons[i]
       let j = it.len-1
-      it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
+      if not endsInNoReturn(it.sons[j]):
+        it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
     result.typ = typ
 
 proc semTry(c: PContext, n: PNode): PNode =
@@ -1851,8 +1853,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
       else:
         n.typ = n.sons[i].typ
         if not isEmptyType(n.typ): n.kind = nkStmtListExpr
-      case n.sons[i].kind
-      of LastBlockStmts:
+      if n.sons[i].kind in LastBlockStmts or
+         n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags:
         for j in countup(i + 1, length - 1):
           case n.sons[j].kind
           of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,
5' href='#n725'>725 726