Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate unsafeAddr; extend addr #19373

Merged
merged 9 commits into from
Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
- `std/sharedstrings` module is removed.
- Constants `colors.colPaleVioletRed` and `colors.colMediumPurple` changed to match the CSS color standard.

- `addr` is now available for all addressable locations, `unsafeAddr` is deprecated and
become an alias for `addr`.
ringabout marked this conversation as resolved.
Show resolved Hide resolved

## Standard library additions and changes

- `macros.parseExpr` and `macros.parseStmt` now accept an optional
Expand Down
2 changes: 1 addition & 1 deletion compiler/isolation_check.nim
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ proc isValueOnlyType(t: PType): bool =

proc canAlias*(arg, ret: PType): bool =
if isValueOnlyType(arg):
# can alias only with unsafeAddr(arg.x) and we don't care if it is not safe
# can alias only with addr(arg.x) and we don't care if it is not safe
result = false
else:
var marker = initIntSet()
Expand Down
9 changes: 2 additions & 7 deletions compiler/semmagic.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@ proc semAddrArg(c: PContext; n: PNode; isUnsafeAddr = false): PNode =
let x = semExprWithType(c, n)
if x.kind == nkSym:
x.sym.flags.incl(sfAddrTaken)
if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
# Do not suggest the use of unsafeAddr if this expression already is a
# unsafeAddr
if isUnsafeAddr:
localError(c.config, n.info, errExprHasNoAddress)
else:
localError(c.config, n.info, errExprHasNoAddress & "; maybe use 'unsafeAddr'")
if isAssignable(c, x, true) notin {arLValue, arLocalLValue}:
localError(c.config, n.info, errExprHasNoAddress)
result = x

proc semTypeOf(c: PContext; n: PNode): PNode =
Expand Down
15 changes: 5 additions & 10 deletions doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3502,8 +3502,9 @@ location is `T`, the `addr` operator result is of the type `ptr T`. An
address is always an untraced reference. Taking the address of an object that
resides on the stack is **unsafe**, as the pointer may live longer than the
object on the stack and can thus reference a non-existing object. One can get
the address of variables, but one can't use it on variables declared through
`let` statements:
the address of variables. For easier interoperability with other compiled languages
such as C, retrieving the address of a `let` variable, a parameter,
or a `for` loop variable can be accomplished too:

.. code-block:: nim

Expand All @@ -3515,24 +3516,18 @@ the address of variables, but one can't use it on variables declared through
# --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello"
echo cast[ptr string](t3)[]
# --> Hello
# The following line doesn't compile:
# The following line also works
echo repr(addr(t1))
# Error: expression has no address


The unsafeAddr operator
-----------------------

For easier interoperability with other compiled languages such as C, retrieving
the address of a `let` variable, a parameter, or a `for` loop variable can
be accomplished by using the `unsafeAddr` operation:
The unsafeAddr operator is an alias for the addr operator and is deprecated:
ringabout marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: nim

let myArray = [1, 2, 3]
foreignProcThatTakesAnAddr(unsafeAddr myArray)


Procedures
==========

Expand Down
2 changes: 1 addition & 1 deletion doc/manual_experimental.rst
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ has `source` as the owner. A path expression `e` is defined recursively:
- Object field access `e.field` is a path expression.
- `system.toOpenArray(e, ...)` is a path expression.
- Pointer dereference `e[]` is a path expression.
- An address `addr e`, `unsafeAddr e` is a path expression.
- An address `addr e` is a path expression.
- A type conversion `T(e)` is a path expression.
- A cast expression `cast[T](e)` is a path expression.
- `f(e, ...)` is a path expression if `f`'s return type is a view type.
Expand Down
15 changes: 11 additions & 4 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ else:

proc `addr`*[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.
##
## .. note:: When you use it to write a wrapper for a C library, you should
## always check that the original library does never write to data behind the
## pointer that is returned from this procedure.
##
ringabout marked this conversation as resolved.
Show resolved Hide resolved
## Cannot be overloaded.
##
## See also:
Expand All @@ -205,13 +212,13 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
## echo p[] # b
discard

proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect,
deprecated: "'unsafeAddr' is a deprecated alias for 'addr'".} =
## 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 <#addr,T>`_.
## for better interop with C.
##
## **Note**: When you use it to write a wrapper for a C library, you should
## .. note:: When you use it to write a wrapper for a C library, you should
## always check that the original library does never write to data behind the
## pointer that is returned from this procedure.
##
Expand Down