Merge branch 'devel' into faster-nimsuggest

This commit is contained in:
Andreas Rumpf 2017-02-22 16:28:32 +01:00
commit ac3b312cc6
13 changed files with 135 additions and 25 deletions

View file

@ -2,14 +2,24 @@ sudo: false
language: c language: c
os: os:
- linux - linux
- osx
dist: trusty dist: trusty
matrix:
allow_failures:
- os: osx
addons: addons:
apt: apt:
packages: packages:
- libcurl4-openssl-dev - libcurl4-openssl-dev
- libsdl1.2-dev - libsdl1.2-dev
- libgc-dev - libgc-dev
brew:
packages:
- boehmgc
- node
before_script: before_script:
- set -e - set -e
- curl --out fasm-1.71.39.tgz https://nim-lang.org/download/fasm-1.71.39.tgz - curl --out fasm-1.71.39.tgz https://nim-lang.org/download/fasm-1.71.39.tgz

View file

@ -24,7 +24,13 @@ proc isKeyword(w: PIdent): bool =
proc mangleField(m: BModule; name: PIdent): string = proc mangleField(m: BModule; name: PIdent): string =
result = mangle(name.s) result = mangle(name.s)
if isKeyword(name) or m.g.config.cppDefines.contains(result): # fields are tricky to get right and thanks to generic types producing
# duplicates we can end up mangling the same field multiple times. However
# if we do so, the 'cppDefines' table might be modified in the meantime
# meaning we produce inconsistent field names (see bug #5404).
# Hence we do not check for ``m.g.config.cppDefines.contains(result)`` here
# anymore:
if isKeyword(name):
result.add "_0" result.add "_0"
when false: when false:

View file

@ -25,19 +25,19 @@ const
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
wOverride, wConstructor, wExportNims} wOverride, wConstructor, wExportNims, wUsed}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp} methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
wDelegator, wExportNims} wDelegator, wExportNims, wUsed}
macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern, wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
wExportNims} wExportNims, wUsed}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
wTags, wLocks, wGcSafe, wExportNims} wTags, wLocks, wGcSafe, wExportNims, wUsed}
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
@ -55,16 +55,16 @@ const
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wExportNims, wPartial} wBorrow, wGcSafe, wExportNims, wPartial, wUsed}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wGuard, wBitsize} wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims, wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
wIntDefine, wStrDefine} wIntDefine, wStrDefine, wUsed}
letPragmas* = varPragmas letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
wThread, wRaises, wLocks, wTags, wGcSafe} wThread, wRaises, wLocks, wTags, wGcSafe}
@ -582,7 +582,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
if it.kind != nkExprColonExpr: if it.kind != nkExprColonExpr:
invalidPragma(it) invalidPragma(it)
else: else:
if it[1].kind != nkNilLit: case it[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
if it[1].strVal == "unknown":
result = UnknownLockLevel
else:
localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")")
else:
let x = expectIntLit(c, it) let x = expectIntLit(c, it)
if x < 0 or x > MaxLockLevel: if x < 0 or x > MaxLockLevel:
localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
@ -961,6 +967,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
sym.magic = mIntDefine sym.magic = mIntDefine
of wStrDefine: of wStrDefine:
sym.magic = mStrDefine sym.magic = mStrDefine
of wUsed:
noVal(it)
if sym == nil: invalidPragma(it)
else: sym.flags.incl sfUsed
else: invalidPragma(it) else: invalidPragma(it)
else: invalidPragma(it) else: invalidPragma(it)

View file

@ -62,7 +62,7 @@ proc sameTree*(a, b: PNode): bool =
# don't go nuts here: same symbol as string is enough: # don't go nuts here: same symbol as string is enough:
result = a.sym.name.id == b.sym.name.id result = a.sym.name.id == b.sym.name.id
of nkIdent: result = a.ident.id == b.ident.id of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkEmpty, nkNilLit, nkType: result = true of nkEmpty, nkNilLit, nkType: result = true

View file

@ -45,7 +45,7 @@ type
wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit, wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit,
wAlign, wNodecl, wPure, wSideeffect, wHeader, wAlign, wNodecl, wPure, wSideeffect, wHeader,
wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib, wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
wCompilerproc, wProcVar, wBase, wCompilerproc, wProcVar, wBase, wUsed,
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
wLinedir, wStacktrace, wLinetrace, wLink, wCompile, wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger, wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
@ -131,7 +131,7 @@ const
"incompletestruct", "incompletestruct",
"requiresinit", "align", "nodecl", "pure", "sideeffect", "requiresinit", "align", "nodecl", "pure", "sideeffect",
"header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib", "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
"compilerproc", "procvar", "base", "compilerproc", "procvar", "base", "used",
"fatal", "error", "warning", "hint", "line", "fatal", "error", "warning", "hint", "line",
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
"link", "compile", "linksys", "deprecated", "varargs", "link", "compile", "linksys", "deprecated", "varargs",

View file

@ -198,3 +198,22 @@ This is essential so that procs can be called within a ``locks`` section:
As usual ``locks`` is an inferred effect and there is a subtype As usual ``locks`` is an inferred effect and there is a subtype
relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}``
iff (M <= N). iff (M <= N).
The ``locks`` pragma can also take the special value ``"unknown"``. This
is useful in the context of dynamic method dispatching. In the following
example, the compiler can infer a lock level of 0 for the ``base`` case.
However, one of the overloaded methods calls a procvar which is
potentially locking. Thus, the lock level of calling ``g.testMethod``
cannot be inferred statically, leading to compiler warnings. By using
``{.locks: "unknown".}``, the base method can be marked explicitly as
having unknown lock level as well:
.. code-block:: nim
type SomeBase* = ref object of RootObj
type SomeDerived* = ref object of SomeBase
memberProc*: proc ()
method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard
method testMethod(g: SomeDerived) =
if g.memberProc != nil:
g.memberProc()

