diff options
author | Araq <rumpf_a@web.de> | 2017-12-27 10:34:31 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2017-12-27 10:34:31 +0100 |
commit | b3732e23716166dfa7c77e8dc1ee9b4571853aed (patch) | |
tree | 39ad24fd1b3a69ce74d4e4a68c242d6d18f04c64 /compiler | |
parent | 5c08092b88c0b6399c52804fd6f2c1fc92c58a86 (diff) | |
parent | 53cf0b2c24e5adc4fa99e49ddf1834991d663846 (diff) | |
download | Nim-b3732e23716166dfa7c77e8dc1ee9b4571853aed.tar.gz |
Merge branch 'devel' of github.com:nim-lang/Nim into devel
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/commands.nim | 2 | ||||
-rw-r--r-- | compiler/dfa.nim | 26 | ||||
-rw-r--r-- | compiler/main.nim | 7 | ||||
-rw-r--r-- | compiler/msgs.nim | 6 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/sem.nim | 13 | ||||
-rw-r--r-- | compiler/semstmts.nim | 24 |
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, |