summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semstmts.nim35
-rw-r--r--compiler/semtempl.nim15
-rw-r--r--tests/pragmas/tpragmas_misc.nim52
-rw-r--r--tests/stdlib/tdecls.nim23
-rw-r--r--tests/stdlib/tsince.nim2
5 files changed, 107 insertions, 20 deletions
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index cc09291c5..14dc89781 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -453,23 +453,29 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode =
       return nil
     let nodePragma = b[1][0]
     # see: `singlePragma`
-    if nodePragma.kind notin {nkIdent, nkAccQuoted}:
-      return nil
-    let ident = considerQuotedIdent(c, nodePragma)
-    var userPragma = strTableGet(c.userPragmas, ident)
-    if userPragma != nil: return nil
-
-    let w = nodePragma.whichPragma
-    if n.kind == nkVarSection and w in varPragmas or
-      n.kind == nkLetSection and w in letPragmas or
-      n.kind == nkConstSection and w in constPragmas:
-      return nil
 
     var amb = false
-    let sym = searchInScopes(c, ident, amb)
-    # XXX what if amb is true?
-    if sym == nil or sfCustomPragma in sym.flags: return nil
+    var sym: PSym = nil
+    case nodePragma.kind
+    of nkIdent, nkAccQuoted:
+      let ident = considerQuotedIdent(c, nodePragma)
+      var userPragma = strTableGet(c.userPragmas, ident)
+      if userPragma != nil: return nil
+      let w = nodePragma.whichPragma
+      if n.kind == nkVarSection and w in varPragmas or
+        n.kind == nkLetSection and w in letPragmas or
+        n.kind == nkConstSection and w in constPragmas:
+        return nil
+      sym = searchInScopes(c, ident, amb)
+      # XXX what if amb is true?
+      # CHECKME: should that test also apply to `nkSym` case?
+      if sym == nil or sfCustomPragma in sym.flags: return nil
+    of nkSym:
+      sym = nodePragma.sym
+    else:
+      return nil
       # skip if not in scope; skip `template myAttr() {.pragma.}`
+
     let lhs = b[0]
     let clash = strTableGet(c.currentScope.symbols, lhs.ident)
     if clash != nil:
@@ -477,7 +483,6 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode =
       wrongRedefinition(c, lhs.info, lhs.ident.s, clash.info)
 
     result = newTree(nkCall)
-    doAssert nodePragma.kind in {nkIdent, nkAccQuoted}, $nodePragma.kind
     result.add nodePragma
     result.add lhs
     if a[1].kind != nkEmpty:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index a2b0f99ba..2636784af 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -208,9 +208,18 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
     if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
       let pragmaNode = n[1]
       for i in 0..<pragmaNode.len:
-        openScope(c)
-        pragmaNode[i] = semTemplBody(c, pragmaNode[i])
-        closeScope(c)
+        let ni = pragmaNode[i]
+        # see D20210801T100514
+        var found = false
+        if ni.kind == nkIdent:
+          for a in templatePragmas:
+            if ni.ident == getIdent(c.c.cache, $a):
+              found = true
+              break
+        if not found:
+          openScope(c)
+          pragmaNode[i] = semTemplBody(c, pragmaNode[i])
+          closeScope(c)
     let ident = getIdentNode(c, n)
     if not isTemplParam(c, ident):
       if n.kind != nkSym:
diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim
index 247fa471e..8cab74053 100644
--- a/tests/pragmas/tpragmas_misc.nim
+++ b/tests/pragmas/tpragmas_misc.nim
@@ -10,3 +10,55 @@ block:
   static: doAssert defined(tpragmas_misc_def)
   {.undef(tpragmas_misc_def).}
   static: doAssert not defined(tpragmas_misc_def)
+
+block: # (partial fix) bug #15920
+  block: # var template pragmas don't work in templates
+    template foo(lhs, typ, expr) =
+      let lhs = expr
+    proc fun1()=
+      let a {.foo.} = 1
+    template fun2()=
+      let a {.foo.} = 1
+    fun1() # ok
+    fun2() # WAS bug
+
+  template foo2() = discard # distractor (template or other symbol kind)
+  block:
+    template foo2(lhs, typ, expr) =
+      let lhs = expr
+    proc fun1()=
+      let a {.foo2.} = 1
+    template fun2()=
+      let a {.foo2.} = 1
+    fun1() # ok
+    when false: # bug: Error: invalid pragma: foo2
+      fun2()
+
+  block: # proc template pragmas don't work in templates
+    # adapted from $nim/lib/std/private/since.nim
+    # case without overload
+    template since3(version: (int, int), body: untyped) {.dirty.} =
+      when (NimMajor, NimMinor) >= version:
+        body
+    when false: # bug
+      template fun3(): int {.since3: (1, 3).} = 12
+
+  block: # ditto, w
+    # case with overload
+    template since2(version: (int, int), body: untyped) {.dirty.} =
+      when (NimMajor, NimMinor) >= version:
+        body
+    template since2(version: (int, int, int), body: untyped) {.dirty.} =
+      when (NimMajor, NimMinor, NimPatch) >= version:
+        body
+    when false: # bug
+      template fun3(): int {.since2: (1, 3).} = 12
+
+when true: # D20210801T100514:here
+  from macros import genSym
+  block:
+    template fn() =
+      var ret {.gensym.}: int # must special case template pragmas so it doesn't get confused
+      discard ret
+    fn()
+    static: discard genSym()
diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim
index 3567639e0..53e070bee 100644
--- a/tests/stdlib/tdecls.nim
+++ b/tests/stdlib/tdecls.nim
@@ -1,6 +1,10 @@
+discard """
+  targets: "c cpp js"
+"""
+
 import std/decls
 
-block:
+template fun() =
   var s = @[10,11,12]
   var a {.byaddr.} = s[0]
   a+=100
@@ -34,6 +38,13 @@ block:
   doAssert compiles(block:
     var b2 {.byaddr.}: int = s[2])
 
+proc fun2() = fun()
+fun()
+fun2()
+static: fun2()
+when false: # pending bug #13887
+  static: fun()
+
 ## We can define custom pragmas in user code
 template byUnsafeAddr(lhs, typ, expr) =
   when typ is type(nil):
@@ -68,3 +79,13 @@ block: # nkAccQuoted
     let a {.`cast`.} = s[0]
     doAssert a == "foo"
     doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
+
+block: # bug #15920
+  template foo(lhs, typ, expr) =
+    let lhs = expr
+  proc fun1()=
+    let a {.foo.} = 1
+  template fun2()=
+    let a {.foo.} = 1
+  fun1() # ok
+  fun2() # BUG
diff --git a/tests/stdlib/tsince.nim b/tests/stdlib/tsince.nim
index 14dd09c15..d0320ff12 100644
--- a/tests/stdlib/tsince.nim
+++ b/tests/stdlib/tsince.nim
@@ -27,6 +27,6 @@ since (99, 3):
   doAssert false
 
 when false:
-  # pending https://github.com/timotheecour/Nim/issues/129
+  # pending bug #15920
   # Error: cannot attach a custom pragma to 'fun3'
   template fun3(): int {.since: (1, 3).} = 12