further steps in implementing sink parameters; refs #7041
This commit is contained in:
parent
1d9343080d
commit
9de05ec3e0
10 changed files with 177 additions and 20 deletions
|
|
@ -453,6 +453,8 @@ type
|
||||||
nfPreventCg # this node should be ignored by the codegen
|
nfPreventCg # this node should be ignored by the codegen
|
||||||
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
nfFromTemplate # a top-level node returned from a template
|
nfFromTemplate # a top-level node returned from a template
|
||||||
|
nfPreventDestructor # prevent destructor injectsion for the node
|
||||||
|
# (but not necessarily its children)
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||||
of "rangechecks": result = contains(gOptions, optRangeCheck)
|
of "rangechecks": result = contains(gOptions, optRangeCheck)
|
||||||
of "boundchecks": result = contains(gOptions, optBoundsCheck)
|
of "boundchecks": result = contains(gOptions, optBoundsCheck)
|
||||||
of "overflowchecks": result = contains(gOptions, optOverflowCheck)
|
of "overflowchecks": result = contains(gOptions, optOverflowCheck)
|
||||||
|
of "movechecks": result = contains(gOptions, optMoveCheck)
|
||||||
of "linedir": result = contains(gOptions, optLineDir)
|
of "linedir": result = contains(gOptions, optLineDir)
|
||||||
of "assertions", "a": result = contains(gOptions, optAssert)
|
of "assertions", "a": result = contains(gOptions, optAssert)
|
||||||
of "deadcodeelim": result = contains(gGlobalOptions, optDeadCodeElim)
|
of "deadcodeelim": result = contains(gGlobalOptions, optDeadCodeElim)
|
||||||
|
|
@ -493,6 +494,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
|
of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
|
||||||
of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
|
of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
|
||||||
of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
|
of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
|
||||||
|
of "movechecks": processOnOffSwitch({optMoveCheck}, arg, pass, info)
|
||||||
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
|
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
|
||||||
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
|
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
|
||||||
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,36 @@
|
||||||
## tmp.bar))
|
## tmp.bar))
|
||||||
## destroy(tmp.bar)
|
## destroy(tmp.bar)
|
||||||
## destroy(tmp.x); destroy(tmp.y)
|
## destroy(tmp.x); destroy(tmp.y)
|
||||||
|
##
|
||||||
|
|
||||||
|
##[
|
||||||
|
From https://github.com/nim-lang/Nim/wiki/Destructors
|
||||||
|
|
||||||
|
Rule Pattern Transformed into
|
||||||
|
---- ------- ----------------
|
||||||
|
1.1 var x: T; stmts var x: T; try stmts
|
||||||
|
finally: `=destroy`(x)
|
||||||
|
1.2 var x: sink T; stmts var x: sink T; stmts; ensureEmpty(x)
|
||||||
|
2 x = f() `=sink`(x, f())
|
||||||
|
3 x = lastReadOf z `=sink`(x, z)
|
||||||
|
4.1 y = sinkParam `=sink`(y, sinkParam)
|
||||||
|
4.2 x = y `=`(x, y) # a copy
|
||||||
|
5.1 f_sink(g()) f_sink(g())
|
||||||
|
5.2 f_sink(y) f_sink(copy y); # copy unless we can see it's the last read
|
||||||
|
5.3 f_sink(move y) f_sink(y); reset(y) # explicit moves empties 'y'
|
||||||
|
5.4 f_noSink(g()) var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp)
|
||||||
|
|
||||||
|
Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
|
||||||
|
not allowed as a local variable.
|
||||||
|
|
||||||
|
``move`` builtin needs to be implemented.
|
||||||
|
|
||||||
|
XXX Think about nfPreventDestructor logic.
|
||||||
|
]##
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||||
strutils, options, dfa, lowerings, rodread
|
strutils, options, dfa, lowerings, rodread, tables
|
||||||
|
|
||||||
const
|
const
|
||||||
InterestingSyms = {skVar, skResult, skLet}
|
InterestingSyms = {skVar, skResult, skLet}
|
||||||
|
|
@ -106,6 +131,14 @@ type
|
||||||
tmpObj: PType
|
tmpObj: PType
|
||||||
tmp: PSym
|
tmp: PSym
|
||||||
destroys, topLevelVars: PNode
|
destroys, topLevelVars: PNode
|
||||||
|
toDropBit: Table[int, PSym]
|
||||||
|
|
||||||
|
proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
|
||||||
|
# XXX why are temps fields in an object here?
|
||||||
|
let f = newSym(skField, getIdent(":d" & $c.tmpObj.n.len), c.owner, info)
|
||||||
|
f.typ = typ
|
||||||
|
rawAddField c.tmpObj, f
|
||||||
|
result = rawDirectAccess(c.tmp, f)
|
||||||
|
|
||||||
proc isHarmlessVar*(s: PSym; c: Con): bool =
|
proc isHarmlessVar*(s: PSym; c: Con): bool =
|
||||||
# 's' is harmless if it used only once and its
|
# 's' is harmless if it used only once and its
|
||||||
|
|
@ -212,14 +245,44 @@ proc genDestroy(t: PType; dest: PNode): PNode =
|
||||||
proc addTopVar(c: var Con; v: PNode) =
|
proc addTopVar(c: var Con; v: PNode) =
|
||||||
c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode, emptyNode)
|
c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode, emptyNode)
|
||||||
|
|
||||||
|
proc dropBit(c: var Con; s: PSym): PSym =
|
||||||
|
result = c.toDropBit.getOrDefault(s.id)
|
||||||
|
assert result != nil
|
||||||
|
|
||||||
|
proc registerDropBit(c: var Con; s: PSym) =
|
||||||
|
let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info)
|
||||||
|
result.typ = getSysType(tyBool)
|
||||||
|
let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
|
||||||
|
c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal)
|
||||||
|
c.toDropBit[s.id] = result
|
||||||
|
# generate:
|
||||||
|
# if not sinkParam_AliveBit: `=destroy`(sinkParam)
|
||||||
|
c.destroys.add newTree(nkIfStmt,
|
||||||
|
newTree(nkElifBranch, newSymNode result, genDestroy(s.typ, newSymNode s)))
|
||||||
|
|
||||||
proc p(n: PNode; c: var Con): PNode
|
proc p(n: PNode; c: var Con): PNode
|
||||||
|
|
||||||
template recurse(n, dest) =
|
template recurse(n, dest) =
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
dest.add p(n[i], c)
|
dest.add p(n[i], c)
|
||||||
|
|
||||||
|
proc isSinkParam(s: PSym): bool {.inline.} =
|
||||||
|
result = s.kind == skParam and s.typ.kind == tySink
|
||||||
|
|
||||||
|
const constrExprs = nkCallKinds+{nkObjConstr}
|
||||||
|
|
||||||
|
proc destructiveMoveSink(n: PNode; c: var Con): PNode =
|
||||||
|
# generate: (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam)
|
||||||
|
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||||
|
let bit = newSymNode dropBit(c, n.sym)
|
||||||
|
if optMoveCheck in c.owner.options:
|
||||||
|
result.add callCodegenProc("chckMove", bit)
|
||||||
|
result.add newTree(nkAsgn, bit,
|
||||||
|
newIntTypeNode(nkIntLit, 0, getSysType(tyBool)))
|
||||||
|
result.add n
|
||||||
|
|
||||||
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
if ri.kind in nkCallKinds+{nkObjConstr}:
|
if ri.kind in constrExprs:
|
||||||
result = genSink(ri.typ, dest)
|
result = genSink(ri.typ, dest)
|
||||||
# watch out and no not transform 'ri' twice if it's a call:
|
# watch out and no not transform 'ri' twice if it's a call:
|
||||||
let ri2 = copyNode(ri)
|
let ri2 = copyNode(ri)
|
||||||
|
|
@ -228,10 +291,82 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
|
elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
|
||||||
result = genSink(ri.typ, dest)
|
result = genSink(ri.typ, dest)
|
||||||
result.add p(ri, c)
|
result.add p(ri, c)
|
||||||
|
elif ri.kind == nkSym and isSinkParam(ri.sym):
|
||||||
|
result = genSink(ri.typ, dest)
|
||||||
|
result.add destructiveMoveSink(ri, c)
|
||||||
else:
|
else:
|
||||||
result = genCopy(ri.typ, dest)
|
result = genCopy(ri.typ, dest)
|
||||||
result.add p(ri, c)
|
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)
|
||||||
|
var m = genCopy(n.typ, tmp)
|
||||||
|
m.add n
|
||||||
|
result.add m
|
||||||
|
result.add tmp
|
||||||
|
incl result.flags, nfPreventDestructor
|
||||||
|
message(n.info, hintPerformance,
|
||||||
|
"passing '$1' to a sink parameter introduces an implicit copy; " &
|
||||||
|
"use 'move($1)' to prevent it" % $n)
|
||||||
|
|
||||||
|
proc genReset(n: PNode; c: var Con): PNode =
|
||||||
|
result = newNodeI(nkCall, n.info)
|
||||||
|
result.add(newSymNode(createMagic("reset", mReset)))
|
||||||
|
# The mReset builtin does not take the address:
|
||||||
|
result.add n
|
||||||
|
|
||||||
|
proc destructiveMoveVar(n: PNode; c: var Con): PNode =
|
||||||
|
# generate: (let tmp = v; reset(v); tmp)
|
||||||
|
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||||
|
|
||||||
|
var temp = newSym(skLet, getIdent("blitTmp"), c.owner, n.info)
|
||||||
|
var v = newNodeI(nkLetSection, n.info)
|
||||||
|
let tempAsNode = newSymNode(temp)
|
||||||
|
|
||||||
|
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||||
|
vpart.sons[0] = tempAsNode
|
||||||
|
vpart.sons[1] = ast.emptyNode
|
||||||
|
vpart.sons[2] = n
|
||||||
|
add(v, vpart)
|
||||||
|
|
||||||
|
result.add v
|
||||||
|
result.add genReset(n, c)
|
||||||
|
result.add tempAsNode
|
||||||
|
incl result.flags, nfPreventDestructor
|
||||||
|
|
||||||
|
proc handleSinkParams(n: PNode; c: var Con) =
|
||||||
|
# first pass: introduce copies for stuff passed to
|
||||||
|
# 'sink' parameters. Introduce destructor guards for
|
||||||
|
# 'sink' parameters.
|
||||||
|
assert n.kind in nkCallKinds
|
||||||
|
# Rule 5.2: Compensate for 'sink' parameters with copies
|
||||||
|
# at the callsite (unless of course we can prove its the
|
||||||
|
# last read):
|
||||||
|
let parameters = n.typ
|
||||||
|
let L = if parameters != nil: parameters.len else: 0
|
||||||
|
for i in 1 ..< L:
|
||||||
|
let t = parameters[i]
|
||||||
|
if t.kind == tySink:
|
||||||
|
if n[i].kind in constrExprs:
|
||||||
|
incl(n[i].flags, nfPreventDestructor)
|
||||||
|
elif n[i].kind == nkSym and isHarmlessVar(n[i].sym, c):
|
||||||
|
# if x is a variable and it its last read we eliminate its
|
||||||
|
# destructor invokation, but don't. We need to reset its memory
|
||||||
|
# to disable its destructor which we have not elided:
|
||||||
|
n.sons[i] = destructiveMoveVar(n[i], c)
|
||||||
|
when false:
|
||||||
|
# XXX we need to find a way to compute "all paths consume 'x'"
|
||||||
|
c.symsNoDestructors.incl n[i].sym.id
|
||||||
|
# however, not emiting the copy operation is correct here.
|
||||||
|
elif n[i].kind == nkSym and isSinkParam(n[i].sym):
|
||||||
|
# mark the sink parameter as used:
|
||||||
|
n.sons[i] = destructiveMoveSink(n[i], c)
|
||||||
|
else:
|
||||||
|
# an object that is not temporary but passed to a 'sink' parameter
|
||||||
|
# results in a copy.
|
||||||
|
n.sons[i] = passCopyToSink(n[i], c)
|
||||||
|
|
||||||
proc p(n: PNode; c: var Con): PNode =
|
proc p(n: PNode; c: var Con): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkVarSection, nkLetSection:
|
of nkVarSection, nkLetSection:
|
||||||
|
|
@ -266,22 +401,21 @@ proc p(n: PNode; c: var Con): PNode =
|
||||||
varSection.add itCopy
|
varSection.add itCopy
|
||||||
result.add varSection
|
result.add varSection
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if n.typ != nil and hasDestructor(n.typ):
|
if n.typ != nil and hasDestructor(n.typ) and nfPreventDestructor notin n.flags:
|
||||||
discard "produce temp creation"
|
discard "produce temp creation"
|
||||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||||
let f = newSym(skField, getIdent(":d" & $c.tmpObj.n.len), c.owner, n.info)
|
let tmp = getTemp(c, n.typ, n.info)
|
||||||
f.typ = n.typ
|
var m = genSink(n.typ, tmp)
|
||||||
rawAddField c.tmpObj, f
|
|
||||||
var m = genSink(n.typ, rawDirectAccess(c.tmp, f))
|
|
||||||
var call = copyNode(n)
|
var call = copyNode(n)
|
||||||
recurse(n, call)
|
recurse(n, call)
|
||||||
m.add call
|
m.add call
|
||||||
result.add m
|
result.add m
|
||||||
result.add rawDirectAccess(c.tmp, f)
|
result.add tmp
|
||||||
c.destroys.add genDestroy(n.typ, rawDirectAccess(c.tmp, f))
|
c.destroys.add genDestroy(n.typ, tmp)
|
||||||
else:
|
else:
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
recurse(n, result)
|
recurse(n, result)
|
||||||
|
#handleSinkParams(result, c)
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
if hasDestructor(n[0].typ):
|
if hasDestructor(n[0].typ):
|
||||||
result = moveOrCopy(n[0], n[1], c)
|
result = moveOrCopy(n[0], n[1], c)
|
||||||
|
|
@ -311,6 +445,11 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
|
||||||
for i in 0..<c.g.len:
|
for i in 0..<c.g.len:
|
||||||
if c.g[i].kind in {goto, fork}:
|
if c.g[i].kind in {goto, fork}:
|
||||||
c.jumpTargets.incl(i+c.g[i].dest)
|
c.jumpTargets.incl(i+c.g[i].dest)
|
||||||
|
if owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter}:
|
||||||
|
let params = owner.typ.n
|
||||||
|
for i in 1 ..< params.len:
|
||||||
|
let param = params[i].sym
|
||||||
|
if param.typ.kind == tySink: registerDropBit(c, param)
|
||||||
let body = p(n, c)
|
let body = p(n, c)
|
||||||
if c.tmp.typ.n.len > 0:
|
if c.tmp.typ.n.len > 0:
|
||||||
c.addTopVar(newSymNode c.tmp)
|
c.addTopVar(newSymNode c.tmp)
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ type
|
||||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||||
hintConditionAlwaysTrue, hintName, hintPattern,
|
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||||
hintExecuting, hintLinking, hintDependency,
|
hintExecuting, hintLinking, hintDependency,
|
||||||
hintSource, hintStackTrace, hintGCStats,
|
hintSource, hintPerformance, hintStackTrace, hintGCStats,
|
||||||
hintUser, hintUserRaw
|
hintUser, hintUserRaw
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -438,6 +438,7 @@ const
|
||||||
hintLinking: "",
|
hintLinking: "",
|
||||||
hintDependency: "$1",
|
hintDependency: "$1",
|
||||||
hintSource: "$1",
|
hintSource: "$1",
|
||||||
|
hintPerformance: "$1",
|
||||||
hintStackTrace: "$1",
|
hintStackTrace: "$1",
|
||||||
hintGCStats: "$1",
|
hintGCStats: "$1",
|
||||||
hintUser: "$1",
|
hintUser: "$1",
|
||||||
|
|
@ -460,7 +461,7 @@ const
|
||||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||||
"Source", "StackTrace", "GCStats",
|
"Source", "Performance", "StackTrace", "GCStats",
|
||||||
"User", "UserRaw"]
|
"User", "UserRaw"]
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ type # please make sure we have under 32 options
|
||||||
TOption* = enum # **keep binary compatible**
|
TOption* = enum # **keep binary compatible**
|
||||||
optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
|
optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
|
||||||
optOverflowCheck, optNilCheck,
|
optOverflowCheck, optNilCheck,
|
||||||
optNaNCheck, optInfCheck,
|
optNaNCheck, optInfCheck, optMoveCheck,
|
||||||
optAssert, optLineDir, optWarns, optHints,
|
optAssert, optLineDir, optWarns, optHints,
|
||||||
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
|
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
|
||||||
optLineTrace, # line tracing support (includes stack tracing)
|
optLineTrace, # line tracing support (includes stack tracing)
|
||||||
|
|
@ -119,13 +119,14 @@ var
|
||||||
|
|
||||||
const
|
const
|
||||||
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
|
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
|
||||||
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck}
|
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
|
||||||
|
optMoveCheck}
|
||||||
|
|
||||||
var
|
var
|
||||||
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
|
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||||
optHints, optStackTrace, optLineTrace,
|
optHints, optStackTrace, optLineTrace,
|
||||||
optPatterns, optNilCheck}
|
optPatterns, optNilCheck, optMoveCheck}
|
||||||
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
|
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
|
||||||
gExitcode*: int8
|
gExitcode*: int8
|
||||||
gCmd*: TCommands = cmdNone # the command
|
gCmd*: TCommands = cmdNone # the command
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ const
|
||||||
wTags, wLocks, wGcSafe, wExportNims, wUsed}
|
wTags, wLocks, wGcSafe, wExportNims, wUsed}
|
||||||
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
|
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions,
|
||||||
|
wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||||
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
|
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
|
||||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||||
|
|
@ -323,6 +324,7 @@ proc processOption(c: PContext, n: PNode): bool =
|
||||||
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
|
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
|
||||||
of wNanChecks: onOff(c, n, {optNaNCheck})
|
of wNanChecks: onOff(c, n, {optNaNCheck})
|
||||||
of wInfChecks: onOff(c, n, {optInfCheck})
|
of wInfChecks: onOff(c, n, {optInfCheck})
|
||||||
|
of wMovechecks: onOff(c, n, {optMoveCheck})
|
||||||
of wAssertions: onOff(c, n, {optAssert})
|
of wAssertions: onOff(c, n, {optAssert})
|
||||||
of wWarnings: onOff(c, n, {optWarns})
|
of wWarnings: onOff(c, n, {optWarns})
|
||||||
of wHints: onOff(c, n, {optHints})
|
of wHints: onOff(c, n, {optHints})
|
||||||
|
|
@ -693,7 +695,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
inc c.instCounter
|
inc c.instCounter
|
||||||
if c.instCounter > 100:
|
if c.instCounter > 100:
|
||||||
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||||
|
|
||||||
pragma(c, sym, userPragma.ast, validPragmas)
|
pragma(c, sym, userPragma.ast, validPragmas)
|
||||||
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
|
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
|
||||||
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
|
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
|
||||||
|
|
@ -906,7 +908,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization,
|
wLinedir, wStacktrace, wLinetrace, wOptimization, wMovechecks,
|
||||||
wCallconv,
|
wCallconv,
|
||||||
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
|
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
|
||||||
wPatterns:
|
wPatterns:
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ proc semConstrField(c: PContext, flags: TExprFlags,
|
||||||
return initValue
|
return initValue
|
||||||
|
|
||||||
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
|
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
|
||||||
for i in 0 .. (branch.len - 2):
|
for i in 0 .. branch.len-2:
|
||||||
if exprStructuralEquivalent(branch[i], matched):
|
if exprStructuralEquivalent(branch[i], matched):
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ type
|
||||||
wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
|
wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
|
||||||
wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
|
wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks,
|
wBoundchecks, wOverflowchecks, wNilchecks,
|
||||||
wFloatchecks, wNanChecks, wInfChecks,
|
wFloatchecks, wNanChecks, wInfChecks, wMoveChecks,
|
||||||
wAssertions, wPatterns, wWarnings,
|
wAssertions, wPatterns, wWarnings,
|
||||||
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
|
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
|
||||||
wDeadCodeElim, wSafecode, wPackage, wNoForward, wReorder, wNoRewrite,
|
wDeadCodeElim, wSafecode, wPackage, wNoForward, wReorder, wNoRewrite,
|
||||||
|
|
@ -139,7 +139,7 @@ const
|
||||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
|
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
|
||||||
"noconv", "on", "off", "checks", "rangechecks", "boundchecks",
|
"noconv", "on", "off", "checks", "rangechecks", "boundchecks",
|
||||||
"overflowchecks", "nilchecks",
|
"overflowchecks", "nilchecks",
|
||||||
"floatchecks", "nanchecks", "infchecks",
|
"floatchecks", "nanchecks", "infchecks", "movechecks",
|
||||||
|
|
||||||
"assertions", "patterns", "warnings", "hints",
|
"assertions", "patterns", "warnings", "hints",
|
||||||
"optimization", "raises", "writes", "reads", "size", "effects", "tags",
|
"optimization", "raises", "writes", "reads", "size", "effects", "tags",
|
||||||
|
|
|
||||||
|
|
@ -617,6 +617,11 @@ type
|
||||||
##
|
##
|
||||||
## This is only raised if the ``segfaults.nim`` module was imported!
|
## This is only raised if the ``segfaults.nim`` module was imported!
|
||||||
|
|
||||||
|
when defined(nimNewRuntime):
|
||||||
|
type
|
||||||
|
MoveError* = object of SystemError ## \
|
||||||
|
## Raised on attempts to re-sink an already consumed ``sink`` parameter.
|
||||||
|
|
||||||
{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect,
|
{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect,
|
||||||
FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect,
|
FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect,
|
||||||
FWriteIO: WriteIOEffect, FExecIO: ExecIOEffect,
|
FWriteIO: WriteIOEffect, FExecIO: ExecIOEffect,
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,11 @@ proc chckNil(p: pointer) =
|
||||||
if p == nil:
|
if p == nil:
|
||||||
sysFatal(NilAccessError, "attempt to write to a nil address")
|
sysFatal(NilAccessError, "attempt to write to a nil address")
|
||||||
|
|
||||||
|
when defined(nimNewRuntime):
|
||||||
|
proc chckMove(b: bool) {.compilerproc.} =
|
||||||
|
if not b:
|
||||||
|
sysFatal(MoveError, "attempt to access an object that was moved")
|
||||||
|
|
||||||
proc chckNilDisp(p: pointer) {.compilerproc.} =
|
proc chckNilDisp(p: pointer) {.compilerproc.} =
|
||||||
if p == nil:
|
if p == nil:
|
||||||
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
|
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue