summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semtempl.nim12
-rw-r--r--doc/manual.md9
-rw-r--r--tests/errmsgs/tinconsistentgensym.nim2
-rw-r--r--tests/template/tinnerouterproc.nim12
4 files changed, 26 insertions, 9 deletions
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index f2083c85c..c6f2fb60c 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -256,25 +256,27 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
     if not isField:
       styleCheckUse(c, n.info, s)
 
-proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
+proc semRoutineInTemplName(c: var TemplCtx, n: PNode, explicitInject: bool): PNode =
   result = n
   if n.kind == nkIdent:
     let s = qualifiedLookUp(c.c, n, {})
     if s != nil:
-      if s.owner == c.owner and s.kind == skParam:
+      if s.owner == c.owner and (s.kind == skParam or
+          (sfGenSym in s.flags and not explicitInject)):
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
         onUse(n.info, s)
   else:
     for i in 0..<n.safeLen:
-      result[i] = semRoutineInTemplName(c, n[i])
+      result[i] = semRoutineInTemplName(c, n[i], explicitInject)
 
 proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
   result = n
   checkSonsLen(n, bodyPos + 1, c.c.config)
   if n.kind notin nkLambdaKinds:
     # routines default to 'inject':
-    if symBinding(n[pragmasPos]) == spGenSym:
+    let binding = symBinding(n[pragmasPos])
+    if binding == spGenSym:
       let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
       if not hasParam:
         var s = newGenSym(k, ident, c)
@@ -286,7 +288,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
       else:
         n[namePos] = ident
     else:
-      n[namePos] = semRoutineInTemplName(c, n[namePos])
+      n[namePos] = semRoutineInTemplName(c, n[namePos], binding == spInject)
   # open scope for parameters
   openScope(c)
   for i in patternPos..paramsPos-1:
diff --git a/doc/manual.md b/doc/manual.md
index 16c116328..e471658a4 100644
--- a/doc/manual.md
+++ b/doc/manual.md
@@ -6216,9 +6216,12 @@ scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas:
 `gensym`'ed symbols are not exposed but `inject`'ed symbols are.
 
 The default for symbols of entity `type`, `var`, `let` and `const`
-is `gensym` and for `proc`, `iterator`, `converter`, `template`,
-`macro` is `inject`. However, if the name of the entity is passed as a
-template parameter, it is an `inject`'ed symbol:
+is `gensym`. For `proc`, `iterator`, `converter`, `template`,
+`macro`, the default is `inject`, but if a `gensym` symbol with the same name
+is defined in the same syntax-level scope, it will be `gensym` by default.
+This can be overriden by marking the routine as `inject`. 
+
+If the name of the entity is passed as a template parameter, it is an `inject`'ed symbol:
 
   ```nim
   template withFile(f, fn, mode: untyped, actions: untyped): untyped =
diff --git a/tests/errmsgs/tinconsistentgensym.nim b/tests/errmsgs/tinconsistentgensym.nim
index 026c17fca..8e4c85106 100644
--- a/tests/errmsgs/tinconsistentgensym.nim
+++ b/tests/errmsgs/tinconsistentgensym.nim
@@ -7,7 +7,7 @@ block:
     when false:
       let x = 123
     else:
-      template x: untyped = 456
+      template x: untyped {.inject.} = 456
     echo x #[tt.Error
          ^ undeclared identifier: 'x`gensym0'; if declared in a template, this identifier may be inconsistently marked inject or gensym]#
   foo()
diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim
index 1f15fb13e..56e0d02df 100644
--- a/tests/template/tinnerouterproc.nim
+++ b/tests/template/tinnerouterproc.nim
@@ -6,3 +6,15 @@ block: # #20002
     discard 3.bar # evaluates to 10 but only check if it compiles for now
   block:
     foo()
+
+block: # issue #23813
+  template r(body: untyped) =
+    proc x() {.gensym.} =
+      body
+  template g() =
+    r:
+      let y = 0
+    r:
+      proc y() = discard
+      y()
+  g()