summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-01-18 12:55:33 +0100
committerAndreas Rumpf <rumpf_a@web.de>2017-01-18 12:55:33 +0100
commit2f08fdf6238baefca633ebbd2776ec366288e96d (patch)
tree55d99a3138b458f8786ab78632a1dd1737ee64e8 /compiler
parentb6b5a11be78961cebd4f3d0b354b227373f64427 (diff)
downloadNim-2f08fdf6238baefca633ebbd2776ec366288e96d.tar.gz
implements {.gcsafe.} enforcement as a pragma block
Diffstat (limited to 'compiler')
-rw-r--r--compiler/pragmas.nim11
-rw-r--r--compiler/sempass2.nim30
-rw-r--r--compiler/semstmts.nim2
3 files changed, 27 insertions, 16 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index a21705208..85e850834 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}
-  exprPragmas* = {wLine, wLocks, wNoRewrite}
+  exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
     wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
@@ -775,9 +775,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault
       of wGcSafe:
         noVal(it)
-        if sym.kind != skType: incl(sym.flags, sfThread)
-        if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
-        else: invalidPragma(it)
+        if sym != nil:
+          if sym.kind != skType: incl(sym.flags, sfThread)
+          if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
+          else: invalidPragma(it)
+        else:
+          discard "no checking if used as a code block"
       of wPacked:
         noVal(it)
         if sym.typ == nil: invalidPragma(it)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 8aa8f15c8..437a45817 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -59,7 +59,7 @@ type
     init: seq[int] # list of initialized variables
     guards: TModel # nested guards
     locked: seq[PNode] # locked locations
-    gcUnsafe, isRecursive, isToplevel, hasSideEffect: bool
+    gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
     maxLockLevel, currLockLevel: TLockLevel
   PEffects = var TEffects
 
@@ -180,17 +180,19 @@ proc warnAboutGcUnsafe(n: PNode) =
   message(n.info, warnGcUnsafe, renderTree(n))
 
 proc markGcUnsafe(a: PEffects; reason: PSym) =
-  a.gcUnsafe = true
-  if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
+  if not a.inEnforcedGcSafe:
+    a.gcUnsafe = true
+    if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
 
 proc markGcUnsafe(a: PEffects; reason: PNode) =
-  a.gcUnsafe = true
-  if a.owner.kind in routineKinds:
-    if reason.kind == nkSym:
-      a.owner.gcUnsafetyReason = reason.sym
-    else:
-      a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
-                                        a.owner, reason.info)
+  if not a.inEnforcedGcSafe:
+    a.gcUnsafe = true
+    if a.owner.kind in routineKinds:
+      if reason.kind == nkSym:
+        a.owner.gcUnsafetyReason = reason.sym
+      else:
+        a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
+                                          a.owner, reason.info)
 
 when true:
   template markSideEffect(a: PEffects; reason: typed) =
@@ -803,10 +805,16 @@ proc track(tracked: PEffects, n: PNode) =
     let pragmaList = n.sons[0]
     let oldLocked = tracked.locked.len
     let oldLockLevel = tracked.currLockLevel
+    var enforcedGcSafety = false
     for i in 0 .. <pragmaList.len:
-      if whichPragma(pragmaList.sons[i]) == wLocks:
+      let pragma = whichPragma(pragmaList.sons[i])
+      if pragma == wLocks:
         lockLocations(tracked, pragmaList.sons[i])
+      elif pragma == wGcSafe:
+        enforcedGcSafety = true
+    if enforcedGcSafety: tracked.inEnforcedGcSafe = true
     track(tracked, n.lastSon)
+    if enforcedGcSafety: tracked.inEnforcedGcSafe = 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 365109249..bbc83eca4 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1444,7 +1444,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:
+    of wLocks, wGcSafe:
       result = n
       result.typ = n.sons[1].typ
     of wNoRewrite: