From 3308d265816b342a842e7cabef492a54ea722e74 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 10 Oct 2017 00:17:20 +0200 Subject: [PATCH] breaking change: arrays of char do not convert to cstring; ptr to array of char does --- changelog.md | 3 +++ compiler/condsyms.nim | 1 + compiler/rodutils.nim | 11 ++++++++--- compiler/sigmatch.nim | 13 +++++++------ compiler/types.nim | 8 -------- lib/pure/nativesockets.nim | 14 ++++++++------ lib/pure/os.nim | 5 ++++- lib/pure/strutils.nim | 10 ++++++++-- lib/system/dyncalls.nim | 5 ++++- lib/system/excpt.nim | 8 ++++++-- lib/system/repr.nim | 11 ++++++++--- lib/system/sysstr.nim | 20 ++++++++++++++++---- 12 files changed, 73 insertions(+), 36 deletions(-) diff --git a/changelog.md b/changelog.md index 9f6a83a37e..22d763f538 100644 --- a/changelog.md +++ b/changelog.md @@ -5,3 +5,6 @@ - Removed basic2d/basic3d out of the stdlib and into Nimble packages. These packages deprecated however, use the ``glm``, ``arraymancer``, ``neo`` or another package. +- Arrays of char cannot be converted to ``cstring`` anymore, pointers to + arrays of char can! This means ``$`` for arrays can finally exist + in ``system.nim`` and do the right thing. diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 9863e90bb5..02c31163ae 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -108,3 +108,4 @@ proc initDefines*() = defineSymbol("nimHasCppDefine") defineSymbol("nimGenericInOutFlags") when false: defineSymbol("nimHasOpt") + defineSymbol("nimNoArrayToCstringConversion") diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 6e77e6b8f9..0456e93490 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -21,9 +21,14 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = if f > 0.0: result = "INF" else: result = "-INF" else: - var buf: array[0..80, char] - discard c_snprintf(buf.cstring, buf.len.uint, "%#.16e%s", f, literalPostfix.cstring) - result = $buf.cstring + when defined(nimNoArrayToCstringConversion): + result = newString(81) + let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring) + setLen(result, n) + else: + var buf: array[0..80, char] + discard c_snprintf(buf.cstring, buf.len.uint, "%#.16e%s", f, literalPostfix.cstring) + result = $buf.cstring proc encodeStr*(s: string, result: var string) = for i in countup(0, len(s) - 1): diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index f2bc243990..50d4178b6c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1288,12 +1288,13 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, of tyString: result = isConvertible of tyPtr: # ptr[Tag, char] is not convertible to 'cstring' for now: - if a.len == 1 and a.sons[0].kind == tyChar: result = isConvertible - of tyArray: - if (firstOrd(a.sons[0]) == 0) and - (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and - (a.sons[1].kind == tyChar): - result = isConvertible + if a.len == 1: + let pointsTo = a.sons[0].skipTypes(abstractInst) + if pointsTo.kind == tyChar: result = isConvertible + elif pointsTo.kind == tyArray and firstOrd(pointsTo.sons[0]) == 0 and + skipTypes(pointsTo.sons[0], {tyRange}).kind in {tyInt..tyInt64} and + pointsTo.sons[1].kind == tyChar: + result = isConvertible else: discard of tyEmpty, tyVoid: diff --git a/compiler/types.nim b/compiler/types.nim index 3dbf6fd180..f32b0da187 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -667,14 +667,6 @@ proc lengthOrd*(t: PType): BiggestInt = else: result = lastOrd(t) - firstOrd(t) + 1 -proc isCompatibleToCString*(a: PType): bool = - if a.kind == tyArray: - if (firstOrd(a.sons[0]) == 0) and - (skipTypes(a.sons[0], {tyRange, tyGenericInst, tyAlias}).kind in - {tyInt..tyInt64, tyUInt..tyUInt64}) and - (a.sons[1].kind == tyChar): - result = true - # -------------- type equality ----------------------------------------------- type diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index c8fb041d80..6c8701843e 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -496,11 +496,12 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) = addr(namelen)) == -1'i32: raiseOSError(osLastError()) # Cannot use INET6_ADDRSTRLEN here, because it's a C define. - var buf: array[64, char] + result[0] = newString(64) if inet_ntop(name.sin6_family.cint, - addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil: + addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: raiseOSError(osLastError()) - result = ($buf.cstring, Port(nativesockets.ntohs(name.sin6_port))) + setLen(result[0], result[0].cstring.len) + result[1] = Port(nativesockets.ntohs(name.sin6_port)) else: raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") @@ -532,11 +533,12 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) = addr(namelen)) == -1'i32: raiseOSError(osLastError()) # Cannot use INET6_ADDRSTRLEN here, because it's a C define. - var buf: array[64, char] + result[0] = newString(64) if inet_ntop(name.sin6_family.cint, - addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil: + addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil: raiseOSError(osLastError()) - result = ($buf.cstring, Port(nativesockets.ntohs(name.sin6_port))) + setLen(result[0], result[0].cstring.len) + result[1] = Port(nativesockets.ntohs(name.sin6_port)) else: raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e6ef96ba3b..a1ae4e250e 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -790,7 +790,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: while true: var x = readdir(d) if x == nil: break - var y = $x.d_name.cstring + when defined(nimNoArrayToCstringConversion): + var y = $cstring(addr x.d_name) + else: + var y = $x.d_name.cstring if y != "." and y != "..": var s: Stat if not relative: diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 910d09afd0..cc0f474f47 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1890,11 +1890,17 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, frmtstr[3] = '*' frmtstr[4] = floatFormatToChar[format] frmtstr[5] = '\0' - L = c_sprintf(buf, frmtstr, precision, f) + when defined(nimNoArrayToCstringConversion): + L = c_sprintf(addr buf, addr frmtstr, precision, f) + else: + L = c_sprintf(buf, frmtstr, precision, f) else: frmtstr[1] = floatFormatToChar[format] frmtstr[2] = '\0' - L = c_sprintf(buf, frmtstr, f) + when defined(nimNoArrayToCstringConversion): + L = c_sprintf(addr buf, addr frmtstr, f) + else: + L = c_sprintf(buf, frmtstr, f) result = newString(L) for i in 0 ..< L: # Depending on the locale either dot or comma is produced, diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index 2b86ddf258..c8e251d1e6 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -142,7 +142,10 @@ elif defined(windows) or defined(dos): dec(m) k = k div 10 if k == 0: break - result = getProcAddress(cast[THINSTANCE](lib), decorated) + when defined(nimNoArrayToCstringConversion): + result = getProcAddress(cast[THINSTANCE](lib), addr decorated) + else: + result = getProcAddress(cast[THINSTANCE](lib), decorated) if result != nil: return procAddrError(name) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index cee4e33a56..950981227c 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -289,8 +289,12 @@ proc raiseExceptionAux(e: ref Exception) = add(buf, " [") xadd(buf, e.name, e.name.len) add(buf, "]\n") - unhandled(buf): - showErrorMessage(buf) + when defined(nimNoArrayToCstringConversion): + template tbuf(): untyped = addr buf + else: + template tbuf(): untyped = buf + unhandled(tbuf()): + showErrorMessage(tbuf()) quitOrDebug() proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 58c86b0dbe..19fa564fb0 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -16,9 +16,14 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x proc reprFloat(x: float): string {.compilerproc.} = return $x proc reprPointer(x: pointer): string {.compilerproc.} = - var buf: array[60, char] - discard c_sprintf(buf.cstring, "%p", x) - result = $buf.cstring + when defined(nimNoArrayToCstringConversion): + result = newString(60) + let n = c_sprintf(addr result[0], "%p", x) + setLen(result, n) + else: + var buf: array[0..59, char] + discard c_sprintf(buf, "%p", x) + return $buf proc `$`(x: uint64): string = if x == 0: diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 90201202c1..43b5a02929 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -24,7 +24,10 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} = if a == b: return 0 if a == nil: return -1 if b == nil: return 1 - return c_strcmp(a.data, b.data) + when defined(nimNoArrayToCstringConversion): + return c_strcmp(addr a.data, addr b.data) + else: + return c_strcmp(a.data, b.data) proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = if a == b: return true @@ -320,7 +323,10 @@ proc nimIntToStr(x: int): string {.compilerRtl.} = proc add*(result: var string; x: float) = var buf: array[0..64, char] - var n: int = c_sprintf(buf, "%.16g", x) + when defined(nimNoArrayToCstringConversion): + var n: int = c_sprintf(addr buf, "%.16g", x) + else: + var n: int = c_sprintf(buf, "%.16g", x) var hasDot = false for i in 0..n-1: if buf[i] == ',': @@ -342,7 +348,10 @@ proc add*(result: var string; x: float) = else: result.add "inf" else: - result.add buf + var i = 0 + while buf[i] != '\0': + result.add buf[i] + inc i proc nimFloatToStr(f: float): string {.compilerproc.} = result = newStringOfCap(8) @@ -507,7 +516,10 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 t[ti-3] = ('0'.ord + abs_exponent mod 10).char - number = c_strtod(t, nil) + when defined(nimNoArrayToCstringConversion): + number = c_strtod(addr t, nil) + else: + number = c_strtod(t, nil) proc nimInt64ToStr(x: int64): string {.compilerRtl.} = result = newStringOfCap(sizeof(x)*4)