diff --git a/changelog.md b/changelog.md index 6d4ccd4b03021..7d52b289cfa63 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 f81dc443dcae3..399d7e5613e1f 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 9b085b8ed9c72..63de3ba149233 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 7130c8462880e..cbef6771f6b39 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 a50593aca6917..f14c1d91553e7 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 40ff7ab559a92..63cfbbd9f4945 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.. 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 47d7fb3a56f1b..7ab67873b4f95 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 f15cb27527389..a0bf6af566eda 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 24901180ef1db..cc2d5041e727d 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 0000000000000..51eb6cb0ec40b --- /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 0000000000000..ac336f1504bf9 --- /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 de132f2538994..66722a234400c 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 b624f32ba32b7..5a68b7677b321 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 0000000000000..e6769246f5fc0 --- /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 74b248739b2de..8fe51e5480fbd 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'")