View file

@ -503,6 +503,26 @@ identifier that can be used to enable or disable it:
This is often better than disabling all warnings at once. This is often better than disabling all warnings at once.
used pragma
-----------
Nim produces a warning for symbols that are not exported and not used either.
The ``used`` pragma can be attached to a symbol to suppress this warning. This
is particularly useful when the symbol was generated by a macro:
.. code-block:: nim
template implementArithOps(T) =
proc echoAdd(a, b: T) {.used.} =
echo a + b
proc echoSub(a, b: T) {.used.} =
echo a - b
# no warning produced for the unused 'echoSub'
implementArithOps(int)
echoAdd 3, 5
experimental pragma experimental pragma
------------------- -------------------
@ -1018,12 +1038,12 @@ the -d/--define option at compile time.
The implementation currently provides the following possible options (various The implementation currently provides the following possible options (various
others may be added later). others may be added later).
=============== ============================================ ================= ============================================
pragma description pragma description
=============== ============================================ ================= ============================================
intdefine Reads in a build-time define as an integer `intdefine`:idx: Reads in a build-time define as an integer
strdefine Reads in a build-time define as a string `strdefine`:idx: Reads in a build-time define as a string
=============== ============================================ ================= ============================================
.. code-block:: nim .. code-block:: nim
const FooBar {.intdefine.}: int = 5 const FooBar {.intdefine.}: int = 5

View file

@ -952,7 +952,7 @@ proc newIndent(curr, indent: int, ml: bool): int =
else: return indent else: return indent
proc nl(s: var string, ml: bool) = proc nl(s: var string, ml: bool) =
if ml: s.add("\n") s.add(if ml: "\n" else: " ")
proc escapeJson*(s: string; result: var string) = proc escapeJson*(s: string; result: var string) =
## Converts a string `s` to its JSON representation. ## Converts a string `s` to its JSON representation.
@ -986,15 +986,14 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
lstArr = false, currIndent = 0) = lstArr = false, currIndent = 0) =
case node.kind case node.kind
of JObject: of JObject:
if currIndent != 0 and not lstArr: result.nl(ml) if lstArr: result.indent(currIndent) # Indentation
result.indent(currIndent) # Indentation
if node.fields.len > 0: if node.fields.len > 0:
result.add("{") result.add("{")
result.nl(ml) # New line result.nl(ml) # New line
var i = 0 var i = 0
for key, val in pairs(node.fields): for key, val in pairs(node.fields):
if i > 0: if i > 0:
result.add(", ") result.add(",")
result.nl(ml) # New Line result.nl(ml) # New Line
inc i inc i
# Need to indent more than { # Need to indent more than {
@ -1030,7 +1029,7 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
result.nl(ml) result.nl(ml)
for i in 0..len(node.elems)-1: for i in 0..len(node.elems)-1:
if i > 0: if i > 0:
result.add(", ") result.add(",")
result.nl(ml) # New Line result.nl(ml) # New Line
toPretty(result, node.elems[i], indent, ml, toPretty(result, node.elems[i], indent, ml,
true, newIndent(currIndent, indent, ml)) true, newIndent(currIndent, indent, ml))

View file

@ -1185,7 +1185,7 @@ proc createHardlink*(src, dest: string) =
proc parseCmdLine*(c: string): seq[string] {. proc parseCmdLine*(c: string): seq[string] {.
noSideEffect, rtl, extern: "nos$1".} = noSideEffect, rtl, extern: "nos$1".} =
## Splits a command line into several components; ## Splits a `command line`:idx: into several components;
## This proc is only occasionally useful, better use the `parseopt` module. ## This proc is only occasionally useful, better use the `parseopt` module.
## ##
## On Windows, it uses the following parsing rules ## On Windows, it uses the following parsing rules

View file

@ -0,0 +1,16 @@
discard """
"""
# bug #5404
import parseopt2
{.emit: """typedef struct {
int key;
} foo;""".}
type foo* {.importc: "foo", nodecl.} = object
key* {.importc: "key".}: cint
for kind, key, value in parseopt2.getopt():
discard

13
tests/pragmas/tlocks.nim Normal file
View file

@ -0,0 +1,13 @@
type SomeBase* = ref object of RootObj
type SomeDerived* = ref object of SomeBase
memberProc*: proc ()
method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard
method testMethod(g: SomeDerived) =
if g.memberProc != nil:
g.memberProc()
# ensure int literals still work
proc plain*() {.locks: 0.} =
discard

13
tests/pragmas/tused.nim Normal file
View file

@ -0,0 +1,13 @@
discard """
output: '''8'''
"""
template implementArithOps(T) =
proc echoAdd(a, b: T) {.used.} =
echo a + b
proc echoSub(a, b: T) {.used.} =
echo a - b
# no warning produced for the unused 'echoSub'
implementArithOps(int)
echoAdd 3, 5

View file

@ -66,6 +66,10 @@ these procedures.
In the near future we will be converting all exception types to refs to In the near future we will be converting all exception types to refs to
remove the need for the ``newException`` template. remove the need for the ``newException`` template.
- A new pragma ``.used`` can be used for symbols to prevent
the "declared but not used" warning. More details can be found `here <http://nim-lang.org/docs/manual.html#pragmas-used-pragma>`_.
Bugfixes Bugfixes
-------- --------