only merge valid implicit pragmas to routine AST, include templates (#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.
This commit is contained in:
metagn
2024-09-26 07:34:50 +03:00
committed by GitHub
parent 69b2a6effc
commit a27542195c
6 changed files with 48 additions and 6 deletions

View File

@@ -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:
@@ -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")

View File

@@ -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)
@@ -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)

View File

@@ -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()

View File

@@ -0,0 +1,2 @@
template foo*(x: untyped) =
echo "got: ", x

View File

@@ -0,0 +1,2 @@
proc foo*(a: string) =
echo "got string: ", a

19
tests/template/t19277.nim Normal file
View File

@@ -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())