mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +00:00
process non-language pragma nodes in templates (#24183)
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](a27542195c/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. (cherry picked from commit911cef1621)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
28
tests/template/tpragma.nim
Normal file
28
tests/template/tpragma.nim
Normal file
@@ -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()
|
||||
Reference in New Issue
Block a user