summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorLemonBoy <LemonBoy@users.noreply.github.com>2019-02-18 12:17:00 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-02-18 12:17:00 +0100
commitcf32d61fa5084ce0f8577fd7e52c8d2070188462 (patch)
treec5134ef6b029e94841165ceb90a85e96a220261e
parent8b39551fca81e95b51393a2a8e702eebe3ba7c51 (diff)
downloadNim-cf32d61fa5084ce0f8577fd7e52c8d2070188462.tar.gz
Prevent crash on pragma templates w/ generics (#10685)
* Prevent crash on pragma templates w/ generics

* Remove incorrect call to pragma reconversion

`semOverloadedCall` may return a node with more elements than the
original nkCall node had (implicit and/or explicit generics).
-rw-r--r--compiler/pragmas.nim28
-rw-r--r--lib/core/macros.nim2
-rw-r--r--tests/pragmas/tcustom_pragma.nim7
3 files changed, 26 insertions, 11 deletions
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index f88035a07..3eedf15a9 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -719,26 +719,34 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
     result = qualifiedLookUp(c, n, {checkUndeclared})
 
 proc semCustomPragma(c: PContext, n: PNode): PNode =
+  var callNode: PNode
+
   if n.kind == nkIdent:
-    result = newTree(nkCall, n)
+    # pragma -> pragma()
+    callNode = newTree(nkCall, n)
   elif n.kind == nkExprColonExpr:
     # pragma: arg -> pragma(arg)
-    result = newTree(nkCall, n[0], n[1])
+    callNode = newTree(nkCall, n[0], n[1])
   elif n.kind in nkPragmaCallKinds:
-    result = n
+    callNode = n
   else:
     invalidPragma(c, n)
     return n
 
-  let r = c.semOverloadedCall(c, result, n, {skTemplate}, {efNoUndeclared})
+  let r = c.semOverloadedCall(c, callNode, n, {skTemplate}, {efNoUndeclared})
+
   if r.isNil or sfCustomPragma notin r[0].sym.flags:
     invalidPragma(c, n)
-  else:
-    result = r
-    if n.kind == nkIdent:
-      result = result[0]
-    elif n.kind == nkExprColonExpr:
-      result.kind = n.kind # pragma(arg) -> pragma: arg
+    return n
+
+  result = r
+  # Transform the nkCall node back to its original form if possible
+  if n.kind == nkIdent and r.len == 1:
+    # pragma() -> pragma
+    result = result[0]
+  elif n.kind == nkExprColonExpr and r.len == 2:
+    # pragma(arg) -> pragma: arg
+    result.kind = n.kind
 
 proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
                   validPragmas: TSpecialWords, comesFromPush: bool) : bool =
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 43e61d660..7ec1eefc6 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1515,7 +1515,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
       else:
         let def = p[0].getImpl[3]
         result = newTree(nnkPar)
-        for i in 1..<p.len:
+        for i in 1 ..< def.len:
           let key = def[i][0]
           let val = p[i]
           result.add newTree(nnkExprColonExpr, key, val)
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
index 0dc85cf67..9f2fc024b 100644
--- a/tests/pragmas/tcustom_pragma.nim
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -233,3 +233,10 @@ block:
   doAssert ps.first == ps[0] and ps.first == "one"
   doAssert ps.second == ps[1] and ps.second == 2
   doAssert ps.third == ps[2] and ps.third == 3.0
+
+# pragma with implicit&explicit generic types
+block:
+  template fooBar[T](x: T; c: static[int] = 42; m: char) {.pragma.}
+  var e {.fooBar("foo", 123, 'u').}: int
+  doAssert(hasCustomPragma(e, fooBar))
+  doAssert(getCustomPragmaVal(e, fooBar).c == 123)