diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-11-26 23:28:02 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-11-27 00:36:29 +0100 |
commit | 413580bc0444fc9d8e01b6af01433f8c08d2d298 (patch) | |
tree | 1b1d5b7ce15100a612621a1cd8871257c4359784 | |
parent | 93cf0ef52ef81af15009566f90e0d020903e8c2b (diff) | |
download | Nim-413580bc0444fc9d8e01b6af01433f8c08d2d298.tar.gz |
new minor language feature: .noSideEffect blocks like .gcsafe blocks
-rw-r--r-- | changelog.md | 3 | ||||
-rw-r--r-- | compiler/pragmas.nim | 7 | ||||
-rw-r--r-- | compiler/sempass2.nim | 10 | ||||
-rw-r--r-- | compiler/semstmts.nim | 2 | ||||
-rw-r--r-- | compiler/vmgen.nim | 3 | ||||
-rw-r--r-- | doc/manual.rst | 10 | ||||
-rw-r--r-- | lib/core/seqs.nim | 7 |
7 files changed, 30 insertions, 12 deletions
diff --git a/changelog.md b/changelog.md index 034acf267..3ecc77614 100644 --- a/changelog.md +++ b/changelog.md @@ -89,7 +89,8 @@ proc enumToString*(enums: openArray[enum]): string = ### Language additions - Vm suport for float32<->int32 and float64<->int64 casts was added. - +- There is a new pragma block `noSideEffect` that works like + the `gcsafe` pragma block. ### Language changes diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 62f70a090..2ce6b2231 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -38,7 +38,7 @@ const wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, wTags, wLocks, wGcSafe, wExportNims, wUsed} - exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe} + exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNosideeffect} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions, wWarnings, wHints, @@ -855,8 +855,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, sym.flags.incl sfOverriden of wNosideeffect: noVal(c, it) - incl(sym.flags, sfNoSideEffect) - if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) + if sym != nil: + incl(sym.flags, sfNoSideEffect) + if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) of wSideeffect: noVal(c, it) incl(sym.flags, sfSideEffect) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 0317fd8ba..75dea069f 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -56,6 +56,7 @@ type guards: TModel # nested guards locked: seq[PNode] # locked locations gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool + inEnforcedNoSideEffects: bool maxLockLevel, currLockLevel: TLockLevel config: ConfigRef graph: ModuleGraph @@ -194,10 +195,10 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = when true: template markSideEffect(a: PEffects; reason: typed) = - a.hasSideEffect = true + if not a.inEnforcedNoSideEffects: a.hasSideEffect = true else: template markSideEffect(a: PEffects; reason: typed) = - a.hasSideEffect = true + if not a.inEnforcedNoSideEffects: a.hasSideEffect = true markGcUnsafe(a, reason) proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) = @@ -846,15 +847,20 @@ proc track(tracked: PEffects, n: PNode) = let oldLocked = tracked.locked.len let oldLockLevel = tracked.currLockLevel var enforcedGcSafety = false + var enforceNoSideEffects = false for i in 0 ..< pragmaList.len: let pragma = whichPragma(pragmaList.sons[i]) if pragma == wLocks: lockLocations(tracked, pragmaList.sons[i]) elif pragma == wGcSafe: enforcedGcSafety = true + elif pragma == wNosideeffect: + enforceNoSideEffects = true if enforcedGcSafety: tracked.inEnforcedGcSafe = true + if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true track(tracked, n.lastSon) if enforcedGcSafety: tracked.inEnforcedGcSafe = false + if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false setLen(tracked.locked, oldLocked) tracked.currLockLevel = oldLockLevel of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 1f2b9f0b3..2af34646c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1860,7 +1860,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = for i in 0 ..< pragmaList.len: case whichPragma(pragmaList.sons[i]) of wLine: setLine(result, pragmaList.sons[i].info) - of wLocks, wGcSafe: + of wLocks, wGcSafe, wNosideeffect: result = n result.typ = n.sons[1].typ of wNoRewrite: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index aef40346f..1f2a3e6d1 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1239,8 +1239,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opcCallSite, dest) of mNGenSym: genBinaryABC(c, n, dest, opcGenSym) - of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, - mDotDot: + of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, mDotDot: c.genCall(n, dest) of mExpandToAst: if n.len != 2: diff --git a/doc/manual.rst b/doc/manual.rst index b39711dfb..a646b7963 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6755,6 +6755,16 @@ routines marked as ``noSideEffect``. func `+` (x, y: int): int +To override the compiler's side effect analysis a ``{.noSideEffect.}`` +pragma block can be used: + +.. code-block:: nim + + func f() = + {.noSideEffect.}: + echo "test" + + compileTime pragma ------------------ The ``compileTime`` pragma is used to mark a proc or variable to be used at diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index fb81a30de..1981998df 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -82,7 +82,7 @@ type cap: int region: Allocator -proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} = +proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, noSideEffect.} = # we have to use type erasure here as Nim does not support generic # compilerProcs. Oh well, this will all be inlined anyway. if cap <= 0: @@ -94,7 +94,8 @@ proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} = else: result = nil -proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.compilerRtl.} = +proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {. + compilerRtl, noSideEffect.} = if len+addlen <= len: result = p elif p == nil: @@ -128,7 +129,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T))) xu.len = newLen for i in oldLen .. newLen-1: - x.data[i] = value + xu.p.data[i] = value proc setLen[T](s: var seq[T], newlen: Natural) = if newlen < s.len: |