diff options
30 files changed, 70 insertions, 67 deletions
diff --git a/changelog.md b/changelog.md index 4d27be3a0..9b74d6d9f 100644 --- a/changelog.md +++ b/changelog.md @@ -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 +becomes an alias for `addr`. + ## Standard library additions and changes - `macros.parseExpr` and `macros.parseStmt` now accept an optional diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index a8c5a3651..68a212794 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -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() diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 874098294..c7fc75620 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -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 = diff --git a/doc/manual.rst b/doc/manual.rst index 007b14b2d..4eabd0225 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -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 @@ -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 a deprecated alias for the `addr` operator: .. code-block:: nim - let myArray = [1, 2, 3] foreignProcThatTakesAnAddr(unsafeAddr myArray) - Procedures ========== diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index 10958c29a..407924a13 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -603,7 +603,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. diff --git a/lib/system.nim b/lib/system.nim index c424cbc1b..3b3e28344 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -190,8 +190,16 @@ when defined(nimHasDeclaredMagic): else: proc declaredInScope*(x: untyped): bool {.magic: "DefinedInScope", noSideEffect, compileTime.} -proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = +proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## Builtin `addr` operator for taking the address of a memory location. + ## + ## .. note:: This works for `let` variables or parameters + ## for better interop with C. When you use it to write a wrapper + ## for a C library and take the address of `let` variables or parameters, + ## you should always check that the original library + ## does never write to data behind the pointer that is returned from + ## this procedure. + ## ## Cannot be overloaded. ## ## See also: @@ -205,15 +213,17 @@ 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>`_. - ## - ## **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. + ## location. + ## + ## .. note:: This works for `let` variables or parameters + ## for better interop with C. When you use it to write a wrapper + ## for a C library and take the address of `let` variables or parameters, + ## you should always check that the original library + ## does never write to data behind the pointer that is returned from + ## this procedure. ## ## Cannot be overloaded. discard diff --git a/tests/arc/tcustomtrace.nim b/tests/arc/tcustomtrace.nim index 3977194d9..5e0ecfb24 100644 --- a/tests/arc/tcustomtrace.nim +++ b/tests/arc/tcustomtrace.nim @@ -130,7 +130,7 @@ proc createSeq*[T](elems: varargs[T]): myseq[T] = result.data = cast[type(result.data)](alloc0(result.cap * sizeof(T))) inc allocCount when supportsCopyMem(T): - copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + copyMem(result.data, addr(elems[0]), result.cap * sizeof(T)) else: for i in 0..<result.len: result.data[i] = elems[i] diff --git a/tests/arc/thard_alignment.nim b/tests/arc/thard_alignment.nim index e644572f0..baa964c77 100644 --- a/tests/arc/thard_alignment.nim +++ b/tests/arc/thard_alignment.nim @@ -18,7 +18,7 @@ type proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".} func `+`(a,b: m256d): m256d {.importc: "_mm256_add_pd", header: "immintrin.h".} proc `$`(a: m256d): string = - result = $(cast[ptr float](a.unsafeAddr)[]) + result = $(cast[ptr float](a.addr)[]) var res: seq[seq[m256d]] diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index fdb8d9597..77d03f8f6 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -234,7 +234,7 @@ when not defined(windows): if fd == -1: raiseOsError(osLastError()) let length = len(data).cint - if posix.write(fd, cast[pointer](unsafeAddr data[0]), + if posix.write(fd, cast[pointer](addr data[0]), len(data).cint) != length: raiseOsError(osLastError()) if posix.close(fd) == -1: diff --git a/tests/ccgbugs/tnoalias.nim b/tests/ccgbugs/tnoalias.nim index 0c6e84e44..f200992d7 100644 --- a/tests/ccgbugs/tnoalias.nim +++ b/tests/ccgbugs/tnoalias.nim @@ -7,7 +7,7 @@ type field {.noalias.}: ptr UncheckedArray[int] proc p(x {.noalias.}: openArray[char]) = - var q {.noalias.}: pointer = unsafeAddr(x[0]) + var q {.noalias.}: pointer = addr(x[0]) var bn: BigNum p "abc" diff --git a/tests/compiles/t8630.nim b/tests/compiles/t8630.nim index aa2be11cd..8b447d061 100644 --- a/tests/compiles/t8630.nim +++ b/tests/compiles/t8630.nim @@ -7,7 +7,7 @@ bar proc test(strings: seq[string]) = for s in strings: - var p3 = unsafeAddr(s) + var p3 = addr(s) echo p3[] test(@["foo", "bar"]) diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index 1a0dd8063..802582f57 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -484,10 +484,10 @@ type var address = pointer(nil) proc prod(r: var QuadraticExt, b: QuadraticExt) = if address == nil: - address = unsafeAddr b + address = addr b prod(r, b) else: - assert address == unsafeAddr b + assert address == addr b type Fp2[N: static int, T] {.byref.} = object diff --git a/tests/destructor/t12037.nim b/tests/destructor/t12037.nim index c2c41dfb5..30266690f 100644 --- a/tests/destructor/t12037.nim +++ b/tests/destructor/t12037.nim @@ -9,11 +9,11 @@ copy length and contents 1 @[42] proc test() = var sq1 = @[42] echo "showing original type, length, and contents ", sq1.typeof, " ", sq1.len, " ", sq1 - doAssert cast[int](sq1[0].unsafeAddr) != 0 + doAssert cast[int](sq1[0].addr) != 0 var sq2 = sq1 # copy of original echo "copy length and contents ", sq2.len, " ", sq2 - doAssert cast[int](sq2[0].unsafeAddr) != 0 - doAssert cast[int](sq1[0].unsafeAddr) != 0 + doAssert cast[int](sq2[0].addr) != 0 + doAssert cast[int](sq1[0].addr) != 0 test() diff --git a/tests/destructor/tarray_indexing.nim b/tests/destructor/tarray_indexing.nim index 657101c4d..a9dfdf4ed 100644 --- a/tests/destructor/tarray_indexing.nim +++ b/tests/destructor/tarray_indexing.nim @@ -63,7 +63,7 @@ proc fillPages*(mem: UserProcessMemory, start: uint32, data: seq[byte]) = #echo cast[uint64](addr mem.pageAccess[i]) let page = mem.pageAccess[i] assert page != nil - #copyMem(page, unsafeAddr data[i * 0x1000 - start], 0x1000) + #copyMem(page, addr data[i * 0x1000 - start], 0x1000) const base = 0x00100000 diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim index 4087dc4a8..17a19f871 100644 --- a/tests/destructor/tcustomseqs.nim +++ b/tests/destructor/tcustomseqs.nim @@ -121,7 +121,7 @@ proc createSeq*[T](elems: varargs[T]): myseq[T] = result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) inc allocCount when supportsCopyMem(T): - copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + copyMem(result.data, addr(elems[0]), result.cap * sizeof(T)) else: for i in 0..<result.len: result.data[i] = elems[i] diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim index 9ee2da33a..119bfec2c 100644 --- a/tests/destructor/tcustomstrings.nim +++ b/tests/destructor/tcustomstrings.nim @@ -75,7 +75,7 @@ proc add*(self: var mystring; y: mystring) = proc create*(lit: string): mystring = let newLen = lit.len ensure(result, newLen) - copyMem(addr result.data[result.len], unsafeAddr lit[0], newLen + 1) + copyMem(addr result.data[result.len], addr lit[0], newLen + 1) result.len = newLen proc `&`*(a, b: mystring): mystring = diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim index d2777bd97..e74c16da3 100644 --- a/tests/destructor/tuse_result_prevents_sinks.nim +++ b/tests/destructor/tuse_result_prevents_sinks.nim @@ -18,7 +18,7 @@ proc `=sink`(self: var Foo; other: Foo) = proc `=destroy`(self: var Foo) = discard template preventCursorInference(x) = - let p = unsafeAddr(x) + let p = addr(x) proc test(): Foo = result = Foo() diff --git a/tests/errmsgs/t10594.nim b/tests/errmsgs/t10594.nim index c9506c542..d27dd6433 100644 --- a/tests/errmsgs/t10594.nim +++ b/tests/errmsgs/t10594.nim @@ -3,5 +3,5 @@ discard """ line: 7 """ -template foo(v: varargs[int]) = unsafeAddr v +template foo(v: varargs[int]) = addr v foo(1, 2) diff --git a/tests/errmsgs/tnon_concrete_cast.nim b/tests/errmsgs/tnon_concrete_cast.nim index e4ae890ce..9e05c736c 100644 --- a/tests/errmsgs/tnon_concrete_cast.nim +++ b/tests/errmsgs/tnon_concrete_cast.nim @@ -34,7 +34,7 @@ proc write(rw: var MyReadWrite; value: SomeNumber): void = proc write[T](rw: var MyReadWrite; value: seq[T]): void = rw.write value.len let dst = cast[ptr SomeNumber](cast[uint](rw.memfile.mem) + uint(rw.offset)) - let src = cast[pointer](value[0].unsafeAddr) + let src = cast[pointer](value[0].addr) let size = sizeof(T) * value.len copyMem(dst, src, size) rw.offset += size diff --git a/tests/js/tfieldchecks.nim b/tests/js/tfieldchecks.nim index 3916cae74..a0679a349 100644 --- a/tests/js/tfieldchecks.nim +++ b/tests/js/tfieldchecks.nim @@ -30,7 +30,7 @@ block: block: let a0 = addr(obj.f0) echo a0[] - # let a1 = unsafeAddr(obj.f1) + # let a1 = addr(obj.f1) # echo a1[] doAssertRaises(FieldDefect): let a2 = addr(obj.f2) diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index e33da06f8..0787e36d9 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -22,12 +22,12 @@ template main2 = # bug #15958 let b = @[21,23] let ss = {1, 2, 3, 5} doAssert byLent(a) == [11,12] - doAssert byLent(a).unsafeAddr == a.unsafeAddr + doAssert byLent(a).addr == a.addr doAssert byLent(b) == @[21,23] when not defined(js): # pending bug #16073 - doAssert byLent(b).unsafeAddr == b.unsafeAddr + doAssert byLent(b).addr == b.addr doAssert byLent(ss) == {1, 2, 3, 5} - doAssert byLent(ss).unsafeAddr == ss.unsafeAddr + doAssert byLent(ss).addr == ss.addr let r = new(float) r[] = 10.0 @@ -41,9 +41,9 @@ template main2 = # bug #15958 proc byLent2[T](a: openArray[T]): lent T = a[0] doAssert byLent2(a) == 11 - doAssert byLent2(a).unsafeAddr == a[0].unsafeAddr + doAssert byLent2(a).addr == a[0].addr doAssert byLent2(b) == 21 - doAssert byLent2(b).unsafeAddr == b[0].unsafeAddr + doAssert byLent2(b).addr == b[0].addr proc byLent3[T](a: varargs[T]): lent T = a[1] let diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim index bac26896d..631c9f265 100644 --- a/tests/misc/taddr.nim +++ b/tests/misc/taddr.nim @@ -83,7 +83,7 @@ block: # bug #14576 # lots of these used to give: Error: internal error: genAddr: 2 proc byLent[T](a: T): lent T = a - proc byPtr[T](a: T): ptr T = a.unsafeAddr + proc byPtr[T](a: T): ptr T = a.addr block: let a = (10,11) diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim index a688e18cb..fe0dbf2bf 100644 --- a/tests/overload/t8829.nim +++ b/tests/overload/t8829.nim @@ -4,7 +4,7 @@ block: template `[]`[T](p: ptr T, span: Slice[int]): untyped = toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) - doAssert $cast[ptr uint8](txt[0].unsafeAddr)[0 ..< txt.len] == + doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" @@ -14,5 +14,5 @@ block: template `[]`[T](p: ptr T, span: Slice[int]): untyped = toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) - doAssert $cast[ptr uint8](txt[0].unsafeAddr)[0 ..< txt.len] == + doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim index 8209e8399..e830e8a22 100644 --- a/tests/overload/tstatic_with_converter.nim +++ b/tests/overload/tstatic_with_converter.nim @@ -42,7 +42,7 @@ proc `^`(x: vfloat, exp: static[float]): vfloat = pow(x, exp) proc `$`(x: vfloat): string = - let y = cast[ptr float](unsafeAddr x) + let y = cast[ptr float](addr x) # xxx not sure if intentional in this issue, but this returns "" echo y[] diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim index 53e070bee..c0d6f8a08 100644 --- a/tests/stdlib/tdecls.nim +++ b/tests/stdlib/tdecls.nim @@ -48,37 +48,37 @@ when false: # pending bug #13887 ## We can define custom pragmas in user code template byUnsafeAddr(lhs, typ, expr) = when typ is type(nil): - let tmp = unsafeAddr(expr) + let tmp = addr(expr) else: - let tmp: ptr typ = unsafeAddr(expr) + let tmp: ptr typ = addr(expr) template lhs: untyped = tmp[] block: let s = @["foo", "bar"] let a {.byUnsafeAddr.} = s[0] doAssert a == "foo" - doAssert a[0].unsafeAddr == s[0][0].unsafeAddr + doAssert a[0].addr == s[0][0].addr block: # nkAccQuoted # shows using a keyword, which requires nkAccQuoted template `cast`(lhs, typ, expr) = when typ is type(nil): - let tmp = unsafeAddr(expr) + let tmp = addr(expr) else: - let tmp: ptr typ = unsafeAddr(expr) + let tmp: ptr typ = addr(expr) template lhs: untyped = tmp[] block: let s = @["foo", "bar"] let a {.`byUnsafeAddr`.} = s[0] doAssert a == "foo" - doAssert a[0].unsafeAddr == s[0][0].unsafeAddr + doAssert a[0].addr == s[0][0].addr block: let s = @["foo", "bar"] let a {.`cast`.} = s[0] doAssert a == "foo" - doAssert a[0].unsafeAddr == s[0][0].unsafeAddr + doAssert a[0].addr == s[0][0].addr block: # bug #15920 template foo(lhs, typ, expr) = diff --git a/tests/stdlib/tmemory.nim b/tests/stdlib/tmemory.nim index 25b5d526a..0349ba035 100644 --- a/tests/stdlib/tmemory.nim +++ b/tests/stdlib/tmemory.nim @@ -12,4 +12,4 @@ block: # cmpMem doAssert cmpMem(a.addr, b.addr, sizeof(SomeHash)) > 0 doAssert cmpMem(b.addr, a.addr, sizeof(SomeHash)) < 0 - doAssert cmpMem(a.addr, c.unsafeAddr, sizeof(SomeHash)) == 0 + doAssert cmpMem(a.addr, c.addr, sizeof(SomeHash)) == 0 diff --git a/tests/stdlib/tsqlitebindatas.nim b/tests/stdlib/tsqlitebindatas.nim index 754c80ae1..b2c3247fa 100644 --- a/tests/stdlib/tsqlitebindatas.nim +++ b/tests/stdlib/tsqlitebindatas.nim @@ -27,7 +27,7 @@ block tsqlitebindatas: ## db_sqlite binary data db.exec(createTableStr) var dbuf = newSeq[byte](orig.len*sizeof(float64)) - copyMem(unsafeAddr(dbuf[0]), unsafeAddr(orig[0]), dbuf.len) + copyMem(addr(dbuf[0]), addr(orig[0]), dbuf.len) var insertStmt = db.prepare("INSERT INTO test (id, name, data) VALUES (?, ?, ?)") insertStmt.bindParams(1, origName, dbuf) @@ -42,7 +42,7 @@ block tsqlitebindatas: ## db_sqlite binary data var dataTest = db.getValue(sql"SELECT data FROM test WHERE id = ?", 1) let seqSize = int(dataTest.len*sizeof(byte)/sizeof(float64)) var res: seq[float64] = newSeq[float64](seqSize) - copyMem(unsafeAddr(res[0]), addr(dataTest[0]), dataTest.len) + copyMem(addr(res[0]), addr(dataTest[0]), dataTest.len) doAssert res.len == orig.len doAssert res == orig diff --git a/tests/strictnotnil/tnilcheck.nim b/tests/strictnotnil/tnilcheck.nim index 5b9292522..c2d009b70 100644 --- a/tests/strictnotnil/tnilcheck.nim +++ b/tests/strictnotnil/tnilcheck.nim @@ -194,7 +194,7 @@ proc testAliasChanging(a: Nilable) = # # proc testPtrAlias(a: Nilable) = # # # pointer to a: hm. # # # alias to a? -# # var ptrA = a.unsafeAddr # {0, 1} +# # var ptrA = a.addr # {0, 1} # # if not a.isNil: # {0, 1} # # ptrA[] = nil # {0, 1} 0: MaybeNil 1: MaybeNil # # echo a.a #[ tt.Warning diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index bdbaa2ce6..cae20865e 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -47,7 +47,7 @@ import strutils let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0'] doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\\x00']" -doAssert $cstring(unsafeAddr arr) == "Hello World!" +doAssert $cstring(addr arr) == "Hello World!" proc takes(c: cstring) = doAssert c == cstring"" diff --git a/tests/types/tlent_var.nim b/tests/types/tlent_var.nim index 491f6fde8..73b5bef9b 100644 --- a/tests/types/tlent_var.nim +++ b/tests/types/tlent_var.nim @@ -15,7 +15,7 @@ proc test_var(x: var MyObj): var int = var x = MyObj(a: 5) doAssert: test_var(x).addr == x.a.addr -doAssert: test_lent(x).unsafeAddr == x.a.addr +doAssert: test_lent(x).addr == x.a.addr proc varProc(x: var int) = x = 100 |