added system.unsafeAddr
This commit is contained in:
parent
f8f9677205
commit
ab26298a03
7 changed files with 48 additions and 16 deletions
|
|
@ -178,13 +178,14 @@ type
|
||||||
arDiscriminant, # is a discriminant
|
arDiscriminant, # is a discriminant
|
||||||
arStrange # it is a strange beast like 'typedesc[var T]'
|
arStrange # it is a strange beast like 'typedesc[var T]'
|
||||||
|
|
||||||
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
||||||
## 'owner' can be nil!
|
## 'owner' can be nil!
|
||||||
result = arNone
|
result = arNone
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
# don't list 'skLet' here:
|
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
|
||||||
if n.sym.kind in {skVar, skResult, skTemp}:
|
else: {skVar, skResult, skTemp}
|
||||||
|
if n.sym.kind in kinds:
|
||||||
if owner != nil and owner.id == n.sym.owner.id and
|
if owner != nil and owner.id == n.sym.owner.id and
|
||||||
sfGlobal notin n.sym.flags:
|
sfGlobal notin n.sym.flags:
|
||||||
result = arLocalLValue
|
result = arLocalLValue
|
||||||
|
|
@ -200,7 +201,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||||
{tyVar, tyPtr, tyRef}:
|
{tyVar, tyPtr, tyRef}:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
else:
|
else:
|
||||||
result = isAssignable(owner, n.sons[0])
|
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||||
if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
|
if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
|
||||||
result = arDiscriminant
|
result = arDiscriminant
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
|
|
@ -208,23 +209,24 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
|
||||||
{tyVar, tyPtr, tyRef}:
|
{tyVar, tyPtr, tyRef}:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
else:
|
else:
|
||||||
result = isAssignable(owner, n.sons[0])
|
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||||
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.sons[1])
|
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
|
||||||
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
|
elif compareTypes(n.typ, n.sons[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.sons[1])
|
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
|
||||||
of nkHiddenDeref, nkDerefExpr, nkHiddenAddr:
|
of nkHiddenDeref, nkDerefExpr, nkHiddenAddr:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||||
result = isAssignable(owner, n.sons[0])
|
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
# builtin slice keeps lvalue-ness:
|
# builtin slice keeps lvalue-ness:
|
||||||
if getMagic(n) == mSlice: result = isAssignable(owner, n.sons[1])
|
if getMagic(n) == mSlice:
|
||||||
|
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -597,8 +597,8 @@ proc skipObjConv(n: PNode): PNode =
|
||||||
of nkObjUpConv, nkObjDownConv: result = n.sons[0]
|
of nkObjUpConv, nkObjDownConv: result = n.sons[0]
|
||||||
else: result = n
|
else: result = n
|
||||||
|
|
||||||
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
||||||
result = parampatterns.isAssignable(c.p.owner, n)
|
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
|
||||||
|
|
||||||
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||||
if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
|
if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
|
||||||
|
|
@ -1700,7 +1700,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
case s.magic # magics that need special treatment
|
case s.magic # magics that need special treatment
|
||||||
of mAddr:
|
of mAddr:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semAddr(c, n.sons[1])
|
result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr")
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semTypeOf(c, n.sons[1])
|
result = semTypeOf(c, n.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@
|
||||||
# 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 semAddr(c: PContext; n: PNode): PNode =
|
proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode =
|
||||||
result = newNodeI(nkAddr, n.info)
|
result = newNodeI(nkAddr, n.info)
|
||||||
let x = semExprWithType(c, n)
|
let x = semExprWithType(c, n)
|
||||||
if isAssignable(c, x) notin {arLValue, arLocalLValue}:
|
if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
|
||||||
localError(n.info, errExprHasNoAddress)
|
localError(n.info, errExprHasNoAddress)
|
||||||
result.add x
|
result.add x
|
||||||
result.typ = makePtrType(c, x.typ)
|
result.typ = makePtrType(c, x.typ)
|
||||||
|
|
@ -119,7 +119,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
case n[0].sym.magic
|
case n[0].sym.magic
|
||||||
of mAddr:
|
of mAddr:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semAddr(c, n.sons[1])
|
result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semTypeOf(c, n.sons[1])
|
result = semTypeOf(c, n.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,13 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
|
||||||
## Cannot be overloaded.
|
## Cannot be overloaded.
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
proc unsafeAddr*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
|
||||||
|
## Builtin 'addr' operator for taking the address of a memory location.
|
||||||
|
## This works even for ``let`` variables or parameters for better interop
|
||||||
|
## with C and so it is considered even more unsafe than the ordinary ``addr``.
|
||||||
|
## Cannot be overloaded.
|
||||||
|
discard
|
||||||
|
|
||||||
proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} =
|
proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} =
|
||||||
## Builtin 'type' operator for accessing the type of an expression.
|
## Builtin 'type' operator for accessing the type of an expression.
|
||||||
## Cannot be overloaded.
|
## Cannot be overloaded.
|
||||||
|
|
|
||||||
19
tests/ccgbugs/tunsafeaddr.nim
Normal file
19
tests/ccgbugs/tunsafeaddr.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
discard """
|
||||||
|
output: '''12'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
{.emit: """
|
||||||
|
long sum(long* a, long len) {
|
||||||
|
long i, result = 0;
|
||||||
|
for (i = 0; i < len; ++i) result += a[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
""".}
|
||||||
|
|
||||||
|
proc sum(a: ptr int; len: int): int {.importc, nodecl.}
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
let foo = [8, 3, 1]
|
||||||
|
echo sum(unsafeAddr foo[0], foo.len)
|
||||||
|
|
||||||
|
main()
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -1,7 +1,6 @@
|
||||||
version 0.11.4
|
version 0.11.4
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- ``unsafeAddr``
|
|
||||||
- document special cased varargs[untyped] and varargs[typed]
|
- document special cased varargs[untyped] and varargs[typed]
|
||||||
|
|
||||||
- The remaining bugs of the lambda lifting pass that is responsible to enable
|
- The remaining bugs of the lambda lifting pass that is responsible to enable
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,11 @@ News
|
||||||
Language Additions
|
Language Additions
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- ``system.unsafeAddr`` can be used to access the address of a ``let``
|
||||||
|
variable or parameter for C interoperability. Since technically this
|
||||||
|
makes parameters and ``let`` variables mutable, it is considered even more
|
||||||
|
unsafe than the ordinary ``addr`` builtin.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
--------
|
--------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue