* implements https://github.com/nim-lang/RFCs/issues/369 * deprecate unsafeAddr; extend addr addr is now available for all addressable locations, unsafeAddr is deprecated and become an alias for addr * follow @Vindaar's advice * change the signature of addr * unsafeAddr => addr (stdlib) * Update changelog.md * unsafeAddr => addr (tests) * Revert "unsafeAddr => addr (stdlib)" This reverts commit ab83c99c507048a8396e636bf22d55fdd84d7d1c. * doc changes; thanks to @konsumlamm Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> * merge * remove * fix bug Co-authored-by: Araq <rumpf_a@web.de> Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
This commit is contained in:
parent
207237cec2
commit
d6d36093b1
4 changed files with 42 additions and 41 deletions
|
|
@ -179,6 +179,7 @@ type
|
||||||
arLocalLValue, # is an l-value, but local var; must not escape
|
arLocalLValue, # is an l-value, but local var; must not escape
|
||||||
# its stack frame!
|
# its stack frame!
|
||||||
arDiscriminant, # is a discriminant
|
arDiscriminant, # is a discriminant
|
||||||
|
arAddressableConst, # an addressable const
|
||||||
arLentValue, # lent value
|
arLentValue, # lent value
|
||||||
arStrange # it is a strange beast like 'typedesc[var T]'
|
arStrange # it is a strange beast like 'typedesc[var T]'
|
||||||
|
|
||||||
|
|
@ -212,7 +213,7 @@ proc exprRoot*(n: PNode): PSym =
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||||
## 'owner' can be nil!
|
## 'owner' can be nil!
|
||||||
result = arNone
|
result = arNone
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -220,15 +221,15 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
if n.typ != nil and n.typ.kind in {tyVar}:
|
if n.typ != nil and n.typ.kind in {tyVar}:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
|
const kinds = {skVar, skResult, skTemp, skParam, skLet, skForVar}
|
||||||
else: {skVar, skResult, skTemp}
|
if n.sym.kind == skParam:
|
||||||
if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}:
|
result = if n.sym.typ.kind in {tyVar, tySink}: arLValue else: arAddressableConst
|
||||||
result = arLValue
|
elif n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast):
|
||||||
elif isUnsafeAddr and n.sym.kind == skParam:
|
result = arAddressableConst
|
||||||
result = arLValue
|
|
||||||
elif isUnsafeAddr and n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast):
|
|
||||||
result = arLValue
|
|
||||||
elif n.sym.kind in kinds:
|
elif n.sym.kind in kinds:
|
||||||
|
if n.sym.kind in {skParam, skLet, skForVar}:
|
||||||
|
result = arAddressableConst
|
||||||
|
else:
|
||||||
if owner != nil and owner == n.sym.owner and
|
if owner != nil and owner == n.sym.owner and
|
||||||
sfGlobal notin n.sym.flags:
|
sfGlobal notin n.sym.flags:
|
||||||
result = arLocalLValue
|
result = arLocalLValue
|
||||||
|
|
@ -241,10 +242,10 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
|
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
|
||||||
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
elif isUnsafeAddr and t.kind == tyLent:
|
elif t.kind == tyLent:
|
||||||
result = arLValue
|
result = arAddressableConst
|
||||||
else:
|
else:
|
||||||
result = isAssignable(owner, n[0], isUnsafeAddr)
|
result = isAssignable(owner, n[0])
|
||||||
if result != arNone and n[1].kind == nkSym and
|
if result != arNone and n[1].kind == nkSym and
|
||||||
sfDiscriminant in n[1].sym.flags:
|
sfDiscriminant in n[1].sym.flags:
|
||||||
result = arDiscriminant
|
result = arDiscriminant
|
||||||
|
|
@ -252,23 +253,23 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
|
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
|
||||||
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
elif isUnsafeAddr and t.kind == tyLent:
|
elif t.kind == tyLent:
|
||||||
result = arLValue
|
result = arAddressableConst
|
||||||
else:
|
else:
|
||||||
result = isAssignable(owner, n[0], isUnsafeAddr)
|
result = isAssignable(owner, n[0])
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
# Object and tuple conversions are still addressable, so we skip them
|
# Object and tuple conversions are still addressable, so we skip them
|
||||||
# XXX why is 'tyOpenArray' allowed here?
|
# XXX why is 'tyOpenArray' allowed here?
|
||||||
if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
|
if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
|
||||||
{tyOpenArray, tyTuple, tyObject}:
|
{tyOpenArray, tyTuple, tyObject}:
|
||||||
result = isAssignable(owner, n[1], isUnsafeAddr)
|
result = isAssignable(owner, n[1])
|
||||||
elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct):
|
elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct):
|
||||||
# types that are equal modulo distinction preserve l-value:
|
# types that are equal modulo distinction preserve l-value:
|
||||||
result = isAssignable(owner, n[1], isUnsafeAddr)
|
result = isAssignable(owner, n[1])
|
||||||
of nkHiddenDeref:
|
of nkHiddenDeref:
|
||||||
let n0 = n[0]
|
let n0 = n[0]
|
||||||
if n0.typ.kind == tyLent:
|
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
|
result = arLValue
|
||||||
else:
|
else:
|
||||||
result = arLentValue
|
result = arLentValue
|
||||||
|
|
@ -277,18 +278,19 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
of nkDerefExpr, nkHiddenAddr:
|
of nkDerefExpr, nkHiddenAddr:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||||
result = isAssignable(owner, n[0], isUnsafeAddr)
|
result = isAssignable(owner, n[0])
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
# builtin slice keeps lvalue-ness:
|
# builtin slice keeps lvalue-ness:
|
||||||
if getMagic(n) in {mArrGet, mSlice}:
|
if getMagic(n) in {mArrGet, mSlice}:
|
||||||
result = isAssignable(owner, n[1], isUnsafeAddr)
|
result = isAssignable(owner, n[1])
|
||||||
elif n.typ != nil and n.typ.kind in {tyVar}:
|
elif n.typ != nil:
|
||||||
result = arLValue
|
case n.typ.kind
|
||||||
elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent:
|
of tyVar: result = arLValue
|
||||||
result = arLValue
|
of tyLent: result = arLentValue
|
||||||
|
else: discard
|
||||||
of nkStmtList, nkStmtListExpr:
|
of nkStmtList, nkStmtListExpr:
|
||||||
if n.typ != nil:
|
if n.typ != nil:
|
||||||
result = isAssignable(owner, n.lastSon, isUnsafeAddr)
|
result = isAssignable(owner, n.lastSon)
|
||||||
of nkVarTy:
|
of nkVarTy:
|
||||||
# XXX: The fact that this is here is a bit of a hack.
|
# 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)"
|
# The goal is to allow the use of checks such as "foo(var T)"
|
||||||
|
|
|
||||||
|
|
@ -650,8 +650,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||||
changeType(c, it[1], s, check=true)
|
changeType(c, it[1], s, check=true)
|
||||||
n[i] = it[1]
|
n[i] = it[1]
|
||||||
|
|
||||||
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||||
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
|
result = parampatterns.isAssignable(c.p.owner, n)
|
||||||
|
|
||||||
proc isUnresolvedSym(s: PSym): bool =
|
proc isUnresolvedSym(s: PSym): bool =
|
||||||
result = s.kind == skGenericParam
|
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`
|
# `proc fun(a: var int): var int = a`
|
||||||
discard
|
discard
|
||||||
else: discard
|
else: discard
|
||||||
let valid = isAssignable(c, n, isLent)
|
let valid = isAssignable(c, n)
|
||||||
if valid != arLValue:
|
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}))
|
localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments}))
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, errExprHasNoAddress)
|
localError(c.config, n.info, errExprHasNoAddress)
|
||||||
|
|
@ -1784,7 +1786,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
if le == nil:
|
if le == nil:
|
||||||
localError(c.config, a.info, "expression has no type")
|
localError(c.config, a.info, "expression has no type")
|
||||||
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
|
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):
|
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs} and views notin c.features):
|
||||||
# Direct assignment to a discriminant is allowed!
|
# Direct assignment to a discriminant is allowed!
|
||||||
localError(c.config, a.info, errXCannotBeAssignedTo %
|
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)
|
markUsed(c, n.info, s)
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
result[0] = newSymNode(s, n[0].info)
|
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)
|
result.typ = makePtrType(c, result[1].typ)
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
markUsed(c, n.info, s)
|
markUsed(c, n.info, s)
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@
|
||||||
# This include file implements the semantic checking for magics.
|
# This include file implements the semantic checking for magics.
|
||||||
# included from sem.nim
|
# 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)
|
let x = semExprWithType(c, n)
|
||||||
if x.kind == nkSym:
|
if x.kind == nkSym:
|
||||||
x.sym.flags.incl(sfAddrTaken)
|
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)
|
localError(c.config, n.info, errExprHasNoAddress)
|
||||||
result = x
|
result = x
|
||||||
|
|
||||||
|
|
@ -466,7 +466,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
of mAddr:
|
of mAddr:
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
result = n
|
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)
|
result.typ = makePtrType(c, result[1].typ)
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
result = semTypeOf(c, n)
|
result = semTypeOf(c, n)
|
||||||
|
|
|
||||||
|
|
@ -202,9 +202,6 @@ proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
|
||||||
##
|
##
|
||||||
## Cannot be overloaded.
|
## Cannot be overloaded.
|
||||||
##
|
##
|
||||||
## See also:
|
|
||||||
## * `unsafeAddr <#unsafeAddr,T>`_
|
|
||||||
##
|
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## var
|
## var
|
||||||
## buf: seq[char] = @['a','b','c']
|
## buf: seq[char] = @['a','b','c']
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue