From f0e1eef65ed08fb153b88615f07ea0fd91e4c258 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 11 Aug 2024 19:10:04 +0800 Subject: [PATCH] fixes #14522 #22085 #12700 #23132; no range check for uints (#23930) fixes #14522 fixes #22085 fixes #12700 fixes #23132 closes https://github.com/nim-lang/Nim/pull/22343 (succeeded by this PR) completes https://github.com/nim-lang/RFCs/issues/175 follow up https://github.com/nim-lang/Nim/pull/12688 --- compiler/semexprs.nim | 3 ++- compiler/semfold.nim | 11 +++++++--- doc/manual.md | 3 --- tests/int/t1.nim | 25 +++++++++++++++++++++++ tests/range/tcompiletime_range_checks.nim | 4 ++-- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c1e74b457515..1c197c5e20e0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -270,7 +270,8 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = discard "convOk" elif targetTyp.isOrdinalType: if src.kind in nkCharLit..nkUInt64Lit and - src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp): + src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp) and + targetTyp.kind notin {tyUInt..tyUInt64}: result = convNotInRange elif src.kind in nkFloatLit..nkFloat64Lit and (classify(src.floatVal) in {fcNan, fcNegInf, fcInf} or diff --git a/compiler/semfold.nim b/compiler/semfold.nim index ca68bc2f3822..69aaf2e90199 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -420,14 +420,17 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P result = newIntNodeT(toInt128(getFloat(a)), n, idgen, g) of tyChar, tyUInt..tyUInt64, tyInt..tyInt64: var val = a.getOrdValue - if check: rangeCheck(n, val, g) - result = newIntNodeT(val, n, idgen, g) if dstTyp.kind in {tyUInt..tyUInt64}: + result = newIntNodeT(val, n, idgen, g) result.transitionIntKind(nkUIntLit) + else: + if check: rangeCheck(n, val, g) + result = newIntNodeT(val, n, idgen, g) else: result = a result.typ = n.typ - if check and result.kind in {nkCharLit..nkUInt64Lit}: + if check and result.kind in {nkCharLit..nkUInt64Lit} and + dstTyp.kind notin {tyUInt..tyUInt64}: rangeCheck(n, getInt(result), g) of tyFloat..tyFloat64: case srcTyp.kind @@ -747,6 +750,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode if leValueConv(n[1], a) and leValueConv(a, n[2]): result = a # a <= x and x <= b result.typ = n.typ + elif n.typ.kind in {tyUInt..tyUInt64}: + discard "don't check uints" else: localError(g.config, n.info, "conversion from $1 to $2 is invalid" % diff --git a/doc/manual.md b/doc/manual.md index e471658a490c..04574945009a 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -3788,9 +3788,6 @@ type conversions 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 diff --git a/tests/int/t1.nim b/tests/int/t1.nim index 36402da074f5..d08f5f29bf48 100644 --- a/tests/int/t1.nim +++ b/tests/int/t1.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c cpp" +""" + doAssert typeOf(1.int64 + 1.int) is int64 doAssert typeOf(1.uint64 + 1.uint) is uint64 doAssert int64 is SomeNumber @@ -12,3 +16,24 @@ doAssert typeOf(myInt16 + myInt) is int # of type `int` doAssert typeOf(myInt16 + 2i32) is int32 # of type `int32` doAssert int32 isnot int64 doAssert int32 isnot int + +block: + # bug #22085 + const + x = uint32(uint64.high) # vm error + u = uint64.high + v = uint32(u) # vm error + + let + z = uint64.high + y = uint32(z) # runtime ok + + let + w = uint32(uint64.high) # semfold error + + doAssert x == w + doAssert v == y + + # bug #14522 + doAssert 0xFF000000_00000000.uint64 == 18374686479671623680'u64 + diff --git a/tests/range/tcompiletime_range_checks.nim b/tests/range/tcompiletime_range_checks.nim index 29e2c48a8d4f..2d3f292ecf3e 100644 --- a/tests/range/tcompiletime_range_checks.nim +++ b/tests/range/tcompiletime_range_checks.nim @@ -1,8 +1,8 @@ discard """ cmd: "nim check --hint:Processing:off --hint:Conf:off $file" errormsg: "18446744073709551615 can't be converted to int8" - nimout: '''tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32 -tcompiletime_range_checks.nim(37, 23) Error: -1 can't be converted to uint64 + nimout: ''' +tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32 tcompiletime_range_checks.nim(38, 34) Error: 255 can't be converted to FullNegativeRange tcompiletime_range_checks.nim(39, 34) Error: 18446744073709551615 can't be converted to HalfNegativeRange tcompiletime_range_checks.nim(40, 34) Error: 300 can't be converted to FullPositiveRange