Compare commits

..

11 Commits

Author SHA1 Message Date
Miran
78983f1876 update the changelog (#24213) 2024-10-01 22:22:30 +02:00
ringabout
0e1df88f7e check fileExists for outputFile (#24211)
ref
a5f46a72ba (commitcomment-147402726)
2024-10-01 08:11:07 +02:00
Miran
a5f46a72ba bump NimVersion to 2.2.0 (#24210) 2024-09-30 20:59:38 +02:00
ringabout
4974baf7fa fixes #24008; triggers a recompilation on output executables changes when switching release/debug modes (#24193)
fixes #24008

The old logic didn't check the contents of the output executables, when
it switched release->debug->release, it picked up the Json files used in
the first release building, the content of which didn't change. So it
mistook the executables which are built by the second debug building as
the functioning one.

`changeDetectedViaJsonBuildInstructions` needs a way to distinguish the
executables generated by different buildings.
2024-09-30 20:55:47 +02:00
metagn
b82ff5a87b make C++ atomic opt in via -d:nimUseCppAtomics (#24209)
refs #24207

The `-d:nimUseCAtomics` flag added in #24207 is now inverted and made
into `-d:nimUseCppAtomics`, which means C++ atomics are only enabled
with the define. This flag is now also documented and tested.
2024-09-30 20:54:07 +02:00
metagn
2a48182288 remove prev == nil requirement for typedesc params as type nodes (#24206)
fixes #24203

`semTypeNode` is called twice for RHS'es of type sections,
[here](b0e6d28782/compiler/semstmts.nim (L1612))
and
[here](b0e6d28782/compiler/semstmts.nim (L1646)).
Each time `prev` is `s.typ`, but the assertion expects `prev == nil`
which is false since `s.typ` is not nil the second time. To fix this,
the `prev == nil` part of the assertion is removed.

The reason this only happens for types like `seq[int]`, `(int, int)` etc
is because they don't have syms: `semTypeIdent` attempts to directly
[replace the typedesc param
itself](b0e6d28782/compiler/semtypes.nim (L1916))
with the sym of the base type of the resolved typedesc type if it
exists, which means `semTypeNode` doesn't receive the typedesc param sym
to perform the assert.
2024-09-30 17:34:49 +02:00
metagn
febc58e036 allow C atomics on C++ with -d:nimUseCAtomics (#24207)
refs https://github.com/nim-lang/Nim/pull/24200#issuecomment-2382501282

Workaround for C++ Atomic[T] issues that doesn't require a compiler
change. Not tested or documented in case it's not meant to be officially
supported, locally tested `tatomics` and #24159 to work with it though,
can add these as tests if required.
2024-09-30 17:34:09 +02:00
metagn
b0e6d28782 fix logic for dcEqIgnoreDistinct in sameType (#24197)
fixes #22523

There were 2 problems with the code in `sameType` for
`dcEqIgnoreDistinct`:

1. The code that skipped `{tyDistinct, tyGenericInst}` only ran if the
given types had different kinds. This is fixed by always performing this
skip.
2. The code block below that checks if `tyGenericInst`s have different
values still ran for `dcEqIgnoreDistinct` since it checks if the given
types are generic insts, not the skipped types (and also only the 1st
given type). This is fixed by only invoking this block for `dcEq`;
`dcEqOrDistinctOf` (which is unused) also skips the first given type.
Arguably there is another issue here that `skipGenericAlias` only ever
skips 1 type.

These combined fix the issue (`T` is `GenericInst(V, 1, distinct int)`
and `D[0]` is `GenericInst(D, 0, distinct int)`).

#24037 shouldn't be a dependency but the diff follows it.
2024-09-29 10:23:59 +02:00
metagn
7974a2208c fix cyclic node flag getting added to sink call [backport:2.0] (#24194)
Sorry I don't have a test case or issue for this. `injectdestructors` is
supposed to add a final bool argument to `=copy` and `=dup` to mark
cyclic types, as generated by `liftdestructors`. Hence this flag is
added after every call to `genCopy`, but `genCopy` can generate a
`=sink` call when passed the flag `IsExplicitSink` by `nkSinkAsgn`. This
creates a codegen error, saying the sink received an extra argument.
This is fixed by not adding the argument on the flag `IsExplicitSink`.

This is a followup to #20585 which is on the 2.0 branch, hence this is
marked backport.
2024-09-29 10:21:45 +02:00
metagn
7cbe031909 fix trivial segfault in sigmatch for static types (#24196)
refs #7382, caused by #24005
2024-09-29 10:20:38 +02:00
ringabout
4f5c0efaf2 fixes #24174; allow copyDir and copyDirWithPermissions skipping special files (#24190)
fixes  #24174
2024-09-27 16:36:31 +02:00
18 changed files with 383 additions and 275 deletions

View File

@@ -1,220 +1,18 @@
# v2.2.0 - yyyy-mm-dd
# v2.x.x - yyyy-mm-dd
## Changes affecting backward compatibility
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` is out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backward compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
```nim
var a, b: int
(a, b) = (1, 2, 3, 4)
```
will no longer compile.
- `internalNew` is removed from the `system` module, use `new` instead.
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
- JS backend now supports closure iterators.
- `owner` in `std/macros` is deprecated.
- Ambiguous type symbols in generic procs and templates now generate symchoice nodes.
Previously; in templates they would error immediately at the template definition,
and in generic procs a type symbol would arbitrarily be captured, losing the
information of the other symbols. This means that generic code can now give
errors for ambiguous type symbols, and macros operating on generic proc AST
may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.
- Partial generic instantiation of routines is no longer allowed. Previously
it compiled in niche situations due to bugs in the compiler.
```nim
proc foo[T, U](x: T, y: U) = echo (x, y)
proc foo[T, U](x: var T, y: U) = echo "var ", (x, y)
proc bar[T]() =
foo[float](1, "abc")
bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
```
- `const` values now open a new scope for each constant, meaning symbols
declared in them can no longer be used outside or in the value of
other constants.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
- The following POSIX wrappers have had their types changed from signed to
unsigned types on OSX and FreeBSD/OpenBSD to correct codegen errors:
- `Gid` (was `int32`, is now `uint32`)
- `Uid` (was `int32`, is now `uint32`)
- `Dev` (was `int32`, is now `uint32` on FreeBSD)
- `Nlink` (was `int16`, is now `uint32` on OpenBSD and `uint16` on OSX/other BSD)
- `sin6_flowinfo` and `sin6_scope_id` fields of `Sockaddr_in6`
(were `int32`, are now `uint32`)
- `n_net` field of `Tnetent` (was `int32`, is now `uint32`)
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow specifying `bufferSize` instead of a hard-coded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
[//]: # "Additions:"
- Added `newStringUninit` to the `system` module, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to the `system` module, which doesn't initialize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added `rangeBase` to `std/typetraits` to obtain the base type of a range type or
convert a value with a range type to its base type.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
- `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based
on Google's Farm Hash) which is also often faster than the present one. Define
`nimStringHash2` to get the old values back. `--jsbigint=off` mode always only
produces the old values. This may impact your automated tests if they depend
on hash order in some obvious or indirect way. Using `sorted` or `OrderedTable`
is often an easy workaround.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.html#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.
```nim
var a, c: int
(a, _, c) = (1, 2, 3)
```
- Tuple unpacking variable declarations now support type annotations, but
only for the entire tuple.
```nim
let (a, b): (int, int) = (1, 2)
let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
```
- The experimental option `--experimental:openSym` has been added to allow
captured symbols in generic routine and template bodies respectively to be
replaced by symbols injected locally by templates/macros at instantiation
time. `bind` may be used to keep the captured symbols over the injected ones
regardless of enabling the option, but other methods like renaming the
captured symbols should be used instead so that the code is not affected by
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo old[int]() # "captured"
template oldTempl(): string =
block:
foo(123):
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
template barTempl(): string =
block:
foo(123):
value
assert barTempl() == "injected" # previously it would be "captured"
template bazTempl(): string =
bind value
block:
foo(123):
value
assert bazTempl() == "captured"
```
This option also generates a new node kind `nnkOpenSym` which contains
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.

View File

@@ -1,12 +1,248 @@
# v2.2.0 - 2023-mm-dd
# v2.2.0 - 2024-10-02
## Changes affecting backward compatibility
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` is out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backward compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
```nim
var a, b: int
(a, b) = (1, 2, 3, 4)
```
will no longer compile.
- `internalNew` is removed from the `system` module, use `new` instead.
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
- JS backend now supports closure iterators.
- `owner` in `std/macros` is deprecated.
- Ambiguous type symbols in generic procs and templates now generate symchoice nodes.
Previously; in templates they would error immediately at the template definition,
and in generic procs a type symbol would arbitrarily be captured, losing the
information of the other symbols. This means that generic code can now give
errors for ambiguous type symbols, and macros operating on generic proc AST
may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.
- Partial generic instantiation of routines is no longer allowed. Previously
it compiled in niche situations due to bugs in the compiler.
```nim
proc foo[T, U](x: T, y: U) = echo (x, y)
proc foo[T, U](x: var T, y: U) = echo "var ", (x, y)
proc bar[T]() =
foo[float](1, "abc")
bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
```
- `const` values now open a new scope for each constant, meaning symbols
declared in them can no longer be used outside or in the value of
other constants.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
- The following POSIX wrappers have had their types changed from signed to
unsigned types on OSX and FreeBSD/OpenBSD to correct codegen errors:
- `Gid` (was `int32`, is now `uint32`)
- `Uid` (was `int32`, is now `uint32`)
- `Dev` (was `int32`, is now `uint32` on FreeBSD)
- `Nlink` (was `int16`, is now `uint32` on OpenBSD and `uint16` on OSX/other BSD)
- `sin6_flowinfo` and `sin6_scope_id` fields of `Sockaddr_in6`
(were `int32`, are now `uint32`)
- `n_net` field of `Tnetent` (was `int32`, is now `uint32`)
- The `Atomic[T]` type on C++ now uses C11 primitives by default instead of
`std::atomic`. To use `std::atomic` instead, `-d:nimUseCppAtomics` can be defined.
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow specifying `bufferSize` instead of a hard-coded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
- Changed `std/os.copyDir` and `copyDirWithPermissions` to allow skipping special "file" objects like FIFOs, device files, etc on Unix by specifying a `skipSpecial` parameter.
[//]: # "Additions:"
- Added `newStringUninit` to the `system` module, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to the `system` module, which doesn't initialize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added `rangeBase` to `std/typetraits` to obtain the base type of a range type or
convert a value with a range type to its base type.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
- `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based
on Google's Farm Hash) which is also often faster than the present one. Define
`nimStringHash2` to get the old values back. `--jsbigint=off` mode always only
produces the old values. This may impact your automated tests if they depend
on hash order in some obvious or indirect way. Using `sorted` or `OrderedTable`
is often an easy workaround.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.html#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.
```nim
var a, c: int
(a, _, c) = (1, 2, 3)
```
- Tuple unpacking variable declarations now support type annotations, but
only for the entire tuple.
```nim
let (a, b): (int, int) = (1, 2)
let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
```
- The experimental option `--experimental:openSym` has been added to allow
captured symbols in generic routine and template bodies respectively to be
replaced by symbols injected locally by templates/macros at instantiation
time. `bind` may be used to keep the captured symbols over the injected ones
regardless of enabling the option, but other methods like renaming the
captured symbols should be used instead so that the code is not affected by
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo old[int]() # "captured"
template oldTempl(): string =
block:
foo(123):
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
template barTempl(): string =
block:
foo(123):
value
assert barTempl() == "injected" # previously it would be "captured"
template bazTempl(): string =
bind value
block:
foo(123):
value
assert bazTempl() == "captured"
```
This option also generates a new node kind `nnkOpenSym` which contains
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package.

View File

@@ -1,4 +1,4 @@
# v1.xx.x - yyyy-mm-dd
# v2.xx.x - yyyy-mm-dd
This is an example file.
The changes should go to changelog.md!

View File

@@ -1000,11 +1000,11 @@ proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile =
# works out of the box with `hashMainCompilationParams`.
result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json")
const cacheVersion = "D20210525T193831" # update when `BuildCache` spec changes
const cacheVersion = "D20240927T193831" # update when `BuildCache` spec changes
type BuildCache = object
cacheVersion: string
outputFile: string
outputChecksum: string
outputLastModificationTime: string
compile: seq[(string, string)]
link: seq[string]
linkcmd: string
@@ -1048,7 +1048,8 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
bcache.depfiles.add (path, $secureHashFile(path))
bcache.nimexe = hashNimExe()
bcache.outputChecksum = $secureHashFile(bcache.outputFile)
if fileExists(bcache.outputFile):
bcache.outputLastModificationTime = $getLastModificationTime(bcache.outputFile)
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
@@ -1069,7 +1070,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
# xxx optimize by returning false if stdin input was the same
for (file, hash) in bcache.depfiles:
if $secureHashFile(file) != hash: return true
if bcache.outputChecksum != $secureHashFile(bcache.outputFile):
if bcache.outputLastModificationTime != $getLastModificationTime(bcache.outputFile):
return true
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =

View File

@@ -317,8 +317,9 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
]#
result = dest.kind != nkSym
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
# add cyclic flag, but not to sink calls, which IsExplicitSink generates
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
@@ -464,7 +465,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
var newCall = newTreeIT(nkCall, src.info, src.typ,
newSymNode(op),
src)
c.finishCopy(newCall, n, isFromSink = true)
c.finishCopy(newCall, n, {}, isFromSink = true)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newCall
@@ -473,7 +474,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
c.finishCopy(m, n, {}, isFromSink = true)
result.add m
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
message(c.graph.config, n.info, hintPerformance,
@@ -761,7 +762,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
let tmp = c.getTemp(s, n[0].typ, n.info)
var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn)
m.add p(n[0], c, s, normal)
c.finishCopy(m, n[0], isFromSink = false)
c.finishCopy(m, n[0], {}, isFromSink = false)
result = newTree(nkStmtList, c.genWasMoved(tmp), m)
var toDisarm = n[0]
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
@@ -1173,7 +1174,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkBracket:
# array constructor
if ri.len > 0 and isDangerousSeq(ri.typ):
@@ -1181,7 +1182,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
else:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
@@ -1202,7 +1203,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
@@ -1222,7 +1223,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
when false:
proc computeUninit(c: var Con) =

View File

@@ -300,8 +300,8 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
localError(g.config, n.info,
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
" Consider using a <ref T> which can be captured.") %
[s.name.s, typeToString(s.typ.skipTypes({tyVar})), g.config$s.info])
" Consider using a <ref $2> which can be captured.") %
[s.name.s, typeToString(s.typ), g.config$s.info])
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])

View File

@@ -2167,7 +2167,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind != skError: localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone
result = s.typ.base
elif prev == nil:
result = s.typ
@@ -2191,7 +2191,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind == skType:
s.typ
else:
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone
s.typ.base
let alias = maybeAliasType(c, t, prev)
if alias != nil:

View File

@@ -2012,7 +2012,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var r = tryResolvingStaticExpr(c, f.n)
if r == nil: r = f.n
if not exprStructuralEquivalent(r, aOrig.n) and
not (aOrig.n.kind == nkIntLit and
not (aOrig.n != nil and aOrig.n.kind == nkIntLit and
inferStaticParam(c, r, aOrig.n.intVal)):
result = isNone
elif f.base.kind == tyGenericParam:

View File

@@ -1250,18 +1250,18 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
b = skipTypes(b.last, aliasSkipSet)
assert(a != nil)
assert(b != nil)
if a.kind != b.kind:
case c.cmp
of dcEq: return false
of dcEqIgnoreDistinct:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
b = b.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
case c.cmp
of dcEq:
if a.kind != b.kind: return false
of dcEqIgnoreDistinct:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
b = b.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
#[
The following code should not run in the case either side is an generic alias,
@@ -1269,7 +1269,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
objects ie `type A[T] = SomeObject`
]#
# this is required by tunique_type but makes no sense really:
if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
if c.cmp == dcEq and x.kind == tyGenericInst and
IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
let
lhs = x.skipGenericAlias
rhs = y.skipGenericAlias

View File

@@ -10,6 +10,9 @@
## Types and operations for atomic operations and lockless algorithms.
##
## Unstable API.
##
## By default, C++ uses C11 atomic primitives. To use C++ `std::atomic`,
## `-d:nimUseCppAtomics` can be defined.
runnableExamples:
# Atomic
@@ -50,8 +53,7 @@ runnableExamples:
flag.clear(moRelaxed)
assert not flag.testAndSet
when defined(cpp) or defined(nimdoc):
when (defined(cpp) and defined(nimUseCppAtomics)) or defined(nimdoc):
# For the C++ backend, types and operations map directly to C++11 atomics.
{.push, header: "<atomic>".}
@@ -274,10 +276,17 @@ else:
cast[T](interlockedXor(addr(location.value), cast[nonAtomicType(T)](value)))
else:
{.push, header: "<stdatomic.h>".}
when defined(cpp):
{.push, header: "<atomic>".}
template maybeWrapStd(x: string): string =
"std::" & x
else:
{.push, header: "<stdatomic.h>".}
template maybeWrapStd(x: string): string =
x
type
MemoryOrder* {.importc: "memory_order".} = enum
MemoryOrder* {.importc: "memory_order".maybeWrapStd.} = enum
moRelaxed
moConsume
moAcquire
@@ -285,16 +294,25 @@ else:
moAcquireRelease
moSequentiallyConsistent
type
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
when defined(cpp):
type
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
AtomicInt8 {.importc: "_Atomic NI8".} = int8
AtomicInt16 {.importc: "_Atomic NI16".} = int16
AtomicInt32 {.importc: "_Atomic NI32".} = int32
AtomicInt64 {.importc: "_Atomic NI64".} = int64
AtomicInt8 {.importc: "std::atomic<NI8>".} = int8
AtomicInt16 {.importc: "std::atomic<NI16>".} = int16
AtomicInt32 {.importc: "std::atomic<NI32>".} = int32
AtomicInt64 {.importc: "std::atomic<NI64>".} = int64
else:
type
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
AtomicInt8 {.importc: "_Atomic NI8".} = int8
AtomicInt16 {.importc: "_Atomic NI16".} = int16
AtomicInt32 {.importc: "_Atomic NI32".} = int32
AtomicInt64 {.importc: "_Atomic NI64".} = int64
type
AtomicFlag* {.importc: "atomic_flag", size: 1.} = object
AtomicFlag* {.importc: "atomic_flag".maybeWrapStd, size: 1.} = object
Atomic*[T] = object
when T is Trivial:
@@ -308,27 +326,27 @@ else:
guard: AtomicFlag
#proc init*[T](location: var Atomic[T]; value: T): T {.importcpp: "atomic_init(@)".}
proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc.}
proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc.}
proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc: "atomic_load_explicit".maybeWrapStd.}
proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_store_explicit".maybeWrapStd.}
proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_exchange_explicit".maybeWrapStd.}
proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc: "atomic_compare_exchange_strong_explicit".maybeWrapStd.}
proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc: "atomic_compare_exchange_weak_explicit".maybeWrapStd.}
# Numerical operations
proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_add_explicit".maybeWrapStd.}
proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_sub_explicit".maybeWrapStd.}
proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_and_explicit".maybeWrapStd.}
proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_or_explicit".maybeWrapStd.}
proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_xor_explicit".maybeWrapStd.}
# Flag operations
# var ATOMIC_FLAG_INIT {.importc, nodecl.}: AtomicFlag
# proc init*(location: var AtomicFlag) {.inline.} = location = ATOMIC_FLAG_INIT
proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".}
proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".}
proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".maybeWrapStd.}
proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".maybeWrapStd.}
proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".}
proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".}
proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".maybeWrapStd.}
proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".maybeWrapStd.}
{.pop.}

