Merge ../Nim into devel

This commit is contained in:
Charles Blake
2015-08-04 16:13:45 -04:00
8 changed files with 49 additions and 17 deletions

View File

@@ -178,13 +178,14 @@ type
arDiscriminant, # is a discriminant
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!
result = arNone
case n.kind
of nkSym:
# don't list 'skLet' here:
if n.sym.kind in {skVar, skResult, skTemp}:
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
else: {skVar, skResult, skTemp}
if n.sym.kind in kinds:
if owner != nil and owner.id == n.sym.owner.id and
sfGlobal notin n.sym.flags:
result = arLocalLValue
@@ -200,7 +201,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
{tyVar, tyPtr, tyRef}:
result = arLValue
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:
result = arDiscriminant
of nkBracketExpr:
@@ -208,23 +209,24 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
{tyVar, tyPtr, tyRef}:
result = arLValue
else:
result = isAssignable(owner, n.sons[0])
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
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.sons[1])
result = isAssignable(owner, n.sons[1], isUnsafeAddr)
elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
# 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:
result = arLValue
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(owner, n.sons[0])
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
of nkCallKinds:
# 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:
discard

View File

@@ -597,8 +597,8 @@ proc skipObjConv(n: PNode): PNode =
of nkObjUpConv, nkObjDownConv: result = n.sons[0]
else: result = n
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n)
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
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
of mAddr:
checkSonsLen(n, 2)
result = semAddr(c, n.sons[1])
result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr")
of mTypeOf:
checkSonsLen(n, 2)
result = semTypeOf(c, n.sons[1])

View File

@@ -10,10 +10,10 @@
# This include file implements the semantic checking for magics.
# 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)
let x = semExprWithType(c, n)
if isAssignable(c, x) notin {arLValue, arLocalLValue}:
if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
localError(n.info, errExprHasNoAddress)
result.add x
result.typ = makePtrType(c, x.typ)
@@ -119,7 +119,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
case n[0].sym.magic
of mAddr:
checkSonsLen(n, 2)
result = semAddr(c, n.sons[1])
result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
of mTypeOf:
checkSonsLen(n, 2)
result = semTypeOf(c, n.sons[1])

View File

@@ -217,4 +217,4 @@ General commit rules
3. Describe your commit and use your common sense.
.. include:: styleguide.rst
.. include:: docstyle.rst

View File

@@ -153,6 +153,13 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
## Cannot be overloaded.
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.} =
## Builtin 'type' operator for accessing the type of an expression.
## 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
==============
- ``unsafeAddr``
- document special cased varargs[untyped] and varargs[typed]
- The remaining bugs of the lambda lifting pass that is responsible to enable

View File

@@ -57,6 +57,11 @@ News
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
--------