mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
Merge ../Nim into devel
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -217,4 +217,4 @@ General commit rules
|
||||
|
||||
3. Describe your commit and use your common sense.
|
||||
|
||||
.. include:: styleguide.rst
|
||||
.. include:: docstyle.rst
|
||||
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
==============
|
||||
|
||||
- ``unsafeAddr``
|
||||
- document special cased varargs[untyped] and varargs[typed]
|
||||
|
||||
- The remaining bugs of the lambda lifting pass that is responsible to enable
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
Reference in New Issue
Block a user