summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml10
-rw-r--r--compiler/ccgtypes.nim8
-rw-r--r--compiler/pragmas.nim28
-rw-r--r--compiler/trees.nim2
-rw-r--r--compiler/wordrecg.nim4
-rw-r--r--doc/manual/locking.txt19
-rw-r--r--doc/manual/pragmas.txt32
-rw-r--r--lib/pure/json.nim9
-rw-r--r--lib/pure/os.nim2
-rw-r--r--tests/ccgbugs/tmangle_field.nim16
-rw-r--r--tests/pragmas/tlocks.nim13
-rw-r--r--tests/pragmas/tused.nim13
-rw-r--r--web/news/e031_version_0_16_2.rst4
13 files changed, 135 insertions, 25 deletions
diff --git a/.travis.yml b/.travis.yml
index a3db0c58e..ffb0033a3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,14 +2,24 @@ sudo: false
 language: c
 os:
   - linux
+  - osx
 dist: trusty
 
+matrix:
+  allow_failures:
+    - os: osx
+
 addons:
   apt:
     packages:
     - libcurl4-openssl-dev
     - libsdl1.2-dev
     - libgc-dev
+  brew:
+    packages:
+    - boehmgc
+    - node
+
 before_script:
   - set -e
   - curl --out fasm-1.71.39.tgz https://nim-lang.org/download/fasm-1.71.39.tgz
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index e30fe5598..29d4e23c9 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -24,7 +24,13 @@ proc isKeyword(w: PIdent): bool =
 
 proc mangleField(m: BModule; name: PIdent): string =
   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"
 
 when false:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 04dbd3612..bcb0461f2 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -25,19 +25,19 @@ const
     wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
     wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
     wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
-    wOverride, wConstructor, wExportNims}
+    wOverride, wConstructor, wExportNims, wUsed}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas+{wBase}-{wImportCpp}
   templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
-    wDelegator, wExportNims}
+    wDelegator, wExportNims, wUsed}
   macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
     wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
-    wExportNims}
+    wExportNims, wUsed}
   iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
-    wTags, wLocks, wGcSafe, wExportNims}
+    wTags, wLocks, wGcSafe, wExportNims, wUsed}
   exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
@@ -55,16 +55,16 @@ const
     wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
     wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
-    wBorrow, wGcSafe, wExportNims, wPartial}
+    wBorrow, wGcSafe, wExportNims, wPartial, wUsed}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
-    wImportCpp, wImportObjC, wError, wGuard, wBitsize}
+    wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
     wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
     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,
     wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
-    wIntDefine, wStrDefine}
+    wIntDefine, wStrDefine, wUsed}
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
                       wThread, wRaises, wLocks, wTags, wGcSafe}
@@ -582,7 +582,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
   if it.kind != nkExprColonExpr:
     invalidPragma(it)
   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)
       if x < 0 or x > 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
       of wStrDefine:
         sym.magic = mStrDefine
+      of wUsed:
+        noVal(it)
+        if sym == nil: invalidPragma(it)
+        else: sym.flags.incl sfUsed
       else: invalidPragma(it)
     else: invalidPragma(it)
 
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 79a460aa0..424fba14c 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -62,7 +62,7 @@ proc sameTree*(a, b: PNode): bool =
       # don't go nuts here: same symbol as string is enough:
       result = a.sym.name.id == b.sym.name.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 nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     of nkEmpty, nkNilLit, nkType: result = true
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index cf66b6358..6072bd64c 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -45,7 +45,7 @@ type
     wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideeffect, wHeader,
     wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
-    wCompilerproc, wProcVar, wBase,
+    wCompilerproc, wProcVar, wBase, wUsed,
     wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
     wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
     wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
@@ -131,7 +131,7 @@ const
     "incompletestruct",
     "requiresinit", "align", "nodecl", "pure", "sideeffect",
     "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
-    "compilerproc", "procvar", "base",
+    "compilerproc", "procvar", "base", "used",
     "fatal", "error", "warning", "hint", "line",
     "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
     "link", "compile", "linksys", "deprecated", "varargs",
diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt
index c00efdd91..c1bd5ca46 100644
--- a/doc/manual/locking.txt
+++ b/doc/manual/locking.txt
@@ -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
 relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}``
 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()
diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt
index 2a276c2e7..d30c37ff7 100644
--- a/doc/manual/pragmas.txt
+++ b/doc/manual/pragmas.txt
@@ -503,6 +503,26 @@ identifier that can be used to enable or disable it:
 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
 -------------------
 
@@ -1018,12 +1038,12 @@ the -d/--define option at compile time.
 The implementation currently provides the following possible options (various
 others may be added later).
 
-===============  ============================================
-pragma           description
-===============  ============================================
-intdefine        Reads in a build-time define as an integer
-strdefine        Reads in a build-time define as a string
-===============  ============================================
+=================  ============================================
+pragma             description
+=================  ============================================
+`intdefine`:idx:   Reads in a build-time define as an integer
+`strdefine`:idx:   Reads in a build-time define as a string
+=================  ============================================
 
 .. code-block:: nim
    const FooBar {.intdefine.}: int = 5
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 5e36a2aa1..c7b581a85 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -952,7 +952,7 @@ proc newIndent(curr, indent: int, ml: bool): int =
   else: return indent
 
 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) =
   ## 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) =
   case node.kind
   of JObject:
-    if currIndent != 0 and not lstArr: result.nl(ml)
-    result.indent(currIndent) # Indentation
+    if lstArr: result.indent(currIndent) # Indentation
     if node.fields.len > 0:
       result.add("{")
       result.nl(ml) # New line
       var i = 0
       for key, val in pairs(node.fields):
         if i > 0:
-          result.add(", ")
+          result.add(",")
           result.nl(ml) # New Line
         inc i
         # Need to indent more than {
@@ -1030,7 +1029,7 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
       result.nl(ml)
       for i in 0..len(node.elems)-1:
         if i > 0:
-          result.add(", ")
+          result.add(",")
           result.nl(ml) # New Line
         toPretty(result, node.elems[i], indent, ml,
             true, newIndent(currIndent, indent, ml))
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 92e295820..6bf776a44 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1185,7 +1185,7 @@ proc createHardlink*(src, dest: string) =
 
 proc parseCmdLine*(c: string): seq[string] {.
   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.
   ##
   ## On Windows, it uses the following parsing rules
diff --git a/tests/ccgbugs/tmangle_field.nim b/tests/ccgbugs/tmangle_field.nim
new file mode 100644
index 000000000..9e4012b8b
--- /dev/null
+++ b/tests/ccgbugs/tmangle_field.nim
@@ -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
diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim
new file mode 100644
index 000000000..ba66a2dca
--- /dev/null
+++ b/tests/pragmas/tlocks.nim
@@ -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
diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim
new file mode 100644
index 000000000..f3126bd45
--- /dev/null
+++ b/tests/pragmas/tused.nim
@@ -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
diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst
index 171e4cef1..785285eaf 100644
--- a/web/news/e031_version_0_16_2.rst
+++ b/web/news/e031_version_0_16_2.rst
@@ -66,6 +66,10 @@ these procedures.
 In the near future we will be converting all exception types to refs to
 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
 --------