Skip to content

Commit

Permalink
process non-language pragma nodes in templates (#24183)
Browse files Browse the repository at this point in the history
fixes #24186 

When encountering pragma nodes in templates, if it's a language pragma,
we don't process the name, and only any values if they exist. If it's
not a language pragma, we process the full node. Previously only the
values of colon expressions were processed.

To make this simpler, `whichPragma` is patched to consider bracketed
hint/warning etc pragmas like `{.hint[HintName]: off.}` as being a
pragma of kind `wHint` rather than an invalid pragma which would have to
be checked separately. From looking at the uses of `whichPragma` this
doesn't seem like it would cause problems.

Generics have [the same
problem](https://github.com/nim-lang/Nim/blob/a27542195c9ba760d58e9d1e977313bc322a1ede/compiler/semgnrc.nim#L619)
(causing #18649), but to make it work we need to make sure the
templates/macros don't get evaluated or get evaluated correctly (i.e.
passing the proc node as the final argument), either with #23094 or by
completely disabling template/macro evaluation when processing the
pragma node, which would also cover `{.pragma.}` templates.
  • Loading branch information
metagn authored Oct 7, 2024
1 parent ea9811a commit 911cef1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
15 changes: 11 additions & 4 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -535,13 +535,20 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkConverterDef:
result = semRoutineInTemplBody(c, n, skConverter)
of nkPragmaExpr:
result[0] = semTemplBody(c, n[0])
result = semTemplBodySons(c, n)
of nkPostfix:
result[1] = semTemplBody(c, n[1])
of nkPragma:
for x in n:
if x.kind == nkExprColonExpr:
x[1] = semTemplBody(c, x[1])
for i in 0 ..< n.len:
let x = n[i]
let prag = whichPragma(x)
if prag == wInvalid:
# only sem if not a language-level pragma
result[i] = semTemplBody(c, x)
elif x.kind in nkPragmaCallKinds:
# is pragma, but value still needs to be checked
for j in 1 ..< x.len:
x[j] = semTemplBody(c, x[j])
of nkBracketExpr:
if n.typ == nil:
# if a[b] is nested inside a typed expression, don't convert it
Expand Down
7 changes: 7 additions & 0 deletions compiler/trees.nim
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ proc whichPragma*(n: PNode): TSpecialWord =
of nkCast: return wCast
of nkClosedSymChoice, nkOpenSymChoice:
return whichPragma(key[0])
of nkBracketExpr:
if n.kind notin nkPragmaCallKinds: return wInvalid
result = whichPragma(key[0])
if result notin {wHint, wHintAsError, wWarning, wWarningAsError}:
# note bracket pragmas, see processNote
result = wInvalid
return
else: return wInvalid
if result in nonPragmaWordsLow..nonPragmaWordsHigh:
result = wInvalid
Expand Down
28 changes: 28 additions & 0 deletions tests/template/tpragma.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# issue #24186

macro mymacro(typ: typedesc; def) =
def

macro mymacro2(typ: typedesc; typ2: typedesc; def) =
def

template mytemplate(typ: typedesc) = # works
proc myproc() {.mymacro: typ .} =
discard

template mytemplate2(typ: typedesc) = # Error: undeclared identifier: 'typ'
proc myproc2() {.mymacro(typ) .} =
discard

template mytemplate3(typ: typedesc, typ2: typedesc) = # Error: undeclared identifier: 'typ'
proc myproc3() {.mymacro2(typ, typ2) .} =
discard

template mytemplate4() = # works
proc myproc4() {.mymacro2(string, int) .} =
discard

mytemplate(string)
mytemplate2(string)
mytemplate3(string, int)
mytemplate4()

0 comments on commit 911cef1

Please sign in to comment.