* fixes #18550 * update the manual to reflect reality
This commit is contained in:
parent
58080525a1
commit
01fc9e58ca
9 changed files with 57 additions and 11 deletions
|
|
@ -32,6 +32,10 @@
|
||||||
echo a1.ord.B # produces no warning
|
echo a1.ord.B # produces no warning
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning.
|
||||||
|
This warning will become an error in future versions! Use an explicit conversion
|
||||||
|
like `cstring(x)` in order to silence the warning.
|
||||||
|
|
||||||
- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous
|
- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for previous
|
||||||
behavior.
|
behavior.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ type
|
||||||
warnCannotOpen = "CannotOpen",
|
warnCannotOpen = "CannotOpen",
|
||||||
warnFileChanged = "FileChanged",
|
warnFileChanged = "FileChanged",
|
||||||
warnSuspiciousEnumConv = "EnumConv",
|
warnSuspiciousEnumConv = "EnumConv",
|
||||||
|
warnCstringConv = "CStringConv",
|
||||||
warnUser = "User",
|
warnUser = "User",
|
||||||
# hints
|
# hints
|
||||||
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
hintSuccess = "Success", hintSuccessX = "SuccessX",
|
||||||
|
|
@ -155,6 +156,7 @@ const
|
||||||
warnCannotOpen: "cannot open: $1",
|
warnCannotOpen: "cannot open: $1",
|
||||||
warnFileChanged: "file changed: $1",
|
warnFileChanged: "file changed: $1",
|
||||||
warnSuspiciousEnumConv: "$1",
|
warnSuspiciousEnumConv: "$1",
|
||||||
|
warnCstringConv: "$1",
|
||||||
warnUser: "$1",
|
warnUser: "$1",
|
||||||
hintSuccess: "operation successful: $#",
|
hintSuccess: "operation successful: $#",
|
||||||
# keep in sync with `testament.isSuccess`
|
# keep in sync with `testament.isSuccess`
|
||||||
|
|
|
||||||
|
|
@ -951,6 +951,15 @@ proc trackInnerProc(tracked: PEffects, n: PNode) =
|
||||||
else:
|
else:
|
||||||
for ch in n: trackInnerProc(tracked, ch)
|
for ch in n: trackInnerProc(tracked, ch)
|
||||||
|
|
||||||
|
proc allowCStringConv(n: PNode): bool =
|
||||||
|
case n.kind
|
||||||
|
of nkStrLit..nkTripleStrLit: result = true
|
||||||
|
of nkSym: result = n.sym.kind in {skConst, skParam}
|
||||||
|
of nkAddr: result = isCharArrayPtr(n.typ, true)
|
||||||
|
of nkCallKinds:
|
||||||
|
result = isCharArrayPtr(n.typ, n[0].kind == nkSym and n[0].sym.magic == mAddr)
|
||||||
|
else: result = isCharArrayPtr(n.typ, false)
|
||||||
|
|
||||||
proc track(tracked: PEffects, n: PNode) =
|
proc track(tracked: PEffects, n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
|
@ -1157,6 +1166,13 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if tracked.owner.kind != skMacro:
|
if tracked.owner.kind != skMacro:
|
||||||
createTypeBoundOps(tracked, n.typ, n.info)
|
createTypeBoundOps(tracked, n.typ, n.info)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
|
if n.kind in {nkHiddenStdConv, nkHiddenSubConv} and
|
||||||
|
n.typ.skipTypes(abstractInst).kind == tyCstring and
|
||||||
|
not allowCStringConv(n[1]):
|
||||||
|
message(tracked.config, n.info, warnCstringConv,
|
||||||
|
"implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" %
|
||||||
|
[$n[1]])
|
||||||
|
|
||||||
if n.len == 2:
|
if n.len == 2:
|
||||||
track(tracked, n[1])
|
track(tracked, n[1])
|
||||||
if tracked.owner.kind != skMacro:
|
if tracked.owner.kind != skMacro:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ from hashes import Hash
|
||||||
import types
|
import types
|
||||||
|
|
||||||
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
|
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
|
||||||
proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1)
|
proc `&=`(c: var MD5Context, ch: char) =
|
||||||
|
# XXX suspicious code here; relies on ch being zero terminated?
|
||||||
|
md5Update(c, unsafeAddr ch, 1)
|
||||||
proc `&=`(c: var MD5Context, r: Rope) =
|
proc `&=`(c: var MD5Context, r: Rope) =
|
||||||
for l in leaves(r): md5Update(c, l, l.len)
|
for l in leaves(r): md5Update(c, l, l.len)
|
||||||
proc `&=`(c: var MD5Context, i: BiggestInt) =
|
proc `&=`(c: var MD5Context, i: BiggestInt) =
|
||||||
|
|
|
||||||
|
|
@ -1664,3 +1664,18 @@ proc lookupFieldAgain*(ty: PType; field: PSym): PSym =
|
||||||
if result != nil: break
|
if result != nil: break
|
||||||
ty = ty[0]
|
ty = ty[0]
|
||||||
if result == nil: result = field
|
if result == nil: result = field
|
||||||
|
|
||||||
|
proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
|
||||||
|
let t = t.skipTypes(abstractInst)
|
||||||
|
if t.kind == tyPtr:
|
||||||
|
let pointsTo = t[0].skipTypes(abstractInst)
|
||||||
|
case pointsTo.kind
|
||||||
|
of tyUncheckedArray:
|
||||||
|
result = pointsTo[0].kind == tyChar
|
||||||
|
of tyArray:
|
||||||
|
result = pointsTo[1].kind == tyChar and firstOrd(nil, pointsTo[0]) == 0 and
|
||||||
|
skipTypes(pointsTo[0], {tyRange}).kind in {tyInt..tyInt64}
|
||||||
|
of tyChar:
|
||||||
|
result = allowPointerToChar
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
|
||||||
|
|
@ -1380,10 +1380,9 @@ variadic proc, it is implicitly converted to `cstring` too:
|
||||||
|
|
||||||
Even though the conversion is implicit, it is not *safe*: The garbage collector
|
Even though the conversion is implicit, it is not *safe*: The garbage collector
|
||||||
does not consider a `cstring` to be a root and may collect the underlying
|
does not consider a `cstring` to be a root and may collect the underlying
|
||||||
memory. However, in practice, this almost never happens as the GC considers
|
memory. For this reason, the implicit conversion will be removed in future
|
||||||
stack roots conservatively. One can use the builtin procs `GC_ref` and
|
releases of the Nim compiler. Certain idioms like conversion of a `const` string
|
||||||
`GC_unref` to keep the string data alive for the rare cases where it does
|
to `cstring` are safe and will remain to be allowed.
|
||||||
not work.
|
|
||||||
|
|
||||||
A `$` proc is defined for cstrings that returns a string. Thus to get a nim
|
A `$` proc is defined for cstrings that returns a string. Thus to get a nim
|
||||||
string from a cstring:
|
string from a cstring:
|
||||||
|
|
|
||||||
|
|
@ -630,8 +630,8 @@ const
|
||||||
""
|
""
|
||||||
else:
|
else:
|
||||||
""
|
""
|
||||||
FormatOpen: array[FileMode, string] = [
|
FormatOpen: array[FileMode, cstring] = [
|
||||||
"rb" & NoInheritFlag, "wb" & NoInheritFlag, "w+b" & NoInheritFlag,
|
cstring("rb" & NoInheritFlag), "wb" & NoInheritFlag, "w+b" & NoInheritFlag,
|
||||||
"r+b" & NoInheritFlag, "ab" & NoInheritFlag
|
"r+b" & NoInheritFlag, "ab" & NoInheritFlag
|
||||||
]
|
]
|
||||||
#"rt", "wt", "w+t", "r+t", "at"
|
#"rt", "wt", "w+t", "r+t", "at"
|
||||||
|
|
@ -678,7 +678,7 @@ proc open*(f: var File, filename: string,
|
||||||
## This throws no exception if the file could not be opened.
|
## This throws no exception if the file could not be opened.
|
||||||
##
|
##
|
||||||
## The file handle associated with the resulting `File` is not inheritable.
|
## The file handle associated with the resulting `File` is not inheritable.
|
||||||
var p = fopen(filename, FormatOpen[mode])
|
var p = fopen(filename.cstring, FormatOpen[mode])
|
||||||
if p != nil:
|
if p != nil:
|
||||||
var f2 = cast[File](p)
|
var f2 = cast[File](p)
|
||||||
when defined(posix) and not defined(nimscript):
|
when defined(posix) and not defined(nimscript):
|
||||||
|
|
@ -711,7 +711,7 @@ proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
|
||||||
## Default mode is readonly. Returns true if the file could be reopened.
|
## Default mode is readonly. Returns true if the file could be reopened.
|
||||||
##
|
##
|
||||||
## The file handle associated with `f` won't be inheritable.
|
## The file handle associated with `f` won't be inheritable.
|
||||||
if freopen(filename, FormatOpen[mode], f) != nil:
|
if freopen(filename.cstring, FormatOpen[mode], f) != nil:
|
||||||
when not defined(nimInheritHandles) and declared(setInheritable) and
|
when not defined(nimInheritHandles) and declared(setInheritable) and
|
||||||
NoInheritFlag.len == 0:
|
NoInheritFlag.len == 0:
|
||||||
if not setInheritable(getOsFileHandle(f), false):
|
if not setInheritable(getOsFileHandle(f), false):
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ proc newWideCString*(s: cstring): WideCStringObj =
|
||||||
result = newWideCString(s, s.len)
|
result = newWideCString(s, s.len)
|
||||||
|
|
||||||
proc newWideCString*(s: string): WideCStringObj =
|
proc newWideCString*(s: string): WideCStringObj =
|
||||||
result = newWideCString(s, s.len)
|
result = newWideCString(cstring s, s.len)
|
||||||
|
|
||||||
proc `$`*(w: WideCString, estimate: int, replacement: int = 0xFFFD): string =
|
proc `$`*(w: WideCString, estimate: int, replacement: int = 0xFFFD): string =
|
||||||
result = newStringOfCap(estimate + estimate shr 2)
|
result = newStringOfCap(estimate + estimate shr 2)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
matrix: "--warningAsError:EnumConv"
|
matrix: "--warningAsError:EnumConv --warningAsError:CStringConv"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template reject(x) =
|
template reject(x) =
|
||||||
|
|
@ -84,3 +84,11 @@ block: # https://github.com/nim-lang/RFCs/issues/294
|
||||||
|
|
||||||
reject: Goo(k2)
|
reject: Goo(k2)
|
||||||
reject: k2.Goo
|
reject: k2.Goo
|
||||||
|
|
||||||
|
reject:
|
||||||
|
# bug #18550
|
||||||
|
proc f(c: char): cstring =
|
||||||
|
var x = newString(109*1024*1024)
|
||||||
|
x[0] = c
|
||||||
|
x
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue