summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/parampatterns.nim60
-rw-r--r--compiler/semexprs.nim14
-rw-r--r--compiler/semmagic.nim6
-rw-r--r--lib/system.nim3
4 files changed, 42 insertions, 41 deletions
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index bfbc72675..cceb236ae 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -179,6 +179,7 @@ type
     arLocalLValue,            # is an l-value, but local var; must not escape
                               # its stack frame!
     arDiscriminant,           # is a discriminant
+    arAddressableConst,       # an addressable const
     arLentValue,              # lent value
     arStrange                 # it is a strange beast like 'typedesc[var T]'
 
@@ -212,7 +213,7 @@ proc exprRoot*(n: PNode): PSym =
     else:
       break
 
-proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
+proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
   ## 'owner' can be nil!
   result = arNone
   case n.kind
@@ -220,20 +221,20 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
     if n.typ != nil and n.typ.kind in {tyVar}:
       result = arLValue
   of nkSym:
-    let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
-                else: {skVar, skResult, skTemp}
-    if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}:
-      result = arLValue
-    elif isUnsafeAddr and n.sym.kind == skParam:
-      result = arLValue
-    elif isUnsafeAddr and n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast):
-      result = arLValue
+    const kinds = {skVar, skResult, skTemp, skParam, skLet, skForVar}
+    if n.sym.kind == skParam:
+      result = if n.sym.typ.kind in {tyVar, tySink}: arLValue else: arAddressableConst
+    elif n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast):
+      result = arAddressableConst
     elif n.sym.kind in kinds:
-      if owner != nil and owner == n.sym.owner and
-          sfGlobal notin n.sym.flags:
-        result = arLocalLValue
+      if n.sym.kind in {skParam, skLet, skForVar}:
+        result = arAddressableConst
       else:
-        result = arLValue
+        if owner != nil and owner == n.sym.owner and
+            sfGlobal notin n.sym.flags:
+          result = arLocalLValue
+        else:
+          result = arLValue
     elif n.sym.kind == skType:
       let t = n.sym.typ.skipTypes({tyTypeDesc})
       if t.kind in {tyVar}: result = arStrange
@@ -241,10 +242,10 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
     let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
     if t.kind in {tyVar, tySink, tyPtr, tyRef}:
       result = arLValue
-    elif isUnsafeAddr and t.kind == tyLent:
-      result = arLValue
+    elif t.kind == tyLent:
+      result = arAddressableConst
     else:
-      result = isAssignable(owner, n[0], isUnsafeAddr)
+      result = isAssignable(owner, n[0])
     if result != arNone and n[1].kind == nkSym and
         sfDiscriminant in n[1].sym.flags:
       result = arDiscriminant
@@ -252,23 +253,23 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
     let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
     if t.kind in {tyVar, tySink, tyPtr, tyRef}:
       result = arLValue
-    elif isUnsafeAddr and t.kind == tyLent:
-      result = arLValue
+    elif t.kind == tyLent:
+      result = arAddressableConst
     else:
