Skip to content

Commit

Permalink
conversions to unsigned numbers are not checked anymore (#12688) [bac…
Browse files Browse the repository at this point in the history
…kport]

* conversions to unsigned numbers are not checked anymore; implements / fixes nim-lang/RFCs#175

* change the spec yet again to be less consistent but to make more sense; updated the changelog

(cherry picked from commit c98e0e2)
  • Loading branch information
Araq authored and narimiran committed Nov 21, 2019
1 parent 7d444ff commit 4084ef1
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 6 deletions.
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

## Language changes

- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim
versions. The documentation was improved to acknowledge this special case.
See https://github.com/nim-lang/RFCs/issues/175 for more details.


### Tool changes
Expand Down
3 changes: 2 additions & 1 deletion compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1931,7 +1931,8 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
var a: TLoc
var dest = skipTypes(n.typ, abstractVar)
if optRangeCheck notin p.options:
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
checkUnsignedConversions notin p.config.legacyFeatures):
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
Expand Down
5 changes: 4 additions & 1 deletion compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2155,7 +2155,10 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
var a, b: TCompRes
gen(p, n.sons[0], r)
if optRangeCheck in p.options:
if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and
checkUnsignedConversions notin p.config.legacyFeatures):
discard "XXX maybe emit masking instructions here"
else:
gen(p, n.sons[1], a)
gen(p, n.sons[2], b)
useMagic(p, "chckRange")
Expand Down
4 changes: 4 additions & 0 deletions compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ type
## Allows to modify a NimNode where the type has already been
## flagged with nfSem. If you actually do this, it will cause
## bugs.
checkUnsignedConversions
## Historically and especially in version 1.0.0 of the language
## conversions to unsigned numbers were checked. In 1.0.4 they
## are not anymore.

SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf
Expand Down
6 changes: 2 additions & 4 deletions compiler/semfold.nim
Original file line number Diff line number Diff line change
Expand Up @@ -433,25 +433,23 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
let dstTyp = skipTypes(n.typ, abstractRange - {tyTypeDesc})
let srcTyp = skipTypes(a.typ, abstractRange - {tyTypeDesc})


# if srcTyp.kind == tyUInt64 and "FFFFFF" in $n:
# echo "n: ", n, " a: ", a
# echo "from: ", srcTyp, " to: ", dstTyp, " check: ", check
# echo getInt(a)
# echo high(int64)
# writeStackTrace()

# XXX range checks?
case dstTyp.kind
of tyInt..tyInt64, tyUInt..tyUInt64:
case srcTyp.kind
of tyFloat..tyFloat64:
result = newIntNodeT(BiggestInt(getFloat(a)), n, g)
of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
var val = a.getOrdValue

if check: rangeCheck(n, val, g)
result = newIntNodeT(val, n, g)
if dstTyp.kind in {tyUInt .. tyUInt64}:
if dstTyp.kind in {tyUInt..tyUInt64}:
result.kind = nkUIntLit
else:
result = a
Expand Down
14 changes: 14 additions & 0 deletions doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3185,6 +3185,7 @@ has lots of advantages:

Type conversions
----------------

Syntactically a `type conversion` is like a procedure call, but a
type name replaces the procedure name. A type conversion is always
safe in the sense that a failure to convert a type to another
Expand All @@ -3204,6 +3205,19 @@ A type conversion can also be used to disambiguate overloaded routines:
let procVar = (proc(x: string))(p)
procVar("a")
Since operations on unsigned numbers wrap around and are unchecked so are
type conversion to unsigned integers and between unsigned integers. The
rationale for this is mostly better interoperability with the C Programming
language when algorithms are ported from C to Nim.

Exception: Values that are converted to an unsigned type at compile time
are checked so that code like ``byte(-1)`` does not compile.

**Note**: Historically the operations
were unchecked and the conversions were sometimes checked but starting with
the revision 1.0.4 of this document and the language implementation the
conversions too are now *always unchecked*.


Type casts
----------
Expand Down

0 comments on commit 4084ef1

Please sign in to comment.