summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md3
-rw-r--r--compiler/ast.nim21
-rw-r--r--compiler/ccgexprs.nim6
-rw-r--r--compiler/ccgliterals.nim2
-rw-r--r--compiler/guards.nim2
-rw-r--r--compiler/injectdestructors.nim6
-rw-r--r--compiler/jsgen.nim6
-rw-r--r--compiler/parampatterns.nim2
-rw-r--r--compiler/patterns.nim2
-rw-r--r--compiler/pragmas.nim6
-rw-r--r--compiler/semcall.nim4
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semfold.nim8
-rw-r--r--compiler/sempass2.nim9
-rw-r--r--compiler/semstmts.nim45
-rw-r--r--compiler/sighashes.nim2
-rw-r--r--compiler/suggest.nim10
-rw-r--r--compiler/transf.nim10
-rw-r--r--compiler/vmgen.nim2
-rw-r--r--lib/core/macros.nim2
-rw-r--r--tests/deprecated/tconst.nim8
-rw-r--r--tests/macros/t19766_20114.nim16
-rw-r--r--tests/macros/tgetimpl.nim2
-rw-r--r--tests/pragmas/tcustom_pragma.nim40
-rw-r--r--tests/trmacros/tnorewrite.nim20
-rw-r--r--tests/trmacros/trmacros_various.nim3
26 files changed, 176 insertions, 65 deletions
diff --git a/changelog.md b/changelog.md
index 6d4ccd4b0..7d52b289c 100644
--- a/changelog.md
+++ b/changelog.md
@@ -51,6 +51,9 @@
 
 - Static linking against OpenSSL versions below 1.1, previously done by
   setting `-d:openssl10`, is no longer supported.
+  
+- `macros.getImpl` for `const` symbols now returns the full definition node
+  (as `nnkConstDef`) rather than the AST of the constant value.
 
 - ORC is now the default memory management strategy. Use
   `--mm:refc` for a transition period.
diff --git a/compiler/ast.nim b/compiler/ast.nim
index f81dc443d..399d7e561 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1233,6 +1233,25 @@ proc getDeclPragma*(n: PNode): PNode =
   if result != nil:
     assert result.kind == nkPragma, $(result.kind, n.kind)
 
+proc extractPragma*(s: PSym): PNode =
+  ## gets the pragma node of routine/type/var/let/const symbol `s`
+  if s.kind in routineKinds:
+    result = s.ast[pragmasPos]
+  elif s.kind in {skType, skVar, skLet, skConst}:
+    if s.ast != nil and s.ast.len > 0:
+      if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
+        # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
+        result = s.ast[0][1]
+  assert result == nil or result.kind == nkPragma
+
+proc skipPragmaExpr*(n: PNode): PNode =
+  ## if pragma expr, give the node the pragmas are applied to,
+  ## otherwise give node itself
+  if n.kind == nkPragmaExpr:
+    result = n[0]
+  else:
+    result = n
+
 when defined(useNodeIds):
   const nodeIdToDebug* = -1 # 2322968
   var gNodeId: int
@@ -1321,7 +1340,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym,
 
 proc astdef*(s: PSym): PNode =
   # get only the definition (initializer) portion of the ast
-  if s.ast != nil and s.ast.kind == nkIdentDefs:
+  if s.ast != nil and s.ast.kind in {nkIdentDefs, nkConstDef}:
     s.ast[2]
   else:
     s.ast
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 9b085b8ed..63de3ba14 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2856,7 +2856,7 @@ proc genConstSetup(p: BProc; sym: PSym): bool =
   useHeader(m, sym)
   if sym.loc.k == locNone:
     fillBackendName(p.module, sym)
-    fillLoc(sym.loc, locData, sym.ast, OnStatic)
+    fillLoc(sym.loc, locData, sym.astdef, OnStatic)
   if m.hcrOn: incl(sym.loc.flags, lfIndirect)
   result = lfNoDecl notin sym.loc.flags
 
@@ -2882,7 +2882,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
   var data = newRopeAppender()
   data.addf("N_LIB_PRIVATE NIM_CONST $1 $2 = ",
            [getTypeDesc(q, sym.typ), actualConstName])
-  genBracedInit(q.initProc, sym.ast, isConst = true, sym.typ, data)
+  genBracedInit(q.initProc, sym.astdef, isConst = true, sym.typ, data)
   data.addf(";$n", [])
   q.s[cfsData].add data
   if q.hcrOn:
@@ -2942,7 +2942,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     of skConst:
       if isSimpleConst(sym.typ):
         var lit = newRopeAppender()
-        genLiteral(p, sym.ast, sym.typ, lit)
+        genLiteral(p, sym.astdef, sym.typ, lit)
         putIntoDest(p, d, n, lit, OnStatic)
       elif useAliveDataFromDce in p.module.flags:
         genConstHeader(p.module, p.module, p, sym)
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index 7130c8462..cbef6771f 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -21,7 +21,7 @@ template detectVersion(field, corename) =
     if core == nil or core.kind != skConst:
       m.g.field = 1
     else:
-      m.g.field = toInt(ast.getInt(core.ast))
+      m.g.field = toInt(ast.getInt(core.astdef))
   result = m.g.field
 
 proc detectStrVersion(m: BModule): int =
diff --git a/compiler/guards.nim b/compiler/guards.nim
index a50593aca..f14c1d915 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -200,7 +200,7 @@ proc highBound*(conf: ConfigRef; x: PNode; o: Operators): PNode =
              nkIntLit.newIntNode(lastOrd(conf, typ))
            elif typ.kind == tySequence and x.kind == nkSym and
                x.sym.kind == skConst:
-             nkIntLit.newIntNode(x.sym.ast.len-1)
+             nkIntLit.newIntNode(x.sym.astdef.len-1)
            else:
              o.opAdd.buildCall(o.opLen.buildCall(x), minusOne())
   result.info = x.info
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 40ff7ab55..63cfbbd9f 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -866,9 +866,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
         if it.kind == nkVarTuple and hasDestructor(c, ri.typ):
           let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner)
           result.add p(x, c, s, consumed)
-        elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ):
+        elif it.kind == nkIdentDefs and hasDestructor(c, skipPragmaExpr(it[0]).typ):
           for j in 0..<it.len-2:
-            let v = it[j]
+            let v = skipPragmaExpr(it[j])
             if v.kind == nkSym:
               if sfCompileTime in v.sym.flags: continue
               pVarTopLevel(v, c, s, result)
@@ -1125,7 +1125,7 @@ proc injectDefaultCalls(n: PNode, c: var Con) =
       if it.kind == nkIdentDefs and it[^1].kind == nkEmpty:
         computeUninit(c)
         for j in 0..<it.len-2:
-          let v = it[j]
+          let v = skipPragmaExpr(it[j])
           doAssert v.kind == nkSym
           if c.uninit.contains(v.sym.id):
             it[^1] = genDefaultCall(v.sym.typ, c, v.info)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index dc58efb82..301662f10 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1484,7 +1484,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
     if s.loc.r == "":
       internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
     if sfCompileTime in s.flags:
-      genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info))
+      genVarInit(p, s, if s.astdef != nil: s.astdef else: newNodeI(nkEmpty, s.info))
     if s.kind == skParam:
       genCopyForParamIfNeeded(p, n)
     let k = mapType(p, s.typ)
@@ -1945,8 +1945,8 @@ proc genVarStmt(p: PProc, n: PNode) =
 proc genConstant(p: PProc, c: PSym) =
   if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
     let oldBody = move p.body
-    #genLineDir(p, c.ast)
-    genVarInit(p, c, c.ast)
+    #genLineDir(p, c.astdef)
+    genVarInit(p, c, c.astdef)
     p.g.constants.add(p.body)
     p.body = oldBody
 
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index cceb236ae..38b7faa07 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -224,7 +224,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
     const kinds = {skVar, skResult, skTemp, skParam, skLet, skForVar}
     if n.sym.kind == skParam:
       result = if n.sym.typ.kind in {tyVar, tySink}: arLValue else: arAddressableConst
-    elif n.sym.kind == skConst and dontInlineConstant(n, n.sym.ast):
+    elif n.sym.kind == skConst and dontInlineConstant(n, n.sym.astdef):
       result = arAddressableConst
     elif n.sym.kind in kinds:
       if n.sym.kind in {skParam, skLet, skForVar}:
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 87e9c825c..d4577981f 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -146,7 +146,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
   elif n.kind == nkSym and n.sym.kind == skConst:
     # try both:
     if p.kind == nkSym: result = p.sym == n.sym
-    elif matches(c, p, n.sym.ast): result = true
+    elif matches(c, p, n.sym.astdef): result = true
   elif p.kind == nkPattern:
     # pattern operators: | *
     let opr = p[0].ident.s
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index fdf4dd91f..a312478ae 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -313,7 +313,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
     # {.dynlib: myGetProcAddr(...).}
     result = c.semExpr(c, n[1])
     if result.kind == nkSym and result.sym.kind == skConst:
-      result = result.sym.ast # look it up
+      result = result.sym.astdef # look it up
     if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
       localError(c.config, n.info, errStringLiteralExpected)
       result = newEmptyStrNode(c, n)
@@ -998,7 +998,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       of wExplain:
         sym.flags.incl sfExplain
       of wDeprecated:
-        if sym != nil and sym.kind in routineKinds + {skType, skVar, skLet}:
+        if sym != nil and sym.kind in routineKinds + {skType, skVar, skLet, skConst}:
           if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
           incl(sym.flags, sfDeprecated)
         elif sym != nil and sym.kind != skModule:
@@ -1247,7 +1247,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
     elif comesFromPush and whichKeyword(ident) != wInvalid:
       discard "ignore the .push pragma; it doesn't apply"
     else:
-      if sym == nil or (sym.kind in {skVar, skLet, skParam, skIterator,
+      if sym == nil or (sym.kind in {skVar, skLet, skConst, skParam, skIterator,
                         skField, skProc, skFunc, skConverter, skMethod, skType}):
         n[i] = semCustomPragma(c, it)
       elif sym != nil:
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 21e519a59..3dff744a3 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -544,8 +544,8 @@ proc semResolvedCall(c: PContext, x: TCandidate,
       for s in instantiateGenericParamList(c, gp, x.bindings):
         case s.kind
         of skConst:
-          if not s.ast.isNil:
-            x.call.add s.ast
+          if not s.astdef.isNil:
+            x.call.add s.astdef
           else:
             x.call.add c.graph.emptyNode
         of skType:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 32bb4c331..a0753010a 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -108,7 +108,7 @@ proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   result = symChoice(c, n, s, scClosed)
 
 proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
-  result = copyTree(s.ast)
+  result = copyTree(s.astdef)
   if result.isNil:
     localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
     result = newSymNode(s)
@@ -1230,7 +1230,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       # It is clear that ``[]`` means two totally different things. Thus, we
       # copy `x`'s AST into each context, so that the type fixup phase can
       # deal with two different ``[]``.
-      if s.ast.safeLen == 0: result = inlineConst(c, n, s)
+      if s.astdef.safeLen == 0: result = inlineConst(c, n, s)
       else: result = newSymNode(s, n.info)
     of tyStatic:
       if typ.n != nil:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index f627bffc7..94e5fda31 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -517,12 +517,12 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
               "{.intdefine.} const was set to an invalid integer: '" &
                 g.config.symbols[s.name.s] & "'")
         else:
-          result = copyTree(s.ast)
+          result = copyTree(s.astdef)
       of mStrDefine:
         if isDefined(g.config, s.name.s):
           result = newStrNodeT(g.config.symbols[s.name.s], n, g)
         else:
-          result = copyTree(s.ast)
+          result = copyTree(s.astdef)
       of mBoolDefine:
         if isDefined(g.config, s.name.s):
           try:
@@ -532,9 +532,9 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
               "{.booldefine.} const was set to an invalid bool: '" &
                 g.config.symbols[s.name.s] & "'")
         else:
-          result = copyTree(s.ast)
+          result = copyTree(s.astdef)
       else:
-        result = copyTree(s.ast)
+        result = copyTree(s.astdef)
     of skProc, skFunc, skMethod:
       result = n
     of skParam:
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 940291f53..5d701c496 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -1101,12 +1101,13 @@ proc track(tracked: PEffects, n: PNode) =
           for i in 0..<child.len-2:
             createTypeBoundOps(tracked, child[i].typ, child.info)
         else:
-          createTypeBoundOps(tracked, child[0].typ, child.info)
+          createTypeBoundOps(tracked, skipPragmaExpr(child[0]).typ, child.info)
       if child.kind == nkIdentDefs and last.kind != nkEmpty:
         for i in 0..<child.len-2:
-          initVar(tracked, child[i], volatileCheck=false)
-          addAsgnFact(tracked.guards, child[i], last)
-          notNilCheck(tracked, last, child[i].typ)
+          let a = skipPragmaExpr(child[i])
+          initVar(tracked, a, volatileCheck=false)
+          addAsgnFact(tracked.guards, a, last)
+          notNilCheck(tracked, last, a.typ)
       elif child.kind == nkVarTuple and last.kind != nkEmpty:
         for i in 0..<child.len-1:
           if child[i].kind == nkEmpty or
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index fd8f2180b..faf8e3baa 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -694,28 +694,25 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         if def.kind != nkEmpty:
           if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit)
         setVarType(c, v, typ)
+        # this is needed for the evaluation pass, guard checking
+        #  and custom pragmas:
         b = newNodeI(nkIdentDefs, a.info)
         if importantComments(c.config):
           # keep documentation information:
           b.comment = a.comment
-        b.add newSymNode(v)
-        # keep type desc for doc generator
-        b.add a[^2]
-        b.add copyTree(def)
-        addToVarSection(c, result, n, b)
-        # this is needed for the evaluation pass, guard checking
-        #  and custom pragmas:
-        var ast = newNodeI(nkIdentDefs, a.info)
+        # postfix not generated here (to generate, get rid of it in transf)
         if a[j].kind == nkPragmaExpr:
           var p = newNodeI(nkPragmaExpr, a.info)
           p.add newSymNode(v)
-          p.add a[j][1].copyTree
-          ast.add p
+          p.add a[j][1]
+          b.add p
         else:
-          ast.add newSymNode(v)
-        ast.add a[^2].copyTree
-        ast.add def
-        v.ast = ast
+          b.add newSymNode(v)
+        # keep type desc for doc generator
+        b.add a[^2]
+        b.add copyTree(def)
+        addToVarSection(c, result, n, b)
+        v.ast = b
       else:
         if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j]
         # bug #7663, for 'nim check' this can be a non-tuple:
@@ -811,12 +808,21 @@ proc semConst(c: PContext, n: PNode): PNode =
 
       if a.kind != nkVarTuple:
         setVarType(c, v, typ)
-        v.ast = def               # no need to copy
+        when false:
+          v.ast = def               # no need to copy
         b = newNodeI(nkConstDef, a.info)
         if importantComments(c.config): b.comment = a.comment
-        b.add newSymNode(v)
+        # postfix not generated here (to generate, get rid of it in transf)
+        if a[j].kind == nkPragmaExpr:
+          var p = newNodeI(nkPragmaExpr, a.info)
+          p.add newSymNode(v)
+          p.add a[j][1].copyTree
+          b.add p
+        else:
+          b.add newSymNode(v)
         b.add a[1]
         b.add copyTree(def)
+        v.ast = b
       else:
         setVarType(c, v, typ[j])
         v.ast = if def[j].kind != nkExprColonExpr: def[j]
@@ -2330,6 +2336,11 @@ proc setLine(n: PNode, info: TLineInfo) =
     for i in 0..<n.safeLen: setLine(n[i], info)
     n.info = info
 
+proc recursiveSetFlag(n: PNode, flag: TNodeFlag) =
+  if n != nil:
+    for i in 0..<n.safeLen: recursiveSetFlag(n[i], flag)
+    incl(n.flags, flag)
+
 proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
   checkSonsLen(n, 2, c.config)
   let pragmaList = n[0]
@@ -2354,7 +2365,7 @@ proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
   for i in 0..<pragmaList.len:
     case whichPragma(pragmaList[i])
     of wLine: setLine(result, pragmaList[i].info)
