* fix: `var a{.foo.} = expr` inside templates
* add test
* improve tdecls test
* improve tests
* add failing test
* PRTEMP
* fixup
This commit is contained in:
parent
8540065754
commit
6c1bd4bb1c
5 changed files with 107 additions and 20 deletions
|
|
@ -453,23 +453,29 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode =
|
||||||
return nil
|
return nil
|
||||||
let nodePragma = b[1][0]
|
let nodePragma = b[1][0]
|
||||||
# see: `singlePragma`
|
# see: `singlePragma`
|
||||||
if nodePragma.kind notin {nkIdent, nkAccQuoted}:
|
|
||||||
return nil
|
var amb = false
|
||||||
|
var sym: PSym = nil
|
||||||
|
case nodePragma.kind
|
||||||
|
of nkIdent, nkAccQuoted:
|
||||||
let ident = considerQuotedIdent(c, nodePragma)
|
let ident = considerQuotedIdent(c, nodePragma)
|
||||||
var userPragma = strTableGet(c.userPragmas, ident)
|
var userPragma = strTableGet(c.userPragmas, ident)
|
||||||
if userPragma != nil: return nil
|
if userPragma != nil: return nil
|
||||||
|
|
||||||
let w = nodePragma.whichPragma
|
let w = nodePragma.whichPragma
|
||||||
if n.kind == nkVarSection and w in varPragmas or
|
if n.kind == nkVarSection and w in varPragmas or
|
||||||
n.kind == nkLetSection and w in letPragmas or
|
n.kind == nkLetSection and w in letPragmas or
|
||||||
n.kind == nkConstSection and w in constPragmas:
|
n.kind == nkConstSection and w in constPragmas:
|
||||||
return nil
|
return nil
|
||||||
|
sym = searchInScopes(c, ident, amb)
|
||||||
var amb = false
|
|
||||||
let sym = searchInScopes(c, ident, amb)
|
|
||||||
# XXX what if amb is true?
|
# 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
|
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.}`
|
# skip if not in scope; skip `template myAttr() {.pragma.}`
|
||||||
|
|
||||||
let lhs = b[0]
|
let lhs = b[0]
|
||||||
let clash = strTableGet(c.currentScope.symbols, lhs.ident)
|
let clash = strTableGet(c.currentScope.symbols, lhs.ident)
|
||||||
if clash != nil:
|
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)
|
wrongRedefinition(c, lhs.info, lhs.ident.s, clash.info)
|
||||||
|
|
||||||
result = newTree(nkCall)
|
result = newTree(nkCall)
|
||||||
doAssert nodePragma.kind in {nkIdent, nkAccQuoted}, $nodePragma.kind
|
|
||||||
result.add nodePragma
|
result.add nodePragma
|
||||||
result.add lhs
|
result.add lhs
|
||||||
if a[1].kind != nkEmpty:
|
if a[1].kind != nkEmpty:
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||||
if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
|
if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
|
||||||
let pragmaNode = n[1]
|
let pragmaNode = n[1]
|
||||||
for i in 0..<pragmaNode.len:
|
for i in 0..<pragmaNode.len:
|
||||||
|
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)
|
openScope(c)
|
||||||
pragmaNode[i] = semTemplBody(c, pragmaNode[i])
|
pragmaNode[i] = semTemplBody(c, pragmaNode[i])
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,55 @@ block:
|
||||||
static: doAssert defined(tpragmas_misc_def)
|
static: doAssert defined(tpragmas_misc_def)
|
||||||
{.undef(tpragmas_misc_def).}
|
{.undef(tpragmas_misc_def).}
|
||||||
static: doAssert not defined(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()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
discard """
|
||||||
|
targets: "c cpp js"
|
||||||
|
"""
|
||||||
|
|
||||||
import std/decls
|
import std/decls
|
||||||
|
|
||||||
block:
|
template fun() =
|
||||||
var s = @[10,11,12]
|
var s = @[10,11,12]
|
||||||
var a {.byaddr.} = s[0]
|
var a {.byaddr.} = s[0]
|
||||||
a+=100
|
a+=100
|
||||||
|
|
@ -34,6 +38,13 @@ block:
|
||||||
doAssert compiles(block:
|
doAssert compiles(block:
|
||||||
var b2 {.byaddr.}: int = s[2])
|
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
|
## We can define custom pragmas in user code
|
||||||
template byUnsafeAddr(lhs, typ, expr) =
|
template byUnsafeAddr(lhs, typ, expr) =
|
||||||
when typ is type(nil):
|
when typ is type(nil):
|
||||||
|
|
@ -68,3 +79,13 @@ block: # nkAccQuoted
|
||||||
let a {.`cast`.} = s[0]
|
let a {.`cast`.} = s[0]
|
||||||
doAssert a == "foo"
|
doAssert a == "foo"
|
||||||
doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
|
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
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,6 @@ since (99, 3):
|
||||||
doAssert false
|
doAssert false
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
# pending https://github.com/timotheecour/Nim/issues/129
|
# pending bug #15920
|
||||||
# Error: cannot attach a custom pragma to 'fun3'
|
# Error: cannot attach a custom pragma to 'fun3'
|
||||||
template fun3(): int {.since: (1, 3).} = 12
|
template fun3(): int {.since: (1, 3).} = 12
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue