From 2cca38d33c50650d1606c6ec09c73af6b8b0c3c8 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 3 Oct 2022 07:07:55 +0300 Subject: [PATCH 1/3] pragma for sfCallsite instead of name check + better semantics, test (#20464) * pragma for sfCallsite instead of name check at every template definition Not documented because it seems to be for internal use? Should also make it possible to make comparisons and setops imports, but this doesn't have to be done. I can reuse a name like `cursor` for the pragma as well, added a new name just to be safe. * make sfCallsite recursive, add tests --- compiler/ast.nim | 6 ++++++ compiler/condsyms.nim | 1 + compiler/evaltempl.nim | 4 ++-- compiler/pragmas.nim | 5 ++++- compiler/semstmts.nim | 7 +------ compiler/semtempl.nim | 6 ------ compiler/vm.nim | 5 ++++- compiler/wordrecg.nim | 2 +- lib/system.nim | 9 ++++++--- lib/system/comparisons.nim | 9 ++++++--- lib/system/setops.nim | 7 +++++-- tests/template/tcallsitelineinfo.nim | 17 +++++++++++++++++ tests/template/tcallsitelineinfo2.nim | 20 ++++++++++++++++++++ 13 files changed, 73 insertions(+), 25 deletions(-) create mode 100644 tests/template/tcallsitelineinfo.nim create mode 100644 tests/template/tcallsitelineinfo2.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index e1d982a434..4174e7f34d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1254,6 +1254,12 @@ proc skipPragmaExpr*(n: PNode): PNode = else: result = n +proc setInfoRecursive*(n: PNode, info: TLineInfo) = + ## set line info recursively + if n != nil: + for i in 0..=", ">", "incl", "excl", "in", "notin", "isnot"] - if sfSystemModule in s.owner.flags and s.name.s in names or - s.owner.name.s == "vm" and s.name.s == "stackTrace": - incl(s.flags, sfCallsite) - styleCheckDef(c, s) onDef(n[namePos].info, s) # check parameter list: diff --git a/compiler/vm.nim b/compiler/vm.nim index 1717fe1194..7a6dbd0ee5 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -75,8 +75,11 @@ proc stackTraceImpl(c: PCtx, tos: PStackFrame, pc: int, let lineInfo = if lineInfo == TLineInfo.default: c.debug[pc] else: lineInfo liMessage(c.config, lineInfo, errGenerated, msg, action, infoOrigin) +when not defined(nimHasCallsitePragma): + {.pragma: callsite.} + template stackTrace(c: PCtx, tos: PStackFrame, pc: int, - msg: string, lineInfo: TLineInfo = TLineInfo.default) = + msg: string, lineInfo: TLineInfo = TLineInfo.default) {.callsite.} = stackTraceImpl(c, tos, pc, msg, lineInfo, instantiationInfo(-2, fullPaths = true)) return diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index d33982b0fe..c21eda1f9c 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -87,7 +87,7 @@ type wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked", wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain", wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises", - wRedefine = "redefine", + wRedefine = "redefine", wCallsite = "callsite", wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default", diff --git a/lib/system.nim b/lib/system.nim index fd31cf3da3..1b6b3c9a80 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -731,13 +731,16 @@ proc contains*[U, V, W](s: HSlice[U, V], value: W): bool {.noSideEffect, inline. ## ``` result = s.a <= value and value <= s.b -template `in`*(x, y: untyped): untyped {.dirty.} = contains(y, x) +when not defined(nimHasCallsitePragma): + {.pragma: callsite.} + +template `in`*(x, y: untyped): untyped {.dirty, callsite.} = contains(y, x) ## Sugar for `contains`. ## ``` ## assert(1 in (1..3) == true) ## assert(5 in (1..3) == false) ## ``` -template `notin`*(x, y: untyped): untyped {.dirty.} = not contains(y, x) +template `notin`*(x, y: untyped): untyped {.dirty, callsite.} = not contains(y, x) ## Sugar for `not contains`. ## ``` ## assert(1 notin (1..3) == false) @@ -762,7 +765,7 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## assert(test[int](3) == 3) ## assert(test[string]("xyz") == 0) ## ``` -template `isnot`*(x, y: untyped): untyped = not (x is y) +template `isnot`*(x, y: untyped): untyped {.callsite.} = not (x is y) ## Negated version of `is <#is,T,S>`_. Equivalent to `not(x is y)`. ## ``` ## assert 42 isnot float diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index eedac9d840..36d4d06a8e 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -125,15 +125,18 @@ proc `<`*[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.} proc `<`*[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} proc `<`*(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.} -template `!=`*(x, y: untyped): untyped = +when not defined(nimHasCallsitePragma): + {.pragma: callsite.} + +template `!=`*(x, y: untyped): untyped {.callsite.} = ## Unequals operator. This is a shorthand for `not (x == y)`. not (x == y) -template `>=`*(x, y: untyped): untyped = +template `>=`*(x, y: untyped): untyped {.callsite.} = ## "is greater or equals" operator. This is the same as `y <= x`. y <= x -template `>`*(x, y: untyped): untyped = +template `>`*(x, y: untyped): untyped {.callsite.} = ## "is greater" operator. This is the same as `y < x`. y < x diff --git a/lib/system/setops.nim b/lib/system/setops.nim index 755eafdb81..b42c8b4a8d 100644 --- a/lib/system/setops.nim +++ b/lib/system/setops.nim @@ -9,7 +9,10 @@ func incl*[T](x: var set[T], y: T) {.magic: "Incl".} = a.incl(4) assert a == {1, 2, 3, 4, 5} -template incl*[T](x: var set[T], y: set[T]) = +when not defined(nimHasCallsitePragma): + {.pragma: callsite.} + +template incl*[T](x: var set[T], y: set[T]) {.callsite.} = ## Includes the set `y` in the set `x`. runnableExamples: var a = {1, 3, 5, 7} @@ -27,7 +30,7 @@ func excl*[T](x: var set[T], y: T) {.magic: "Excl".} = b.excl(5) assert b == {2, 3, 6, 12, 545} -template excl*[T](x: var set[T], y: set[T]) = +template excl*[T](x: var set[T], y: set[T]) {.callsite.} = ## Excludes the set `y` from the set `x`. runnableExamples: var a = {1, 3, 5, 7} diff --git a/tests/template/tcallsitelineinfo.nim b/tests/template/tcallsitelineinfo.nim new file mode 100644 index 0000000000..5fed933630 --- /dev/null +++ b/tests/template/tcallsitelineinfo.nim @@ -0,0 +1,17 @@ +discard """ + nimout: ''' +tcallsitelineinfo.nim(17, 4) Warning: abc [User] +''' + exitcode: 1 + outputsub: ''' +tcallsitelineinfo.nim(17) tcallsitelineinfo +Error: unhandled exception: def [ValueError] +''' +""" + +template foo(): untyped {.callsite.} = + {.warning: "abc".} + raise newException(ValueError, "def") + echo "hello" + +foo() diff --git a/tests/template/tcallsitelineinfo2.nim b/tests/template/tcallsitelineinfo2.nim new file mode 100644 index 0000000000..d5f2574749 --- /dev/null +++ b/tests/template/tcallsitelineinfo2.nim @@ -0,0 +1,20 @@ +discard """ + nimout: ''' +tcallsitelineinfo2.nim(18, 1) Warning: abc [User] +tcallsitelineinfo2.nim(19, 12) Warning: def [User] +''' + exitcode: 1 + outputsub: ''' +tcallsitelineinfo2.nim(20) tcallsitelineinfo2 +Error: unhandled exception: ghi [ValueError] +''' +""" + +template foo(a: untyped): untyped {.callsite.} = + {.warning: "abc".} + a + echo "hello" + +foo: # with `{.line.}:`, the following do not keep their line information: + {.warning: "def".} + raise newException(ValueError, "ghi") From 852a7c4919d7801bc73310fecca14faaeb278652 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:37:27 +0800 Subject: [PATCH 2/3] close #11415; add testcase (#20486) --- tests/pragmas/tcustom_pragma.nim | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 5a68b7677b..ad25cad98c 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -423,6 +423,31 @@ when false: doAssert hasMyAttr(TObj) + +# bug #11415 +template noserialize() {.pragma.} + +type + Point[T] = object + x, y: T + + ReplayEventKind = enum + FoodAppeared, FoodEaten, DirectionChanged + + ReplayEvent = object + case kind: ReplayEventKind + of FoodEaten, FoodAppeared: # foodPos is in multiple branches + foodPos {.noserialize.}: Point[float] + of DirectionChanged: + playerPos: float +let ev = ReplayEvent( + kind: FoodEaten, + foodPos: Point[float](x: 5.0, y: 1.0) + ) + +doAssert ev.foodPos.hasCustomPragma(noserialize) + + when false: # misc {.pragma: haha.} From 0f5ad499714f3fc6bc02b54351e59ecf9946dd5a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 3 Oct 2022 22:12:23 +0800 Subject: [PATCH 3/3] [ARC] fixes #18645; C Compiler error when initializing {.global.} with a block (#19953) * fixes #18645; C Compiler error when initializing {.global.} with a block: * arguably cleaner solution Co-authored-by: xflywind <43030857+xflywind@users.noreply.github.com> Co-authored-by: Araq --- compiler/injectdestructors.nim | 29 +++++++++++++++++------------ tests/arc/t18645.nim | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 tests/arc/t18645.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 298bc77116..598a5f226e 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -77,7 +77,7 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = proc nestedScope(parent: var Scope; body: PNode): Scope = Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent)) -proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode +proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNode when false: @@ -508,14 +508,14 @@ proc processScope(c: var Con; s: var Scope; ret: PNode): PNode = if s.parent != nil: s.parent[].needsTry = s.parent[].needsTry or s.needsTry -template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped): PNode = +template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: untyped, tmpFlags: TSymFlags): PNode = assert not ret.typ.isEmptyType var result = newNodeIT(nkStmtListExpr, ret.info, ret.typ) # There is a possibility to do this check: s.wasMoved.len > 0 or s.final.len > 0 # later and use it to eliminate the temporary when theres no need for it, but its # tricky because you would have to intercept moveOrCopy at a certain point let tmp = c.getTemp(s.parent[], ret.typ, ret.info) - tmp.sym.flags.incl sfSingleUsedTemp + tmp.sym.flags = tmpFlags let cpy = if hasDestructor(c, ret.typ): s.parent[].final.add c.genDestroy(tmp) moveOrCopy(tmp, ret, c, s, isDecl = true) @@ -542,7 +542,8 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt result -template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = +template handleNestedTempl(n, processCall: untyped, willProduceStmt = false, + tmpFlags = {sfSingleUsedTemp}) = template maybeVoid(child, s): untyped = if isEmptyType(child.typ): p(child, c, s, normal) else: processCall(child, s) @@ -570,7 +571,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt: processScope(c, ofScope, maybeVoid(it[^1], ofScope)) else: - processScopeExpr(c, ofScope, it[^1], processCall) + processScopeExpr(c, ofScope, it[^1], processCall, tmpFlags) result.add branch of nkWhileStmt: @@ -603,7 +604,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = result.add if n[1].typ.isEmptyType or willProduceStmt: processScope(c, bodyScope, processCall(n[1], bodyScope)) else: - processScopeExpr(c, bodyScope, n[1], processCall) + processScopeExpr(c, bodyScope, n[1], processCall, tmpFlags) of nkIfStmt, nkIfExpr: result = copyNode(n) @@ -618,7 +619,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt: processScope(c, branchScope, maybeVoid(it[^1], branchScope)) else: - processScopeExpr(c, branchScope, it[^1], processCall) + processScopeExpr(c, branchScope, it[^1], processCall, tmpFlags) result.add branch of nkTryStmt: @@ -627,7 +628,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) = result.add if n[0].typ.isEmptyType or willProduceStmt: processScope(c, tryScope, maybeVoid(n[0], tryScope)) else: - processScopeExpr(c, tryScope, n[0], maybeVoid) + processScopeExpr(c, tryScope, n[0], maybeVoid, tmpFlags) for i in 1..