mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 14:23:45 +00:00
don't transform typed bracket exprs to [] calls in templates (#23175)
fixes #22775 It's pre-existing that [`prepareOperand` doesn't typecheck expressions which have types](a4f3bf3742/compiler/sigmatch.nim (L2444)). Templates can take typed subscript expressions, transform them into calls to `[]`, and then have this `[]` not be resolved later if the expression is nested inside of a call argument, which leaks an untyped expression past semantic analysis. To prevent this, don't transform any typed subscript expressions into calls to `[]` in templates. Ditto for curly subscripts (with `{}`) and assignments to subscripts and curly subscripts (with `[]=` and `{}=`). (cherry picked from commit62d8ca4306)
This commit is contained in:
@@ -506,14 +506,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
if x.kind == nkExprColonExpr:
|
||||
x[1] = semTemplBody(c, x[1])
|
||||
of nkBracketExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
|
||||
for i in 0..<n.len: result.add(n[i])
|
||||
if n.typ == nil:
|
||||
# if a[b] is nested inside a typed expression, don't convert it
|
||||
# back to `[]`(a, b), prepareOperand will not typecheck it again
|
||||
# and so `[]` will not be resolved
|
||||
# checking if a[b] is typed should be enough to cover this case
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
|
||||
for i in 0..<n.len: result.add(n[i])
|
||||
result = semTemplBodySons(c, result)
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
|
||||
for i in 0..<n.len: result.add(n[i])
|
||||
if n.typ == nil:
|
||||
# see nkBracketExpr case for explanation
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
|
||||
for i in 0..<n.len: result.add(n[i])
|
||||
result = semTemplBodySons(c, result)
|
||||
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
||||
checkSonsLen(n, 2, c.c.config)
|
||||
@@ -523,17 +530,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
let k = a.kind
|
||||
case k
|
||||
of nkBracketExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
|
||||
for i in 0..<a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
if a.typ == nil:
|
||||
# see nkBracketExpr case above for explanation
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
|
||||
for i in 0..<a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
let a0 = semTemplBody(c, a[0])
|
||||
result = semTemplBodySons(c, result)
|
||||
of nkCurlyExpr:
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
|
||||
for i in 0..<a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
if a.typ == nil:
|
||||
# see nkBracketExpr case above for explanation
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
|
||||
for i in 0..<a.len: result.add(a[i])
|
||||
result.add(b)
|
||||
result = semTemplBodySons(c, result)
|
||||
else:
|
||||
result = semTemplBodySons(c, n)
|
||||
|
||||
38
tests/template/tnested.nim
Normal file
38
tests/template/tnested.nim
Normal file
@@ -0,0 +1,38 @@
|
||||
block: # issue #22775
|
||||
proc h(c: int) = discard
|
||||
template k(v: int) =
|
||||
template p() = v.h()
|
||||
p()
|
||||
let a = @[0]
|
||||
k(0 and not a[0])
|
||||
|
||||
block: # issue #22775 case 2
|
||||
proc h(c: int, q: int) = discard
|
||||
template k(v: int) =
|
||||
template p() = h(v, v)
|
||||
p()
|
||||
let a = [0]
|
||||
k(0 and not a[0])
|
||||
|
||||
block: # issue #22775 minimal cases
|
||||
proc h(c: int) = discard
|
||||
template k(v: int) =
|
||||
template p() = h(v)
|
||||
p()
|
||||
let a = [0]
|
||||
k(not a[0])
|
||||
block:
|
||||
k(-a[0])
|
||||
block:
|
||||
proc f(x: int): int = x
|
||||
k(f a[0])
|
||||
|
||||
block: # bracket assignment case of above tests
|
||||
proc h(c: int) = discard
|
||||
template k(v: int) =
|
||||
template p() = h(v)
|
||||
p()
|
||||
var a = [0]
|
||||
k(not (block:
|
||||
a[0] = 1
|
||||
1))
|
||||
Reference in New Issue
Block a user