added system.unsafeAddr

This commit is contained in:
Araq 2015-08-04 17:31:00 +02:00
commit ab26298a03
7 changed files with 48 additions and 16 deletions

View file

@ -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

View file

@ -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])

View file

@ -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])

View file

@ -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.

View 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()

View file

@ -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

View file

@ -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
-------- --------