Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
commit
b9dc486db1
9 changed files with 152 additions and 73 deletions
|
|
@ -121,7 +121,8 @@ type
|
||||||
notnil,
|
notnil,
|
||||||
dynamicBindSym,
|
dynamicBindSym,
|
||||||
forLoopMacros,
|
forLoopMacros,
|
||||||
caseStmtMacros
|
caseStmtMacros,
|
||||||
|
codeReordering,
|
||||||
|
|
||||||
SymbolFilesOption* = enum
|
SymbolFilesOption* = enum
|
||||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||||
|
|
|
||||||
|
|
@ -231,8 +231,17 @@ proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
|
||||||
else: resOptions = resOptions - op
|
else: resOptions = resOptions - op
|
||||||
|
|
||||||
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
|
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
|
||||||
if isTurnedOn(c, n): incl(c.module.flags, flag)
|
if isTurnedOn(c, n):
|
||||||
else: excl(c.module.flags, flag)
|
incl(c.module.flags, flag)
|
||||||
|
c.features.incl codeReordering
|
||||||
|
else:
|
||||||
|
excl(c.module.flags, flag)
|
||||||
|
# c.features.excl codeReordering
|
||||||
|
|
||||||
|
# deprecated as of 0.18.1
|
||||||
|
message(c.config, n.info, warnDeprecated,
|
||||||
|
"use {.experimental: \"codeReordering.\".} instead; " &
|
||||||
|
(if flag == sfNoForward: "{.noForward.}" else: "{.reorder.}"))
|
||||||
|
|
||||||
proc processCallConv(c: PContext, n: PNode) =
|
proc processCallConv(c: PContext, n: PNode) =
|
||||||
if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
|
if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
|
||||||
|
|
@ -351,7 +360,13 @@ proc processExperimental(c: PContext; n: PNode) =
|
||||||
case n[1].kind
|
case n[1].kind
|
||||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||||
try:
|
try:
|
||||||
c.features.incl parseEnum[Feature](n[1].strVal)
|
let feature = parseEnum[Feature](n[1].strVal)
|
||||||
|
c.features.incl feature
|
||||||
|
if feature == codeReordering:
|
||||||
|
if not isTopLevel(c):
|
||||||
|
localError(c.config, n.info,
|
||||||
|
"Code reordering experimental pragma only valid at toplevel")
|
||||||
|
c.module.flags.incl sfReorder
|
||||||
except ValueError:
|
except ValueError:
|
||||||
localError(c.config, n[1].info, "unknown experimental feature")
|
localError(c.config, n[1].info, "unknown experimental feature")
|
||||||
else:
|
else:
|
||||||
|
|
@ -817,7 +832,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
incl(sym.flags, {sfThread, sfGlobal})
|
incl(sym.flags, {sfThread, sfGlobal})
|
||||||
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
|
of wDeadCodeElimUnused: discard # deprecated, dead code elim always on
|
||||||
of wNoForward: pragmaNoForward(c, it)
|
of wNoForward: pragmaNoForward(c, it)
|
||||||
of wReorder: pragmaNoForward(c, it, sfReorder)
|
of wReorder: pragmaNoForward(c, it, flag = sfReorder)
|
||||||
of wMagic: processMagic(c, it, sym)
|
of wMagic: processMagic(c, it, sym)
|
||||||
of wCompileTime:
|
of wCompileTime:
|
||||||
noVal(c, it)
|
noVal(c, it)
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ else:
|
||||||
toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
|
toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
|
||||||
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) = md5Update(c, unsafeAddr ch, 1)
|
||||||
|
proc `&=`(c: var MD5Context, r: Rope) =
|
||||||
|
for l in leaves(r): md5Update(c, l, l.len)
|
||||||
proc `&=`(c: var MD5Context, i: BiggestInt) =
|
proc `&=`(c: var MD5Context, i: BiggestInt) =
|
||||||
md5Update(c, cast[cstring](unsafeAddr i), sizeof(i))
|
md5Update(c, cast[cstring](unsafeAddr i), sizeof(i))
|
||||||
|
|
||||||
|
|
@ -185,11 +187,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||||
# Every cyclic type in Nim need to be constructed via some 't.sym', so this
|
# Every cyclic type in Nim need to be constructed via some 't.sym', so this
|
||||||
# is actually safe without an infinite recursion check:
|
# is actually safe without an infinite recursion check:
|
||||||
if t.sym != nil:
|
if t.sym != nil:
|
||||||
#if "Future:" in t.sym.name.s and t.typeInst == nil:
|
if {sfCompilerProc} * t.sym.flags != {}:
|
||||||
# writeStackTrace()
|
doAssert t.sym.loc.r != nil
|
||||||
# echo "yes ", t.sym.name.s
|
# The user has set a specific name for this type
|
||||||
# #quit 1
|
c &= t.sym.loc.r
|
||||||
if CoOwnerSig in flags:
|
elif CoOwnerSig in flags:
|
||||||
c.hashTypeSym(t.sym)
|
c.hashTypeSym(t.sym)
|
||||||
else:
|
else:
|
||||||
c.hashSym(t.sym)
|
c.hashSym(t.sym)
|
||||||
|
|
|
||||||
154
doc/manual.rst
154
doc/manual.rst
|
|
@ -6534,6 +6534,111 @@ iterator in which case the overloading resolution takes place:
|
||||||
var x = 4
|
var x = 4
|
||||||
write(stdout, x) # not ambiguous: uses the module C's x
|
write(stdout, x) # not ambiguous: uses the module C's x
|
||||||
|
|
||||||
|
Code reordering
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
**Note**: Code reordering is experimental and must be enabled via the
|
||||||
|
``{.experimental.}`` pragma.
|
||||||
|
|
||||||
|
The code reordering feature can implicitly rearrange procedure, template, and
|
||||||
|
macro definitions along with variable declarations and initializations at the top
|
||||||
|
level scope so that, to a large extent, a programmer should not have to worry
|
||||||
|
about ordering definitions correctly or be forced to use forward declarations to
|
||||||
|
preface definitions inside a module.
|
||||||
|
|
||||||
|
..
|
||||||
|
NOTE: The following was documentation for the code reordering precursor,
|
||||||
|
which was {.noForward.}.
|
||||||
|
|
||||||
|
In this mode, procedure definitions may appear out of order and the compiler
|
||||||
|
will postpone their semantic analysis and compilation until it actually needs
|
||||||
|
to generate code using the definitions. In this regard, this mode is similar
|
||||||
|
to the modus operandi of dynamic scripting languages, where the function
|
||||||
|
calls are not resolved until the code is executed. Here is the detailed
|
||||||
|
algorithm taken by the compiler:
|
||||||
|
|
||||||
|
1. When a callable symbol is first encountered, the compiler will only note
|
||||||
|
the symbol callable name and it will add it to the appropriate overload set
|
||||||
|
in the current scope. At this step, it won't try to resolve any of the type
|
||||||
|
expressions used in the signature of the symbol (so they can refer to other
|
||||||
|
not yet defined symbols).
|
||||||
|
|
||||||
|
2. When a top level call is encountered (usually at the very end of the
|
||||||
|
module), the compiler will try to determine the actual types of all of the
|
||||||
|
symbols in the matching overload set. This is a potentially recursive process
|
||||||
|
as the signatures of the symbols may include other call expressions, whose
|
||||||
|
types will be resolved at this point too.
|
||||||
|
|
||||||
|
3. Finally, after the best overload is picked, the compiler will start
|
||||||
|
compiling the body of the respective symbol. This in turn will lead the
|
||||||
|
compiler to discover more call expressions that need to be resolved and steps
|
||||||
|
2 and 3 will be repeated as necessary.
|
||||||
|
|
||||||
|
Please note that if a callable symbol is never used in this scenario, its
|
||||||
|
body will never be compiled. This is the default behavior leading to best
|
||||||
|
compilation times, but if exhaustive compilation of all definitions is
|
||||||
|
required, using ``nim check`` provides this option as well.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc foo(x: int) =
|
||||||
|
bar(x)
|
||||||
|
|
||||||
|
proc bar(x: int) =
|
||||||
|
echo(x)
|
||||||
|
|
||||||
|
foo(10)
|
||||||
|
|
||||||
|
Variables can also be reordered as well. Variables that are *initialized* (i.e.
|
||||||
|
variables that have their declaration and assignment combined in a single
|
||||||
|
statement) can have their entire initialization statement reordered. Be wary of
|
||||||
|
what code is executed at the top level:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc a() =
|
||||||
|
echo(foo)
|
||||||
|
|
||||||
|
var foo = 5
|
||||||
|
|
||||||
|
a() # outputs: "5"
|
||||||
|
|
||||||
|
..
|
||||||
|
TODO: Let's table this for now. This is an *experimental feature* and so the
|
||||||
|
specific manner in which ``declared`` operates with it can be decided in
|
||||||
|
eventuality, because right now it works a bit weirdly.
|
||||||
|
|
||||||
|
The values of expressions involving ``declared`` are decided *before* the
|
||||||
|
code reordering process, and not after. As an example, the output of this
|
||||||
|
code is the same as it would be with code reordering disabled.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc x() =
|
||||||
|
echo(declared(foo))
|
||||||
|
|
||||||
|
var foo = 4
|
||||||
|
|
||||||
|
x() # "false"
|
||||||
|
|
||||||
|
It is important to note that reordering *only* works for symbols at top level
|
||||||
|
scope. Therefore, the following will *fail to compile:*
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
|
proc a() =
|
||||||
|
b()
|
||||||
|
proc b() =
|
||||||
|
echo("Hello!")
|
||||||
|
|
||||||
|
a()
|
||||||
|
|
||||||
Compiler Messages
|
Compiler Messages
|
||||||
=================
|
=================
|
||||||
|
|
@ -6943,55 +7048,6 @@ the created global variables within a module is not defined, but all of them
|
||||||
will be initialized after any top-level variables in their originating module
|
will be initialized after any top-level variables in their originating module
|
||||||
and before any variable in a module that imports it.
|
and before any variable in a module that imports it.
|
||||||
|
|
||||||
|
|
||||||
..
|
|
||||||
NoForward pragma
|
|
||||||
----------------
|
|
||||||
The ``noforward`` pragma can be used to turn on and off a special compilation
|
|
||||||
mode that to large extent eliminates the need for forward declarations. In this
|
|
||||||
mode, the proc definitions may appear out of order and the compiler will postpone
|
|
||||||
their semantic analysis and compilation until it actually needs to generate code
|
|
||||||
using the definitions. In this regard, this mode is similar to the modus operandi
|
|
||||||
of dynamic scripting languages, where the function calls are not resolved until
|
|
||||||
the code is executed. Here is the detailed algorithm taken by the compiler:
|
|
||||||
|
|
||||||
1. When a callable symbol is first encountered, the compiler will only note the
|
|
||||||
symbol callable name and it will add it to the appropriate overload set in the
|
|
||||||
current scope. At this step, it won't try to resolve any of the type expressions
|
|
||||||
used in the signature of the symbol (so they can refer to other not yet defined
|
|
||||||
symbols).
|
|
||||||
|
|
||||||
2. When a top level call is encountered (usually at the very end of the module),
|
|
||||||
the compiler will try to determine the actual types of all of the symbols in the
|
|
||||||
matching overload set. This is a potentially recursive process as the signatures
|
|
||||||
of the symbols may include other call expressions, whose types will be resolved
|
|
||||||
at this point too.
|
|
||||||
|
|
||||||
3. Finally, after the best overload is picked, the compiler will start
|
|
||||||
compiling the body of the respective symbol. This in turn will lead the
|
|
||||||
compiler to discover more call expressions that need to be resolved and steps
|
|
||||||
2 and 3 will be repeated as necessary.
|
|
||||||
|
|
||||||
Please note that if a callable symbol is never used in this scenario, its body
|
|
||||||
will never be compiled. This is the default behavior leading to best compilation
|
|
||||||
times, but if exhaustive compilation of all definitions is required, using
|
|
||||||
``nim check`` provides this option as well.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
{.noforward: on.}
|
|
||||||
|
|
||||||
proc foo(x: int) =
|
|
||||||
bar x
|
|
||||||
|
|
||||||
proc bar(x: int) =
|
|
||||||
echo x
|
|
||||||
|
|
||||||
foo(10)
|
|
||||||
|
|
||||||
|
|
||||||
pragma pragma
|
pragma pragma
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,6 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
when declared(ThisIsSystem):
|
|
||||||
# we are in system module:
|
|
||||||
{.pragma: codegenType, compilerproc.}
|
|
||||||
else:
|
|
||||||
{.pragma: codegenType.}
|
|
||||||
|
|
||||||
type
|
type
|
||||||
# This should be the same as ast.TTypeKind
|
# This should be the same as ast.TTypeKind
|
||||||
# many enum fields are not used at runtime
|
# many enum fields are not used at runtime
|
||||||
|
|
@ -79,7 +73,7 @@ type
|
||||||
tyVoidHidden
|
tyVoidHidden
|
||||||
|
|
||||||
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||||
TNimNode {.codegenType.} = object
|
TNimNode {.compilerProc.} = object
|
||||||
kind: TNimNodeKind
|
kind: TNimNodeKind
|
||||||
offset: int
|
offset: int
|
||||||
typ: ptr TNimType
|
typ: ptr TNimType
|
||||||
|
|
@ -92,7 +86,7 @@ type
|
||||||
ntfAcyclic = 1, # type cannot form a cycle
|
ntfAcyclic = 1, # type cannot form a cycle
|
||||||
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
||||||
# version
|
# version
|
||||||
TNimType {.codegenType.} = object
|
TNimType {.compilerProc.} = object
|
||||||
size: int
|
size: int
|
||||||
kind: TNimKind
|
kind: TNimKind
|
||||||
flags: set[TNimTypeFlag]
|
flags: set[TNimTypeFlag]
|
||||||
|
|
@ -109,6 +103,6 @@ type
|
||||||
PNimType = ptr TNimType
|
PNimType = ptr TNimType
|
||||||
|
|
||||||
when defined(nimTypeNames):
|
when defined(nimTypeNames):
|
||||||
var nimTypeRoot {.codegenType.}: PNimType
|
var nimTypeRoot {.compilerProc.}: PNimType
|
||||||
|
|
||||||
# node.len may be the ``first`` element of a set
|
# node.len may be the ``first`` element of a set
|
||||||
|
|
|
||||||
10
tests/ccgbugs/t8964.nim
Normal file
10
tests/ccgbugs/t8964.nim
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
discard """
|
||||||
|
targets: "c cpp"
|
||||||
|
"""
|
||||||
|
|
||||||
|
from json import JsonParsingError
|
||||||
|
import marshal
|
||||||
|
|
||||||
|
const nothing = ""
|
||||||
|
doAssertRaises(JsonParsingError):
|
||||||
|
var bar = marshal.to[int](nothing)
|
||||||
|
|
@ -2,7 +2,8 @@ discard """
|
||||||
disabled: true
|
disabled: true
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{. noforward: on .}
|
# {. noforward: on .}
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
proc foo(x: int) =
|
proc foo(x: int) =
|
||||||
bar x
|
bar x
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ defined
|
||||||
3'''
|
3'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.reorder: on.}
|
{.experimental: "codeReordering".}
|
||||||
{.experimental.}
|
|
||||||
|
|
||||||
proc bar(x: T)
|
proc bar(x: T)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ output:'''0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
{.reorder: on .}
|
# {.reorder: on .}
|
||||||
|
{.experimental: "codeReordering".}
|
||||||
|
|
||||||
echo foo(-1)
|
echo foo(-1)
|
||||||
echo callWithFoo(0)
|
echo callWithFoo(0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue