From 2e93d83149fe99f75820b4fe6e78e09d145f726a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Sep 2026 00:17:04 +0800 Subject: [PATCH] fixes #26175; Utf16Char incorrectly declared as signed (#26181) fixes #26175 --- lib/std/widestrs.nim | 10 +++++----- tests/stdlib/twchartoutf8.nim | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/std/widestrs.nim b/lib/std/widestrs.nim index af9be00108..ca0407a8f4 100644 --- a/lib/std/widestrs.nim +++ b/lib/std/widestrs.nim @@ -13,7 +13,7 @@ # {.error: "You must not import this module explicitly".} type - Utf16Char* = distinct int16 + Utf16Char* = distinct uint16 when not (defined(cpu16) or defined(cpu8)): when defined(nimv2): @@ -78,10 +78,10 @@ when not (defined(cpu16) or defined(cpu8)): ## returns the length of a widestring. This traverses the whole string to ## find the binary zero end marker! result = 0 - while int16(w[result]) != 0'i16: inc result + while uint16(w[result]) != 0'u16: inc result const - UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16) + UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'u16) UNI_MAX_BMP = 0x0000FFFF UNI_MAX_UTF16 = 0x0010FFFF # UNI_MAX_UTF32 = 0x7FFFFFFF @@ -188,12 +188,12 @@ when not (defined(cpu16) or defined(cpu8)): iterator decodeUtf16(w: WideCString; replacement: int): int = ## Looks for a terminating NUL for length var i = 0 - while w[i].int16 != 0'i16: + while w[i].uint16 != 0'u16: var ch = ord(w[i]) inc i if ch >= UNI_SUR_HIGH_START and ch <= UNI_SUR_HIGH_END: # If the 16 bits following the high surrogate are NOT in the source... - if w[i].int16 == 0'i16: + if w[i].uint16 == 0'u16: ch = replacement #invalid UTF-16 else: let ch2 = ord(w[i]) diff --git a/tests/stdlib/twchartoutf8.nim b/tests/stdlib/twchartoutf8.nim index e437177ac3..0a5b8d0af5 100644 --- a/tests/stdlib/twchartoutf8.nim +++ b/tests/stdlib/twchartoutf8.nim @@ -3,7 +3,21 @@ discard """ output: '''OK''' """ -import std/[syncio, assertions] +import std/[syncio, assertions, widestrs] + +const + face = [Utf16Char(0xD83E), Utf16Char(0xDD2A)] + legacyHighSurrogate = -10178'i16 + +static: + doAssert sizeof(Utf16Char) == sizeof(int16) + doAssert alignof(Utf16Char) == alignof(int16) + doAssert uint16(cast[Utf16Char](legacyHighSurrogate)) == uint16(face[0]) + +proc testUtf16CodeUnits(chars: openArray[Utf16Char]) = + doAssert $chars == "🤪" + +testUtf16CodeUnits(face) #assume WideCharToMultiByte always produce correct result #windows only @@ -11,7 +25,6 @@ import std/[syncio, assertions] when not defined(windows): echo "OK" else: - import std/widestrs {.push gcsafe.} const CP_UTF8 = 65001'i32