summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2018-11-26 23:28:02 +0100
committerAndreas Rumpf <rumpf_a@web.de>2018-11-27 00:36:29 +0100
commit413580bc0444fc9d8e01b6af01433f8c08d2d298 (patch)
tree1b1d5b7ce15100a612621a1cd8871257c4359784
parent93cf0ef52ef81af15009566f90e0d020903e8c2b (diff)
downloadNim-413580bc0444fc9d8e01b6af01433f8c08d2d298.tar.gz
new minor language feature: .noSideEffect blocks like .gcsafe blocks
-rw-r--r--changelog.md3
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/sempass2.nim10
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/vmgen.nim3
-rw-r--r--doc/manual.rst10
-rw-r--r--lib/core/seqs.nim7
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: