summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/cgen.nim21
-rw-r--r--compiler/semexprs.nim3
-rw-r--r--tests/errmsgs/tproper_stacktrace.nim124
3 files changed, 129 insertions, 19 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ee60e62d2..cd344f096 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -204,27 +204,22 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
     result = true
 
 proc genLineDir(p: BProc, t: PNode) =
-  var tt = t
-  #while tt.kind in {nkStmtListExpr}+nkCallKinds:
-  #  tt = tt.lastSon
-  if tt.kind in nkCallKinds and tt.len > 1:
-    tt = tt.sons[1]
-  let line = tt.info.safeLineNm
+  let line = t.info.safeLineNm
 
   if optEmbedOrigSrc in p.config.globalOptions:
-    add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & "\L")
-  genCLineDir(p.s(cpsStmts), toFullPath(p.config, tt.info), line, p.config)
+    add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
+  genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
   if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
       (p.prc == nil or sfPure notin p.prc.flags):
-    if freshLineInfo(p, tt.info):
+    if freshLineInfo(p, t.info):
       linefmt(p, cpsStmts, "#endb($1, $2);$N",
-              line.rope, makeCString(toFilename(p.config, tt.info)))
+              line.rope, makeCString(toFilename(p.config, t.info)))
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
-      (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
-    if freshLineInfo(p, tt.info):
+      (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIDX:
+    if freshLineInfo(p, t.info):
       linefmt(p, cpsStmts, "nimln_($1, $2);$n",
-              line.rope, quotedFilename(p.config, tt.info))
+              line.rope, quotedFilename(p.config, t.info))
 
 proc postStmtActions(p: BProc) {.inline.} =
   add(p.s(cpsStmts), p.module.injectStmt)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 64c145e51..135c1b32c 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -31,6 +31,9 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
   popInfoContext(c.config)
 
+  # XXX: A more elaborate line info rewrite might be needed
+  result.info = n.info
+
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 
 proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
diff --git a/tests/errmsgs/tproper_stacktrace.nim b/tests/errmsgs/tproper_stacktrace.nim
index 57e65fa6f..4e5c5fbf8 100644
--- a/tests/errmsgs/tproper_stacktrace.nim
+++ b/tests/errmsgs/tproper_stacktrace.nim
@@ -1,11 +1,123 @@
 discard """
-  outputsub: '''tproper_stacktrace.nim(7) tproper_stacktrace'''
-  exitcode: 1
+  output: '''ok'''
 """
+import strscans, strutils
 
-template fuzzy(x) =
-  echo x[] != 9
+proc raiseTestException*() =
+  raise newException(Exception, "test")
 
-var p: ptr int
-fuzzy p
+proc matchStackTrace(actualEntries: openarray[StackTraceEntry], expected: string) =
+  var expectedEntries = newSeq[StackTraceEntry]()
+  var i = 0
 
+  template checkEqual(actual, expected: typed, subject: string) =
+    if actual != expected:
+      echo "Unexpected ", subject, " on line ", i
+      echo "Actual: ", actual
+      echo "Expected: ", expected
+      doAssert(false)
+
+  for l in splitLines(expected.strip):
+    var procname, filename: string
+    var line: int
+    if not scanf(l, "$s$w.nim($i) $w", filename, line, procname):
+      doAssert(false, "Wrong expected stack trace")
+    checkEqual($actualEntries[i].filename, filename & ".nim", "file name")
+    if line != 0:
+      checkEqual(actualEntries[i].line, line, "line number")
+    checkEqual($actualEntries[i].procname, procname, "proc name")
+    inc i
+
+  doAssert(i == actualEntries.len, "Unexpected number of lines in stack trace")
+
+template verifyStackTrace*(expectedStackTrace: string, body: untyped) =
+  var verified = false
+  try:
+    body
+  except Exception as e:
+    verified = true
+    # echo "Stack trace:"
+    # echo e.getStackTrace
+    matchStackTrace(e.getStackTraceEntries(), expectedStackTrace)
+
+  doAssert(verified, "No exception was raised")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+when isMainModule:
+# <-- Align with line 70 in the text editor
+  block:
+    proc bar() =
+      raiseTestException()
+
+    proc foo() =
+      bar()
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(86) tproper_stacktrace
+      tproper_stacktrace.nim(76) foo
+      tproper_stacktrace.nim(73) bar
+      tproper_stacktrace.nim(7) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      foo()
+
+  block:
+    proc bar(x: int) =
+      raiseTestException()
+
+    template foo(x: int) =
+      bar(x)
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(103) tproper_stacktrace
+      tproper_stacktrace.nim(90) bar
+      tproper_stacktrace.nim(7) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      var x: int
+      foo(x)
+
+  block: #6803
+    proc bar(x = 500) =
+      raiseTestException()
+
+    proc foo() =
+      bar()
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(120) tproper_stacktrace
+      tproper_stacktrace.nim(110) foo
+      tproper_stacktrace.nim(107) bar
+      tproper_stacktrace.nim(7) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      foo()
+
+
+  echo "ok"