View File

@@ -446,13 +446,17 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
else:
discard existsOrCreateDir(p)
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
proc copyDir*(source, dest: string, skipSpecial = false) {.rtl, extern: "nos$1",
tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
## Copies a directory from `source` to `dest`.
##
## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
## are skipped.
##
## If `skipSpecial` is true, then (besides all directories) only *regular*
## files (**without** special "file" objects like FIFOs, device files,
## etc) will be copied on Unix.
##
## If this fails, `OSError` is raised.
##
## On the Windows platform this proc will copy the attributes from
@@ -472,16 +476,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
## * `createDir proc`_
## * `moveDir proc`_
createDir(dest)
for kind, path in walkDir(source):
for kind, path in walkDir(source, skipSpecial = skipSpecial):
var noSource = splitPath(path).tail
if kind == pcDir:
copyDir(path, dest / noSource)
copyDir(path, dest / noSource, skipSpecial = skipSpecial)
else:
copyFile(path, dest / noSource, {cfSymlinkAsIs})
proc copyDirWithPermissions*(source, dest: string,
ignorePermissionErrors = true)
ignorePermissionErrors = true,
skipSpecial = false)
{.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect],
benign, noWeirdTarget.} =
## Copies a directory from `source` to `dest` preserving file permissions.
@@ -489,6 +494,10 @@ proc copyDirWithPermissions*(source, dest: string,
## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
## are skipped.
##
## If `skipSpecial` is true, then (besides all directories) only *regular*
## files (**without** special "file" objects like FIFOs, device files,
## etc) will be copied on Unix.
##
## If this fails, `OSError` is raised. This is a wrapper proc around
## `copyDir`_ and `copyFileWithPermissions`_ procs
## on non-Windows platforms.
@@ -518,10 +527,10 @@ proc copyDirWithPermissions*(source, dest: string,
except:
if not ignorePermissionErrors:
raise
for kind, path in walkDir(source):
for kind, path in walkDir(source, skipSpecial = skipSpecial):
var noSource = splitPath(path).tail
if kind == pcDir:
copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors)
copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors, skipSpecial = skipSpecial)
else:
copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs})

View File

@@ -240,7 +240,7 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}; bufferSize = 1
else:
# generic version of copyFile which works for any platform:
var d, s: File
if not open(s, source):raiseOSError(osLastError(), source)
if not open(s, source): raiseOSError(osLastError(), source)
if not open(d, dest, fmWrite):
close(s)
raiseOSError(osLastError(), dest)

View File

@@ -6,11 +6,11 @@ const
## ```
# see also std/private/since
NimMinor* {.intdefine.}: int = 1
NimMinor* {.intdefine.}: int = 2
## is the minor number of Nim's version.
## Odd for devel, even for releases.
NimPatch* {.intdefine.}: int = 99
NimPatch* {.intdefine.}: int = 0
## is the patch number of Nim's version.
## Odd for devel, even for releases.

View File

@@ -0,0 +1,21 @@
# issue #22523
from std/typetraits import distinctBase
type
V[p: static int] = distinct int
D[p: static int] = distinct int
T = V[1]
proc f(y: var T) = discard
var a: D[0]
static:
doAssert distinctBase(T) is distinctBase(D[0])
doAssert distinctBase(T) is int
doAssert distinctBase(D[0]) is int
doAssert T(a) is T
f(cast[ptr T](addr a)[])
f(T(a))

View File

@@ -157,3 +157,12 @@ block t3338:
var t2 = Bar[int32]()
t2.add()
doAssert t2.x == 5
block: # issue #24203
proc b(G: typedesc) =
type U = G
template s(h: untyped) = h
s(b(typeof (0, 0)))
b(seq[int])
b((int, int))
b(typeof (0, 0))

View File

@@ -1,5 +1,7 @@
discard """
matrix: "--mm:refc; --mm:orc"
# test C with -d:nimUseCppAtomics as well to check nothing breaks
matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
targets: "c cpp"
"""
# test atomic operations

View File

@@ -1,5 +1,6 @@
discard """
matrix: "--mm:refc; --mm:orc"
# test C with -d:nimUseCppAtomics as well to check nothing breaks
matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
targets: "c cpp"
"""
import std/atomics
@@ -17,4 +18,4 @@ block testSize: # issue 12726
f: AtomicFlag
static:
doAssert sizeof(Node) == sizeof(pointer)
doAssert sizeof(MyChannel) == sizeof(pointer) * 2
doAssert sizeof(MyChannel) == sizeof(pointer) * 2

View File

@@ -27,9 +27,8 @@ Raises
"""
# test os path creation, iteration, and deletion
import os, strutils, pathnorm
from stdtest/specialpaths import buildDir
import std/[syncio, assertions]
import std/[syncio, assertions, osproc, os, strutils, pathnorm]
block fileOperations:
let files = @["these.txt", "are.x", "testing.r", "files.q"]
@@ -161,6 +160,18 @@ block fileOperations:
# createDir should not fail if `dir` is empty
createDir("")
when defined(linux): # bug #24174
createDir("a/b")
open("a/file.txt", fmWrite).close
if not fileExists("a/fifoFile"):
doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0
copyDir("a/", "../dest/a/", skipSpecial = true)
copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true)
removeDir("a")
# Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
# `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
block: