summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/evaltempl.nim2
-rw-r--r--compiler/semexprs.nim1
-rw-r--r--compiler/semtempl.nim33
-rw-r--r--lib/pure/pegs.nim7
-rw-r--r--tests/template/tparams_gensymed.nim31
6 files changed, 62 insertions, 15 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index db0321f6c..f3012cd8a 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -228,7 +228,7 @@ type
   TNodeKinds* = set[TNodeKind]
 
 type
-  TSymFlag* = enum    # already 36 flags!
+  TSymFlag* = enum    # already 38 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
     sfFromGeneric,    # symbol is instantiation of a generic; this is needed
@@ -282,6 +282,7 @@ type
     sfGeneratedOp     # proc is a generated '='; do not inject destructors in it
                       # variable is generated closure environment; requires early
                       # destruction for --newruntime.
+    sfTemplateParam   # symbol is a template parameter
 
 
   TSymFlags* = set[TSymFlag]
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index d941f6c46..8ac7d82be 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -38,7 +38,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
   of nkSym:
     var s = templ.sym
     if (s.owner == nil and s.kind == skParam) or s.owner == c.owner:
-      if s.kind == skParam and sfGenSym notin s.flags:
+      if s.kind == skParam and {sfGenSym, sfTemplateParam} * s.flags == {sfTemplateParam}:
         handleParam actual.sons[s.position]
       elif (s.owner != nil) and (s.kind == skGenericParam or
            s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 2d33c742b..1785ae143 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1896,7 +1896,6 @@ proc expectString(c: PContext, n: PNode): string =
 
 proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym =
   result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info)
-  result.flags = {sfGenSym}
 
 proc semExpandToAst(c: PContext, n: PNode): PNode =
   let macroCall = n[1]
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index acf32d1b3..9f39a81ee 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -125,6 +125,7 @@ type
     cursorInBody: bool # only for nimsuggest
     scopeN: int
     noGenSym: int
+    inTemplateHeader: int
 
 template withBracketExpr(ctx, x, body: untyped) =
   body
@@ -144,9 +145,12 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
     illFormedAst(n, c.c.config)
     result = n
 
+template oldCheck(cx: TemplCtx; cond: bool): bool =
+  (optNimV019 notin cx.c.config.globalOptions or cond)
+
 proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
   result = n.kind == nkSym and n.sym.kind == skParam and
-           n.sym.owner == c.owner and sfGenSym notin n.sym.flags
+           n.sym.owner == c.owner and sfTemplateParam in n.sym.flags
 
 proc semTemplBody(c: var TemplCtx, n: PNode): PNode
 
@@ -231,6 +235,8 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
         styleCheckDef(c.c.config, n.info, local)
         onDef(n.info, local)
         replaceIdentBySym(c.c, n, newSymNode(local, n.info))
+        if k == skParam and c.inTemplateHeader > 0:
+          local.flags.incl sfTemplateParam
     else:
       replaceIdentBySym(c.c, n, ident)
 
@@ -288,7 +294,14 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
     n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos])
   # open scope for parameters
   openScope(c)
-  for i in patternPos..miscPos:
+  for i in patternPos..paramsPos-1:
+    n.sons[i] = semTemplBody(c, n.sons[i])
+
+  if k == skTemplate: inc(c.inTemplateHeader)
+  n.sons[paramsPos] = semTemplBody(c, n.sons[paramsPos])
+  if k == skTemplate: dec(c.inTemplateHeader)
+
+  for i in paramsPos+1..miscPos:
     n.sons[i] = semTemplBody(c, n.sons[i])
   # open scope for locals
   inc c.scopeN
@@ -331,8 +344,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     if n.ident.id in c.toInject: return n
     let s = qualifiedLookUp(c.c, n, {})
     if s != nil:
-      if s.owner == c.owner and s.kind == skParam and
-          (sfGenSym notin s.flags or c.noGenSym == 0):
+      if s.owner == c.owner and s.kind == skParam and sfTemplateParam in s.flags:
+        # oldCheck(c, sfGenSym notin s.flags or c.noGenSym == 0):
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
         onUse(n.info, s)
@@ -542,16 +555,16 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     if n.kind == nkDotExpr:
       result = n
       result.sons[0] = semTemplBody(c, n.sons[0])
-      inc c.noGenSym
+      if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym
       result.sons[1] = semTemplBody(c, n.sons[1])
-      dec c.noGenSym
+      if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym
     else:
       result = semTemplBodySons(c, n)
   of nkExprColonExpr, nkExprEqExpr:
     if n.len == 2:
-      inc c.noGenSym
+      if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym
       result.sons[0] = semTemplBody(c, n.sons[0])
-      dec c.noGenSym
+      if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym
       result.sons[1] = semTemplBody(c, n.sons[1])
     else:
       result = semTemplBodySons(c, n)
@@ -625,7 +638,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
     # body by the absence of the sfGenSym flag:
     for i in 1 .. s.typ.n.len-1:
       let param = s.typ.n.sons[i].sym
-      param.flags.excl sfGenSym
+      param.flags.incl sfTemplateParam
+      if optNimV019 in c.config.globalOptions:
+        param.flags.excl sfGenSym
       if param.typ.kind != tyUntyped: allUntyped = false
     if sonsLen(gp) > 0:
       if n.sons[genericParamsPos].kind == nkEmpty:
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 844fbd13c..7ce65b438 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -890,12 +890,13 @@ macro mkHandlerTplts(handlers: untyped): untyped =
   #           <handler code block>
   #   ...
   proc mkEnter(hdName, body: NimNode): NimNode =
-    quote do:
-      template `hdName`(s, p, start) =
+    template helper(hdName, body) {.dirty.} =
+      template hdName(s, p, start) =
         let s {.inject.} = s
         let p {.inject.} = p
         let start {.inject.} = start
-        `body`
+        body
+    result = getAst(helper(hdName, body))
 
   template mkLeave(hdPostf, body) {.dirty.} =
     # this has to be dirty to be able to capture *result* as *length* in
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
index fe5608add..a35d878d5 100644
--- a/tests/template/tparams_gensymed.nim
+++ b/tests/template/tparams_gensymed.nim
@@ -14,6 +14,7 @@ wth
 1
 0
 (total: 6)
+S1
 '''
 """
 # bug #1915
@@ -164,3 +165,33 @@ template baz(): untyped =
   echo (total: bar2(3))
 
 baz()
+
+# bug #12121
+macro state_machine_enum(states: varargs[untyped]) =
+  result = nnkTypeSection.newTree(
+    nnkTypeDef.newTree(
+      nnkPragmaExpr.newTree(ident("State"), nnkPragma.newTree(ident("pure"))),
+      newEmptyNode(),
+      nnkEnumTy.newTree(newEmptyNode())
+    )
+  )
+
+  for s in states:
+    expectKind(s, nnkIdent)
+    result[0][2].add s
+
+template mystate_machine(body: untyped) =
+  state_machine_enum(S1, S2, S3)
+  var state_stack: seq[State]
+  template state_current(): State {.inject, used.} =
+    state_stack[^1]
+  template state_push(state_name) {.inject, used.} =
+    state_stack.add State.state_name
+  template state_pop(n = 1) {.inject, used.} =
+    state_stack.setLen(state_stack.len - n)
+  body
+
+mystate_machine:
+  state_push(S1)
+  echo state_current()
+  state_pop()