-      result = isAssignable(owner, n[0], isUnsafeAddr)
+      result = isAssignable(owner, n[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     # Object and tuple conversions are still addressable, so we skip them
     # XXX why is 'tyOpenArray' allowed here?
     if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
         {tyOpenArray, tyTuple, tyObject}:
-      result = isAssignable(owner, n[1], isUnsafeAddr)
+      result = isAssignable(owner, n[1])
     elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct):
       # types that are equal modulo distinction preserve l-value:
-      result = isAssignable(owner, n[1], isUnsafeAddr)
+      result = isAssignable(owner, n[1])
   of nkHiddenDeref:
     let n0 = n[0]
     if n0.typ.kind == tyLent:
-      if isUnsafeAddr or (n0.kind == nkSym and n0.sym.kind == skResult):
+      if n0.kind == nkSym and n0.sym.kind == skResult:
         result = arLValue
       else:
         result = arLentValue
@@ -277,18 +278,19 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
   of nkDerefExpr, nkHiddenAddr:
     result = arLValue
   of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
-    result = isAssignable(owner, n[0], isUnsafeAddr)
+    result = isAssignable(owner, n[0])
   of nkCallKinds:
     # builtin slice keeps lvalue-ness:
     if getMagic(n) in {mArrGet, mSlice}:
-      result = isAssignable(owner, n[1], isUnsafeAddr)
-    elif n.typ != nil and n.typ.kind in {tyVar}:
-      result = arLValue
-    elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent:
-      result = arLValue
+      result = isAssignable(owner, n[1])
+    elif n.typ != nil:
+      case n.typ.kind
+      of tyVar: result = arLValue
+      of tyLent: result = arLentValue
+      else: discard
   of nkStmtList, nkStmtListExpr:
     if n.typ != nil:
-      result = isAssignable(owner, n.lastSon, isUnsafeAddr)
+      result = isAssignable(owner, n.lastSon)
   of nkVarTy:
     # XXX: The fact that this is here is a bit of a hack.
     # The goal is to allow the use of checks such as "foo(var T)"
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c593efe55..5f3d065b6 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -650,8 +650,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
           changeType(c, it[1], s, check=true)
         n[i] = it[1]
 
-proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
-  result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
+proc isAssignable(c: PContext, n: PNode): TAssignableResult =
+  result = parampatterns.isAssignable(c.p.owner, n)
 
 proc isUnresolvedSym(s: PSym): bool =
   result = s.kind == skGenericParam
@@ -1658,9 +1658,11 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
     # `proc fun(a: var int): var int = a`
     discard
   else: discard
-  let valid = isAssignable(c, n, isLent)
+  let valid = isAssignable(c, n)
   if valid != arLValue:
-    if valid == arLocalLValue:
+    if valid in {arAddressableConst, arLentValue} and isLent:
+      discard "ok"
+    elif valid == arLocalLValue:
       localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments}))
     else:
       localError(c.config, n.info, errExprHasNoAddress)
@@ -1784,7 +1786,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   if le == nil:
     localError(c.config, a.info, "expression has no type")
   elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
-        isAssignable(c, a) in {arNone, arLentValue}) or (
+        isAssignable(c, a) in {arNone, arLentValue, arAddressableConst}) or (
       skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
     # Direct assignment to a discriminant is allowed!
     localError(c.config, a.info, errXCannotBeAssignedTo %
@@ -2267,7 +2269,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     markUsed(c, n.info, s)
     checkSonsLen(n, 2, c.config)
     result[0] = newSymNode(s, n[0].info)
-    result[1] = semAddrArg(c, n[1], s.name.s == "unsafeAddr")
+    result[1] = semAddrArg(c, n[1])
     result.typ = makePtrType(c, result[1].typ)
   of mTypeOf:
     markUsed(c, n.info, s)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index c7fc75620..ed1826fd4 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -10,11 +10,11 @@
 # This include file implements the semantic checking for magics.
 # included from sem.nim
 
-proc semAddrArg(c: PContext; n: PNode; isUnsafeAddr = false): PNode =
+proc semAddrArg(c: PContext; n: PNode): PNode =
   let x = semExprWithType(c, n)
   if x.kind == nkSym:
     x.sym.flags.incl(sfAddrTaken)
-  if isAssignable(c, x, true) notin {arLValue, arLocalLValue}:
+  if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}:
     localError(c.config, n.info, errExprHasNoAddress)
   result = x
 
@@ -466,7 +466,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mAddr:
     checkSonsLen(n, 2, c.config)
     result = n
-    result[1] = semAddrArg(c, n[1], n[0].sym.name.s == "unsafeAddr")
+    result[1] = semAddrArg(c, n[1])
     result.typ = makePtrType(c, result[1].typ)
   of mTypeOf:
     result = semTypeOf(c, n)
diff --git a/lib/system.nim b/lib/system.nim
index 56a6e2887..572768de2 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -202,9 +202,6 @@ proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
   ##
   ## Cannot be overloaded.
   ##
-  ## See also:
-  ## * `unsafeAddr <#unsafeAddr,T>`_
-  ##
   ## .. code-block:: Nim
   ##  var
   ##    buf: seq[char] = @['a','b','c']