summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2018-01-11 18:05:26 +0100
committerAraq <rumpf_a@web.de>2018-01-11 18:05:26 +0100
commit425f221440cbd453591d0fca9eaf93671d5f6d62 (patch)
treefaa55712aa23ebdf5ceb68030ec654ea8e7abf62
parentfb8def869c0a372dd943297a981970adef59bb4d (diff)
parent72d9485e8e0b839c3832ecb3b949e116fe9ed062 (diff)
downloadNim-425f221440cbd453591d0fca9eaf93671d5f6d62.tar.gz
Merge branch 'devel' of github.com:nim-lang/Nim into devel
-rw-r--r--compiler/ccgexprs.nim48
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/pure/asyncfutures.nim6
-rw-r--r--lib/pure/asyncmacro.nim6
-rw-r--r--lib/pure/net.nim2
-rw-r--r--lib/pure/os.nim10
-rw-r--r--lib/pure/times.nim4
-rw-r--r--lib/system/sysio.nim5
-rw-r--r--lib/system/sysstr.nim7
-rw-r--r--lib/windows/winlean.nim1
-rw-r--r--lib/wrappers/openssl.nim95
-rw-r--r--tests/async/t6100.nim15
-rw-r--r--tests/async/tasync_traceback.nim130
-rw-r--r--tests/async/tfuturestream.nim2
-rw-r--r--tests/float/tfloat4.nim6
-rw-r--r--tests/objects/tobjconstr.nim7
-rw-r--r--tests/objects/tobjconstr2.nim7
-rw-r--r--tests/stdlib/ttimes.nim24
-rw-r--r--tests/untestable/tssl.nim36
19 files changed, 301 insertions, 112 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 0a312b4c7..bb9a9f6c6 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1202,18 +1202,30 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   # we skip this step here:
   if not p.module.compileToCpp:
     if handleConstExpr(p, e, d): return
-  var tmp: TLoc
   var t = e.typ.skipTypes(abstractInst)
-  getTemp(p, t, tmp)
   let isRef = t.kind == tyRef
-  var r = rdLoc(tmp)
-  if isRef:
-    rawGenNew(p, tmp, nil)
-    t = t.lastSon.skipTypes(abstractInst)
-    r = "(*$1)" % [r]
-    gcUsage(e)
+
+  # check if we need to construct the object in a temporary
+  var useTemp =
+        isRef or
+        (d.k notin {locTemp,locLocalVar,locGlobalVar,locParam,locField}) or
+        (isPartOf(d.lode, e) != arNo)
+
+  var tmp: TLoc
+  var r: Rope
+  if useTemp:
+    getTemp(p, t, tmp)
+    r = rdLoc(tmp)
+    if isRef:
+      rawGenNew(p, tmp, nil)
+      t = t.lastSon.skipTypes(abstractInst)
+      r = "(*$1)" % [r]
+      gcUsage(e)
+    else:
+      constructLoc(p, tmp)
   else:
-    constructLoc(p, tmp)
+    resetLoc(p, d)
+    r = rdLoc(d)
   discard getTypeDesc(p.module, t)
   let ty = getUniqueType(t)
   for i in 1 ..< e.len:
@@ -1227,15 +1239,19 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
       genFieldCheck(p, it.sons[2], r, field)
     add(tmp2.r, ".")
     add(tmp2.r, field.loc.r)
-    tmp2.k = locTemp
+    if useTemp:
+      tmp2.k = locTemp
+      tmp2.storage = if isRef: OnHeap else: OnStack
+    else:
+      tmp2.k = d.k
+      tmp2.storage = if isRef: OnHeap else: d.storage
     tmp2.lode = it.sons[1]
-    tmp2.storage = if isRef: OnHeap else: OnStack
     expr(p, it.sons[1], tmp2)
-
-  if d.k == locNone:
-    d = tmp
-  else:
-    genAssignment(p, d, tmp, {})
+  if useTemp:
+    if d.k == locNone:
+      d = tmp
+    else:
+      genAssignment(p, d, tmp, {})
 
 proc lhsDoesAlias(a, b: PNode): bool =
   for y in b:
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 31075bbd2..69699a2a4 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -70,7 +70,7 @@ __clang__
 #if defined(_MSC_VER)
 #  pragma warning(disable: 4005 4100 4101 4189 4191 4200 4244 4293 4296 4309)
 #  pragma warning(disable: 4310 4365 4456 4477 4514 4574 4611 4668 4702 4706)
-#  pragma warning(disable: 4710 4711 4774 4800 4820 4996 4090 4297)
+#  pragma warning(disable: 4710 4711 4774 4800 4809 4820 4996 4090 4297)
 #endif
 /* ------------------------------------------------------------------------- */
 
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index bcc3ab613..11461d994 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -324,12 +324,12 @@ proc mget*[T](future: FutureVar[T]): var T =
   ## Future has not been finished.
   result = Future[T](future).value
 
-proc finished*[T](future: Future[T] | FutureVar[T]): bool =
+proc finished*(future: FutureBase | FutureVar): bool =
   ## Determines whether ``future`` has completed.
   ##
   ## ``True`` may indicate an error or a value. Use ``failed`` to distinguish.
-  when future is FutureVar[T]:
-    result = (Future[T](future)).finished
+  when future is FutureVar:
+    result = (FutureBase(future)).finished
   else:
     result = future.finished
 
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index 8c679929d..f70714309 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -32,6 +32,12 @@ template createCb(retFutureSym, iteratorNameSym,
     try:
       if not nameIterVar.finished:
         var next = nameIterVar()
+        # Continue while the yielded future is already finished.
+        while (not next.isNil) and next.finished:
+          next = nameIterVar()
+          if nameIterVar.finished:
+            break
+
         if next == nil:
           if not retFutureSym.finished:
             let msg = "Async procedure ($1) yielded `nil`, are you await'ing a " &
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index aad6ab3e8..083e70c8d 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -413,7 +413,7 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} =
 
 when defineSsl:
   CRYPTO_malloc_init()
-  SslLibraryInit()
+  doAssert SslLibraryInit() == 1
   SslLoadErrorStrings()
   ErrLoadBioStrings()
   OpenSSL_add_all_algorithms()
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index c18d03289..a5db4ed22 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -672,7 +672,10 @@ template walkCommon(pattern: string, filter) =
           if dotPos < 0 or idx >= ff.len or ff[idx] == '.' or
               pattern[dotPos+1] == '*':
             yield splitFile(pattern).dir / extractFilename(ff)
-        if findNextFile(res, f) == 0'i32: break
+        if findNextFile(res, f) == 0'i32:
+          let errCode = getLastError()
+          if errCode == ERROR_NO_MORE_FILES: break
+          else: raiseOSError(errCode.OSErrorCode)
   else: # here we use glob
     var
       f: Glob
@@ -782,7 +785,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
             let xx = if relative: extractFilename(getFilename(f))
                      else: dir / extractFilename(getFilename(f))
             yield (k, xx)
-          if findNextFile(h, f) == 0'i32: break
+          if findNextFile(h, f) == 0'i32:
+            let errCode = getLastError()
+            if errCode == ERROR_NO_MORE_FILES: break
+            else: raiseOSError(errCode.OSErrorCode)
     else:
       var d = opendir(dir)
       if d != nil:
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 42e89e7ce..50bf8f7f2 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -129,8 +129,8 @@ type
                      ## The ``times`` module only supplies implementations for the systems local time and UTC.
                      ## The members ``zoneInfoFromUtc`` and ``zoneInfoFromTz`` should not be accessed directly
                      ## and are only exported so that ``Timezone`` can be implemented by other modules.
-    zoneInfoFromUtc*: proc (time: Time): ZonedTime {.nimcall, tags: [], raises: [], benign .}
-    zoneInfoFromTz*:  proc (adjTime: Time): ZonedTime {.nimcall, tags: [], raises: [], benign .}
+    zoneInfoFromUtc*: proc (time: Time): ZonedTime {.tags: [], raises: [], benign.}
+    zoneInfoFromTz*:  proc (adjTime: Time): ZonedTime {.tags: [], raises: [], benign.}
     name*: string ## The name of the timezone, f.ex 'Europe/Stockholm' or 'Etc/UTC'. Used for checking equality.
                   ## Se also: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
   ZonedTime* = object ## Represents a zooned instant in time that is not associated with any calendar.
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 4348ffbb5..f638b299c 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -406,7 +406,8 @@ proc setStdIoUnbuffered() =
 
 when declared(stdout):
   proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
-    when not defined(windows):
+    # flockfile deadlocks some versions of Android 5.x.x
+    when not defined(windows) and not defined(android):
       proc flockfile(f: File) {.importc, noDecl.}
       proc funlockfile(f: File) {.importc, noDecl.}
       flockfile(stdout)
@@ -415,7 +416,7 @@ when declared(stdout):
     const linefeed = "\n" # can be 1 or more chars
     discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
     discard c_fflush(stdout)
-    when not defined(windows):
+    when not defined(windows) and not defined(android):
       funlockfile(stdout)
 
 {.pop.}
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 4c5f3d9a1..514223af2 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -386,8 +386,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
     kdigits, fdigits = 0
     exponent: int
     integer: uint64
-    fraction: uint64
-    frac_exponent= 0
+    frac_exponent = 0
     exp_sign = 1
     first_digit = -1
     has_sign = false
@@ -480,7 +479,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
 
   # if integer is representable in 53 bits:  fast path
   # max fast path integer is  1<<53 - 1 or  8999999999999999 (16 digits)
-  if kdigits + fdigits <= 16 and first_digit <= 8:
+  let digits = kdigits + fdigits
+  if digits <= 15 or (digits <= 16 and first_digit <= 8):
     # max float power of ten with set bits above the 53th bit is 10^22
     if abs_exponent <= 22:
       if exp_negative:
@@ -504,6 +504,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
   result = i - start
   i = start
   # re-parse without error checking, any error should be handled by the code above.
+  if s[i] == '.': i.inc
   while s[i] in {'0'..'9','+','-'}:
     if ti < maxlen:
       t[ti] = s[i]; inc(ti)
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index a833377e5..bd6e58a10 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -686,6 +686,7 @@ const
   ERROR_FILE_NOT_FOUND* = 2
   ERROR_PATH_NOT_FOUND* = 3
   ERROR_ACCESS_DENIED* = 5
+  ERROR_NO_MORE_FILES* = 18
   ERROR_HANDLE_EOF* = 38
   ERROR_BAD_ARGUMENTS* = 165
 
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 55b0bc3f8..1d0dc5897 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -8,6 +8,17 @@
 #
 
 ## OpenSSL support
+##
+## When OpenSSL is dynamically linked, the wrapper provides partial forward and backward
+## compatibility for OpenSSL versions above and below 1.1.0
+##
+## OpenSSL can be also statically linked using dynlibOverride:ssl for OpenSSL >= 1.1.0
+##
+## Build and test examples:
+##
+## .. code-block::
+##   ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim
+##   ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passL:-lcrypto --passL:-lssl -r tests/untestable/tssl.nim
 
 {.deadCodeElim: on.}
 
@@ -25,8 +36,8 @@ when useWinVersion:
 
   from winlean import SocketHandle
 else:
-  const
-    versions = "(|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
+  const versions = "(.1.1|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
+
   when defined(macosx):
     const
       DLLSSLName = "libssl" & versions & ".dylib"
@@ -140,6 +151,7 @@ const
   SSL_OP_NO_SSLv2* = 0x01000000
   SSL_OP_NO_SSLv3* = 0x02000000
   SSL_OP_NO_TLSv1* = 0x04000000
+  SSL_OP_NO_TLSv1_1* = 0x08000000
   SSL_OP_ALL* = 0x000FFFFF
   SSL_VERIFY_NONE* = 0x00000000
   SSL_VERIFY_PEER* = 0x00000001
@@ -191,16 +203,39 @@ const
 
 proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
 
+# TLS_method(), TLS_server_method(), TLS_client_method() are introduced in 1.1.0
+# and support SSLv3, TLSv1, TLSv1.1 and TLSv1.2
+# SSLv23_method(), SSLv23_server_method(), SSLv23_client_method() are removed in 1.1.0
+
 when compileOption("dynlibOverride", "ssl"):
-  proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.}
-  proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.}
-  proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
+  # Static linking
+  proc OPENSSL_init_ssl*(opts: uint64, settings: uint8): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.}
+  proc SSL_library_init*(): cint {.discardable.} =
+    ## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0
+    return OPENSSL_init_ssl(0.uint64, 0.uint8)
 
-  proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
+  proc TLS_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
+  proc SSLv23_method*(): PSSL_METHOD =
+    TLS_method()
+
+  proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
   proc SSLv2_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
   proc SSLv3_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.}
 
   template OpenSSL_add_all_algorithms*() = discard
+
+  proc OpenSSL_version_num(): culong {.cdecl, dynlib: DLLSSLName, importc.}
+
+  proc getOpenSSLVersion*(): culong =
+    ## Return OpenSSL version as unsigned long
+    OpenSSL_version_num()
+
+  proc SSL_load_error_strings*() =
+    ## Removed from OpenSSL 1.1.0
+    # This proc prevents breaking existing code calling SslLoadErrorStrings
+    # Static linking against OpenSSL < 1.1.0 is not supported
+    discard
+
 else:
   # Here we're trying to stay compatible with openssl 1.0.* and 1.1.*. Some
   # symbols are loaded dynamically and we don't use them if not found.
@@ -223,38 +258,58 @@ else:
       if not dl.isNil:
         result = symAddr(dl, name)
 
+  proc loadPSSLMethod(method1, method2: string): PSSL_METHOD =
+    ## Load <method1> from OpenSSL if available, otherwise <method2>
+    let m1 = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method1))
+    if not m1.isNil:
+      return m1()
+    cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym(method2))()
+
   proc SSL_library_init*(): cint {.discardable.} =
-    let theProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init"))
-    if not theProc.isNil: result = theProc()
+    ## Initialize SSL using OPENSSL_init_ssl for OpenSSL >= 1.1.0 otherwise
+    ## SSL_library_init
+    let theProc = cast[proc(opts: uint64, settings: uint8): cint {.cdecl.}](sslSym("OPENSSL_init_ssl"))
+    if not theProc.isNil:
+      return theProc(0, 0)
+    let olderProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init"))
+    if not olderProc.isNil: result = olderProc()
 
   proc SSL_load_error_strings*() =
     let theProc = cast[proc() {.cdecl.}](sslSym("SSL_load_error_strings"))
     if not theProc.isNil: theProc()
 
   proc SSLv23_client_method*(): PSSL_METHOD =
-    let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv23_client_method"))
-    if not theProc.isNil: result = theProc()
-    else: result = TLSv1_method()
+    loadPSSLMethod("SSLv23_client_method", "TLS_client_method")
 
   proc SSLv23_method*(): PSSL_METHOD =
-    let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv23_method"))
-    if not theProc.isNil: result = theProc()
-    else: result = TLSv1_method()
+    loadPSSLMethod("SSLv23_method", "TLS_method")
 
   proc SSLv2_method*(): PSSL_METHOD =
-    let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv2_method"))
-    if not theProc.isNil: result = theProc()
-    else: result = TLSv1_method()
+    loadPSSLMethod("SSLv2_method", "TLS_method")
 
   proc SSLv3_method*(): PSSL_METHOD =
-    let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv3_method"))
-    if not theProc.isNil: result = theProc()
-    else: result = TLSv1_method()
+    loadPSSLMethod("SSLv3_method", "TLS_method")
+
+  proc TLS_method*(): PSSL_METHOD =
+    loadPSSLMethod("TLS_method", "SSLv23_method")
+
+  proc TLS_client_method*(): PSSL_METHOD =
+    loadPSSLMethod("TLS_client_method", "SSLv23_client_method")
+
+  proc TLS_server_method*(): PSSL_METHOD =
+    loadPSSLMethod("TLS_server_method", "SSLv23_server_method")
 
   proc OpenSSL_add_all_algorithms*() =
     let theProc = cast[proc() {.cdecl.}](sslSym("OPENSSL_add_all_algorithms_conf"))
     if not theProc.isNil: theProc()
 
