Skip to content

Commit

Permalink
only merge valid implicit pragmas to routine AST, include templates (#…
Browse files Browse the repository at this point in the history
…24171)

fixes #19277, refs #24169, refs #18124

When pragmas are pushed to a routine, if the routine symbol AST isn't
nil by the time the pushed pragmas are being processed, the pragmas are
implicitly added to the symbol AST. However this is done without
restriction on the pragma, if the pushed pragma isn't supposed to apply
to the routine, it's still added to the routine. This is why the symbol
AST for templates wasn't set before the pushed pragma processing in
#18124. Now, the pragmas added to the AST are restricted to ones that
apply to the given routine. This means we can set the template symbol
AST earlier so that the pragmas get added to the template AST.
  • Loading branch information
metagn authored Sep 26, 2024
1 parent 69b2a6e commit a275421
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 6 deletions.
13 changes: 12 additions & 1 deletion compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,16 @@ proc mergePragmas(n, pragmas: PNode) =
else:
for p in pragmas: n[pragmasPos].add p

proc mergeValidPragmas(n, pragmas: PNode, validPragmas: TSpecialWords) =
if n[pragmasPos].kind == nkEmpty:
n[pragmasPos] = newNodeI(nkPragma, n.info)
for p in pragmas:
let prag = whichPragma(p)
if prag in validPragmas:
let copy = copyTree(p)
overwriteLineInfo copy, n.info
n[pragmasPos].add copy

proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
validPragmas: TSpecialWords) =
if sym != nil and sym.kind != skModule:
Expand All @@ -1357,7 +1367,8 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
internalError(c.config, info, "implicitPragmas")
inc i
popInfoContext(c.config)
if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
if sym.kind in routineKinds and sym.ast != nil:
mergeValidPragmas(sym.ast, o, validPragmas)

if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(c.config, info, ".dynlib requires .exportc")
Expand Down
6 changes: 1 addition & 5 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
pushOwner(c, s)
openScope(c)
n[namePos] = newSymNode(s)
s.ast = n # for implicitPragmas to use
pragmaCallable(c, s, n, templatePragmas)
implicitPragmas(c, s, n.info, templatePragmas)

Expand Down Expand Up @@ -763,11 +764,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
closeScope(c)
popOwner(c)

# set the symbol AST after pragmas, at least. This stops pragma that have
# been pushed (implicit) to be explicitly added to the template definition
# and misapplied to the body. see #18113
s.ast = n

if sfCustomPragma in s.flags:
if n[bodyPos].kind != nkEmpty:
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
Expand Down
12 changes: 12 additions & 0 deletions tests/pragmas/tpush.nim
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,20 @@ foo41()

{.pop.}

import macros

block:
{.push deprecated.}
template test() = discard
test()
{.pop.}
macro foo(): bool =
let ast = getImpl(bindSym"test")
var found = false
if ast[4].kind == nnkPragma:
for x in ast[4]:
if x.eqIdent"deprecated":
found = true
break
result = newLit(found)
doAssert foo()
2 changes: 2 additions & 0 deletions tests/template/m19277_1.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
template foo*(x: untyped) =
echo "got: ", x
2 changes: 2 additions & 0 deletions tests/template/m19277_2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
proc foo*(a: string) =
echo "got string: ", a
19 changes: 19 additions & 0 deletions tests/template/t19277.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
discard """
output: '''
got: 0
'''
"""

# issue #19277

import m19277_1, m19277_2

template injector(val: untyped): untyped =
template subtemplate: untyped = val
subtemplate()

template methodCall(val: untyped): untyped = val

{.push raises: [Defect].}

foo(injector(0).methodCall())

0 comments on commit a275421

Please sign in to comment.