-    of wNoRewrite: incl(result.flags, nfNoRewrite)
+    of wNoRewrite: recursiveSetFlag(result, nfNoRewrite)
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim
index f58c9c3ef..3dfd71315 100644
--- a/compiler/sighashes.nim
+++ b/compiler/sighashes.nim
@@ -333,7 +333,7 @@ proc hashVarSymBody(graph: ModuleGraph, c: var MD5Context, s: PSym) =
     c &= hashNonProc(s)
     # this one works for let and const but not for var. True variables can change value
     # later on. it is user resposibility to hash his global state if required
-    if s.ast != nil and s.ast.kind == nkIdentDefs:
+    if s.ast != nil and s.ast.kind in {nkIdentDefs, nkConstDef}:
       hashBodyTree(graph, c, s.ast[^1])
     else:
       hashBodyTree(graph, c, s.ast)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 5e8d896bf..9d4089707 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -535,16 +535,6 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
       if parentFileIndex == conf.m.trackPos.fileIndex:
         suggestResult(conf, symToSuggest(g, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
 
-proc extractPragma(s: PSym): PNode =
-  if s.kind in routineKinds:
-    result = s.ast[pragmasPos]
-  elif s.kind in {skType, skVar, skLet}:
-    if s.ast != nil and s.ast.len > 0:
-      if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
-        # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
-        result = s.ast[0][1]
-  doAssert result == nil or result.kind == nkPragma
-
 proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
   var pragmaNode: PNode
   pragmaNode = if s.kind == skEnumField: extractPragma(s.owner) else: extractPragma(s)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 47d7fb3a5..7ab67873b 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -184,10 +184,12 @@ proc transformVarSection(c: PTransf, v: PNode): PNode =
     if it.kind == nkCommentStmt:
       result[i] = it
     elif it.kind == nkIdentDefs:
-      if it[0].kind == nkSym:
+      var vn = it[0]
+      if vn.kind == nkPragmaExpr: vn = vn[0]
+      if vn.kind == nkSym:
         internalAssert(c.graph.config, it.len == 3)
-        let x = freshVar(c, it[0].sym)
-        idNodeTablePut(c.transCon.mapping, it[0].sym, x)
+        let x = freshVar(c, vn.sym)
+        idNodeTablePut(c.transCon.mapping, vn.sym, x)
         var defs = newTransNode(nkIdentDefs, it.info, 3)
         if importantComments(c.graph.config):
           # keep documentation information:
@@ -1036,7 +1038,7 @@ proc transform(c: PTransf, n: PNode): PNode =
     result = transformAsgn(c, n)
   of nkIdentDefs, nkConstDef:
     result = newTransNode(n)
-    result[0] = transform(c, n[0])
+    result[0] = transform(c, skipPragmaExpr(n[0]))
     # Skip the second son since it only contains an unsemanticized copy of the
     # variable type used by docgen
     let last = n.len-1
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index f15cb2752..a0bf6af56 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -2000,7 +2000,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       elif importcCond(c, s): c.importcSym(n.info, s)
       genLit(c, n, dest)
     of skConst:
-      let constVal = if s.ast != nil: s.ast else: s.typ.n
+      let constVal = if s.astdef != nil: s.astdef else: s.typ.n
       gen(c, constVal, dest)
     of skEnumField:
       # we never reach this case - as of the time of this comment,
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 24901180e..cc2d5041e 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1567,7 +1567,7 @@ proc customPragmaNode(n: NimNode): NimNode =
     let impl = n.getImpl()
     if impl.kind in RoutineNodes:
       return impl.pragma
-    elif impl.kind == nnkIdentDefs and impl[0].kind == nnkPragmaExpr:
+    elif impl.kind in {nnkIdentDefs, nnkConstDef} and impl[0].kind == nnkPragmaExpr:
       return impl[0][1]
     else:
       let timpl = typ.getImpl()
diff --git a/tests/deprecated/tconst.nim b/tests/deprecated/tconst.nim
new file mode 100644
index 000000000..51eb6cb0e
--- /dev/null
+++ b/tests/deprecated/tconst.nim
@@ -0,0 +1,8 @@
+discard """
+  nimout: '''
+tconst.nim(8, 9) Warning: abcd; foo is deprecated [Deprecated]
+'''
+"""
+
+const foo* {.deprecated: "abcd".} = 42
+discard foo
diff --git a/tests/macros/t19766_20114.nim b/tests/macros/t19766_20114.nim
new file mode 100644
index 000000000..ac336f150
--- /dev/null
+++ b/tests/macros/t19766_20114.nim
@@ -0,0 +1,16 @@
+discard """
+  action: compile
+  nimout: '''
+const
+  foo {.strdefine.} = "abc"
+let hey {.tddd.} = 5
+'''
+"""
+
+import macros
+
+template tddd {.pragma.}
+
+expandMacros:
+  const foo {.strdefine.} = "abc"
+  let hey {.tddd.} = 5
diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim
index de132f253..66722a234 100644
--- a/tests/macros/tgetimpl.nim
+++ b/tests/macros/tgetimpl.nim
@@ -1,5 +1,5 @@
 discard """
-  nimout: '''"muhaha"
+  nimout: '''foo = "muhaha"
 proc poo(x, y: int) =
   let y = x
   echo ["poo"]'''
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
index b624f32ba..5a68b7677 100644
--- a/tests/pragmas/tcustom_pragma.nim
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -439,3 +439,43 @@ when false:
 
   # left-to-right priority/override order for getCustomPragmaVal
   assert bb.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he")
+
+{.experimental: "dynamicBindSym".}
+
+# const
+block:
+  template myAttr() {.pragma.}
+  template myAttr2(x: int) {.pragma.}
+  template myAttr3(x: string) {.pragma.}
+
+  type
+    MyObj2 = ref object
+
+  const a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
+  const b {.myAttr,myAttr2(2),myAttr3:"test".} = 0
+
+  macro forceHasCustomPragma(x: untyped, y: typed): untyped =
+    var x = bindSym(x.repr)
+    for c in x:
+      if c.symKind == nskConst:
+        x = c
+        break
+    result = getAst(hasCustomPragma(x, y))
+
+  macro forceGetCustomPragmaVal(x: untyped, y: typed): untyped =
+    var x = bindSym(x.repr)
+    for c in x:
+      if c.symKind == nskConst:
+        x = c
+        break
+    result = getAst(getCustomPragmaVal(x, y))
+
+  template check(s: untyped) =
+    doAssert forceHasCustomPragma(s, myAttr)
+    doAssert forceHasCustomPragma(s, myAttr2)
+    doAssert forceGetCustomPragmaVal(s, myAttr2) == 2
+    doAssert forceHasCustomPragma(s, myAttr3)
+    doAssert forceGetCustomPragmaVal(s, myAttr3) == "test"
+
+  check(a)
+  check(b)
diff --git a/tests/trmacros/tnorewrite.nim b/tests/trmacros/tnorewrite.nim
new file mode 100644
index 000000000..e6769246f
--- /dev/null
+++ b/tests/trmacros/tnorewrite.nim
@@ -0,0 +1,20 @@
+block:
+  proc get(x: int): int = x
+
+  template t{get(a)}(a: int): int =
+    {.noRewrite.}:
+      get(a) + 1
+
+  doAssert get(0) == 1
+
+block:
+  var x: int
+
+  template asgn{a = b}(a: int{lvalue}, b: int) =
+    let newVal = b + 1
+    # ^ this is needed but should it be?
+    {.noRewrite.}:
+      a = newVal
+
+  x = 10
+  doAssert x == 11, $x
diff --git a/tests/trmacros/trmacros_various.nim b/tests/trmacros/trmacros_various.nim
index 74b248739..8fe51e548 100644
--- a/tests/trmacros/trmacros_various.nim
+++ b/tests/trmacros/trmacros_various.nim
@@ -33,7 +33,8 @@ block tcse:
 
 block hoist:
   template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
-    var gl {.global, gensym.} = peg(pattern)
+    {.noRewrite.}:
+      var gl {.global, gensym.} = peg(pattern)
     gl
   doAssert match("(a b c)", peg"'(' @ ')'")
   doAssert match("W_HI_Le", peg"\y 'while'")