+  proc getOpenSSLVersion*(): culong =
+    ## Return OpenSSL version as unsigned long or 0 if not available
+    let theProc = cast[proc(): culong {.cdecl.}](sslSym("OpenSSL_version_num"))
+    result =
+      if theProc.isNil: 0.culong
+      else: theProc()
+
 proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.}
 
 proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.}
diff --git a/tests/async/t6100.nim b/tests/async/t6100.nim
new file mode 100644
index 000000000..b4dc0f146
--- /dev/null
+++ b/tests/async/t6100.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "t6100.nim"
+  exitcode: 0
+  output: "10000000"
+"""
+import asyncdispatch
+
+let done = newFuture[int]()
+done.complete(1)
+
+proc asyncSum: Future[int] {.async.} =
+  for _ in 1..10_000_000:
+    result += await done
+
+echo waitFor asyncSum()
\ No newline at end of file
diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim
index 08f7e7317..e4c8a67b3 100644
--- a/tests/async/tasync_traceback.nim
+++ b/tests/async/tasync_traceback.nim
@@ -1,61 +1,7 @@
 discard """
   exitcode: 0
   disabled: "windows"
-  output: '''
-b failure
-Async traceback:
-  tasync_traceback.nim(97) tasync_traceback
-  asyncmacro.nim(395)      a
-  asyncmacro.nim(34)       a_continue
-    ## Resumes an async procedure
-  tasync_traceback.nim(95) aIter
-  asyncmacro.nim(395)      b
-  asyncmacro.nim(34)       b_continue
-    ## Resumes an async procedure
-  tasync_traceback.nim(92) bIter
-  #[
-    tasync_traceback.nim(97) tasync_traceback
-    asyncmacro.nim(395)      a
-    asyncmacro.nim(43)       a_continue
-      ## Resumes an async procedure
-    asyncfutures.nim(211)    callback=
-    asyncfutures.nim(190)    addCallback
-    asyncfutures.nim(53)     callSoon
-    asyncmacro.nim(34)       a_continue
-      ## Resumes an async procedure
-    asyncmacro.nim(0)        aIter
-    asyncfutures.nim(304)    read
-  ]#
-Exception message: b failure
-Exception type:
-
-bar failure
-Async traceback:
-  tasync_traceback.nim(113) tasync_traceback
-  asyncdispatch.nim(1492)   waitFor
-  asyncdispatch.nim(1496)   poll
-    ## Processes asynchronous completion events
-  asyncdispatch.nim(1262)   runOnce
-  asyncdispatch.nim(183)    processPendingCallbacks
-    ## Executes pending callbacks
-  asyncmacro.nim(34)        bar_continue
-    ## Resumes an async procedure
-  tasync_traceback.nim(108) barIter
-  #[
-    tasync_traceback.nim(113) tasync_traceback
-    asyncdispatch.nim(1492)   waitFor
-    asyncdispatch.nim(1496)   poll
-      ## Processes asynchronous completion events
-    asyncdispatch.nim(1262)   runOnce
-    asyncdispatch.nim(183)    processPendingCallbacks
-      ## Executes pending callbacks
-    asyncmacro.nim(34)        foo_continue
-      ## Resumes an async procedure
-    asyncmacro.nim(0)         fooIter
-    asyncfutures.nim(304)     read
-  ]#
-Exception message: bar failure
-Exception type:'''
+  output: "Matched"
 """
 import asyncdispatch
 
@@ -87,6 +33,8 @@ import asyncdispatch
 # tasync_traceback.nim(21) a
 # tasync_traceback.nim(18) b
 
+var result = ""
+
 proc b(): Future[int] {.async.} =
   if true:
     raise newException(OSError, "b failure")
@@ -98,8 +46,8 @@ let aFut = a()
 try:
   discard waitFor aFut
 except Exception as exc:
-  echo exc.msg
-echo()
+  result.add(exc.msg & "\n")
+result.add("\n")
 
 # From #6803
 proc bar(): Future[string] {.async.} =
@@ -110,7 +58,69 @@ proc bar(): Future[string] {.async.} =
 proc foo(): Future[string] {.async.} = return await bar()
 
 try:
-  echo waitFor(foo())
+  result.add(waitFor(foo()) & "\n")
 except Exception as exc:
-  echo exc.msg
-echo()
\ No newline at end of file
+  result.add(exc.msg & "\n")
+result.add("\n")
+
+# Use re to parse the result
+import re
+const expected = """
+b failure
+Async traceback:
+  tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
+  asyncmacro\.nim\(\d+?\)\s+?a
+  asyncmacro\.nim\(\d+?\)\s+?a_continue
+    ## Resumes an async procedure
+  tasync_traceback\.nim\(\d+?\)\s+?aIter
+  asyncmacro\.nim\(\d+?\)\s+?b
+  asyncmacro\.nim\(\d+?\)\s+?b_continue
+    ## Resumes an async procedure
+  tasync_traceback\.nim\(\d+?\)\s+?bIter
+  #\[
+    tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
+    asyncmacro\.nim\(\d+?\)\s+?a
+    asyncmacro\.nim\(\d+?\)\s+?a_continue
+      ## Resumes an async procedure
+    asyncmacro\.nim\(\d+?\)\s+?aIter
+    asyncfutures\.nim\(\d+?\)\s+?read
+  \]#
+Exception message: b failure
+Exception type:
+
+bar failure
+Async traceback:
+  tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
+  asyncdispatch\.nim\(\d+?\)\s+?waitFor
+  asyncdispatch\.nim\(\d+?\)\s+?poll
+    ## Processes asynchronous completion events
+  asyncdispatch\.nim\(\d+?\)\s+?runOnce
+  asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks
+    ## Executes pending callbacks
+  asyncmacro\.nim\(\d+?\)\s+?bar_continue
+    ## Resumes an async procedure
+  tasync_traceback\.nim\(\d+?\)\s+?barIter
+  #\[
+    tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
+    asyncdispatch\.nim\(\d+?\)\s+?waitFor
+    asyncdispatch\.nim\(\d+?\)\s+?poll
+      ## Processes asynchronous completion events
+    asyncdispatch\.nim\(\d+?\)\s+?runOnce
+    asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks
+      ## Executes pending callbacks
+    asyncmacro\.nim\(\d+?\)\s+?foo_continue
+      ## Resumes an async procedure
+    asyncmacro\.nim\(\d+?\)\s+?fooIter
+    asyncfutures\.nim\(\d+?\)\s+?read
+  \]#
+Exception message: bar failure
+Exception type:
+"""
+
+if result.match(re(expected)):
+  echo("Matched")
+else:
+  echo("Not matched!")
+  echo()
+  echo(result)
+  quit(QuitFailure)
diff --git a/tests/async/tfuturestream.nim b/tests/async/tfuturestream.nim
index 9a8e986a0..d76752b7e 100644
--- a/tests/async/tfuturestream.nim
+++ b/tests/async/tfuturestream.nim
@@ -18,8 +18,8 @@ var fs = newFutureStream[int]()
 
 proc alpha() {.async.} =
   for i in 0 .. 5:
-    await sleepAsync(1000)
     await fs.write(i)
+    await sleepAsync(1000)
 
   echo("Done")
   fs.complete()
diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim
index 559c8aaca..68df56be8 100644
--- a/tests/float/tfloat4.nim
+++ b/tests/float/tfloat4.nim
@@ -48,5 +48,11 @@ doAssert "2.71828182845904523536028747".parseFloat ==
        2.71828182845904523536028747
 doAssert 0.00097656250000000021684043449710088680149056017398834228515625 ==
      "0.00097656250000000021684043449710088680149056017398834228515625".parseFloat
+doAssert 0.00998333 == ".00998333".parseFloat
+doAssert 0.00128333 == ".00128333".parseFloat
+doAssert 999999999999999.0 == "999999999999999.0".parseFloat
+doAssert 9999999999999999.0 == "9999999999999999.0".parseFloat
+doAssert 0.999999999999999 == ".999999999999999".parseFloat
+doAssert 0.9999999999999999 == ".9999999999999999".parseFloat
 
 echo("passed all tests.")
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
index b7da176aa..d1f3c8bdb 100644
--- a/tests/objects/tobjconstr.nim
+++ b/tests/objects/tobjconstr.nim
@@ -15,7 +15,8 @@ discard """
 (y: 678, x: 123)
 (y: 678, x: 123)
 (y: 0, x: 123)
-(y: 678, x: 123)'''
+(y: 678, x: 123)
+(y: 123, x: 678)'''
 """
 
 type
@@ -75,3 +76,7 @@ when true:
   echo b                  # (y: 0, x: 123)
   b=B(y: 678, x: 123)
   echo b                  # (y: 678, x: 123)
+  b=B(y: b.x, x: b.y)
+  echo b                  # (y: 123, x: 678)
+
+GC_fullCollect()
diff --git a/tests/objects/tobjconstr2.nim b/tests/objects/tobjconstr2.nim
index f6805190b..6253edab0 100644
--- a/tests/objects/tobjconstr2.nim
+++ b/tests/objects/tobjconstr2.nim
@@ -1,3 +1,8 @@
+discard """
+  output: '''42
+Foo'''
+"""
+
 type TFoo{.exportc.} = object
  x:int
 
@@ -48,3 +53,5 @@ type NamedGraphic = object of Graphic2
 
 var ngr = NamedGraphic(kind: Koo, radius: 6.9, name: "Foo")
 echo ngr.name
+
+GC_fullCollect()
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index a6ac186cc..1f8ae6a22 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -281,6 +281,30 @@ suite "ttimes":
     test "parseTest":
       runTimezoneTests()
 
+  test "dynamic timezone":
+    proc staticOffset(offset: int): Timezone =
+      proc zoneInfoFromTz(adjTime: Time): ZonedTime =
+          result.isDst = false
+          result.utcOffset = offset
+          result.adjTime = adjTime
+
+      proc zoneInfoFromUtc(time: Time): ZonedTime =
+          result.isDst = false
+          result.utcOffset = offset
+          result.adjTime = fromUnix(time.toUnix - offset)
+
+      result.name = ""
+      result.zoneInfoFromTz = zoneInfoFromTz
+      result.zoneInfoFromUtc = zoneInfoFromUtc
+
+    let tz = staticOffset(-9000)
+    let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz)
+    check dt.utcOffset == -9000
+    check dt.isDst == false
+    check $dt == "2000-01-01T12:00:00+02:30"
+    check $dt.utc == "2000-01-01T09:30:00+00:00"
+    check $dt.utc.inZone(tz) == $dt
+
   test "isLeapYear":
     check isLeapYear(2016)
     check (not isLeapYear(2015))
diff --git a/tests/untestable/tssl.nim b/tests/untestable/tssl.nim
new file mode 100644
index 000000000..664ad805c
--- /dev/null
+++ b/tests/untestable/tssl.nim
@@ -0,0 +1,36 @@
+#
+#            Nim - SSL integration tests
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Warning: this test performs external networking.
+##
+## Test with:
+## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim
+## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passL:-lcrypto --passL:-lssl -r tests/untestable/tssl.nim
+## The compilation is expected to succeed with any new/old version of OpenSSL,
+## both with dynamic and static linking.
+## The "howsmyssl" test is known to fail with OpenSSL < 1.1 due to insecure
+## cypher suites being used.
+
+import httpclient, os
+from strutils import contains, toHex
+
+from openssl import getOpenSSLVersion
+
+when isMainModule:
+  echo "version: 0x" & $getOpenSSLVersion().toHex()
+
+  let client = newHttpClient()
+  # hacky SSL check
+  const url = "https://www.howsmyssl.com"
+  let report = client.getContent(url)
+  if not report.contains(">Probably Okay</span>"):
+    let fn = getTempDir() / "sslreport.html"
+    echo "SSL CHECK ERROR, see " & fn
+    writeFile(fn, report)
+    quit(1)
+
+  echo "done"