mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-25 16:11:44 +00:00
Merge branch 'devel' into araq-orc-hotfix
This commit is contained in:
@@ -454,6 +454,7 @@
|
||||
static libraries.
|
||||
|
||||
- When compiling for Release the flag `-fno-math-errno` is used for GCC.
|
||||
- When compiling for Release the flag `--build-id=none` is used for GCC Linker.
|
||||
|
||||
## Docgen
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ type
|
||||
mIsPartOf, mAstToStr, mParallel,
|
||||
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
|
||||
mNewString, mNewStringOfCap, mParseBiggestFloat,
|
||||
mMove, mWasMoved, mDestroy, mTrace,
|
||||
mMove, mWasMoved, mDup, mDestroy, mTrace,
|
||||
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
|
||||
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
|
||||
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
|
||||
@@ -944,7 +944,8 @@ type
|
||||
attachedAsgn,
|
||||
attachedSink,
|
||||
attachedTrace,
|
||||
attachedDeepCopy
|
||||
attachedDeepCopy,
|
||||
attachedDup
|
||||
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
# types are identical iff they have the
|
||||
@@ -1515,7 +1516,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||
|
||||
const
|
||||
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
|
||||
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
|
||||
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy", "=dup"]
|
||||
|
||||
proc `$`*(s: PSym): string =
|
||||
if s != nil:
|
||||
|
||||
@@ -68,7 +68,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
|
||||
result.links[j] = h.links[Mhalf + j]
|
||||
else:
|
||||
for j in 0..<Mhalf:
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result.vals[j] = move h.vals[Mhalf + j]
|
||||
else:
|
||||
shallowCopy(result.vals[j], h.vals[Mhalf + j])
|
||||
@@ -91,7 +91,7 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
|
||||
if less(key, h.keys[j]): break
|
||||
inc j
|
||||
for i in countdown(h.entries, j+1):
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
h.vals[i] = move h.vals[i-1]
|
||||
else:
|
||||
shallowCopy(h.vals[i], h.vals[i-1])
|
||||
|
||||
@@ -269,7 +269,7 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
|
||||
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
|
||||
# Aliasing is preferred over stack overflows.
|
||||
# Also don't regress for non ARC-builds, too risky.
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and
|
||||
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
|
||||
getSize(p.config, a.lode.typ) < 1024:
|
||||
getTemp(p, a.lode.typ, result, needsInit=false)
|
||||
genAssignment(p, result, a, {})
|
||||
|
||||
@@ -382,7 +382,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
of tyArray:
|
||||
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcOrc, gcHooks}:
|
||||
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
|
||||
genGenericAsgn(p, dest, src, flags)
|
||||
else:
|
||||
linefmt(p, cpsStmts,
|
||||
@@ -2346,6 +2346,11 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
genAssignment(p, d, a, {})
|
||||
resetLoc(p, a)
|
||||
|
||||
proc genDup(p: BProc; src: TLoc; d: var TLoc; n: PNode) =
|
||||
if d.k == locNone: getTemp(p, n.typ, d)
|
||||
linefmt(p, cpsStmts, "#nimDupRef((void**)$1, (void*)$2);$n",
|
||||
[addrLoc(p.config, d), rdLoc(src)])
|
||||
|
||||
proc genDestroy(p: BProc; n: PNode) =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
let arg = n[1].skipAddr
|
||||
@@ -2398,7 +2403,7 @@ proc genSlice(p: BProc; e: PNode; d: var TLoc) =
|
||||
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
|
||||
prepareForMutation = e[1].kind == nkHiddenDeref and
|
||||
e[1].typ.skipTypes(abstractInst).kind == tyString and
|
||||
p.config.selectedGC in {gcArc, gcOrc})
|
||||
p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc})
|
||||
if d.k == locNone: getTemp(p, e.typ, d)
|
||||
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
|
||||
when false:
|
||||
@@ -2580,7 +2585,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e)
|
||||
expr(p, n, d)
|
||||
of mDeepCopy:
|
||||
if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
|
||||
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
|
||||
localError(p.config, e.info,
|
||||
"for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
|
||||
|
||||
@@ -2597,6 +2602,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mAccessTypeField: genAccessTypeField(p, e, d)
|
||||
of mSlice: genSlice(p, e, d)
|
||||
of mTrace: discard "no code to generate"
|
||||
of mDup:
|
||||
var a: TLoc
|
||||
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
|
||||
initLocExpr(p, x, a)
|
||||
genDup(p, a, d, e)
|
||||
else:
|
||||
when defined(debugMagics):
|
||||
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
|
||||
|
||||
@@ -1581,11 +1581,11 @@ proc genMainProc(m: BModule) =
|
||||
m.includeHeader("<libc/component.h>")
|
||||
|
||||
let initStackBottomCall =
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
|
||||
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
|
||||
inc(m.labels)
|
||||
|
||||
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0"
|
||||
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0"
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile])
|
||||
|
||||
if m.config.target.targetOS == osWindows and
|
||||
@@ -1725,7 +1725,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
if sfSystemModule in m.module.flags:
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
|
||||
|
||||
if m.s[cfsInitProc].len > 0:
|
||||
@@ -2177,7 +2177,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
|
||||
cgsym(m, "rawWrite")
|
||||
|
||||
# raise dependencies on behalf of genMainProc
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
cgsym(m, "initStackBottomWith")
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
cgsym(m, "initThreadVarsEmulation")
|
||||
|
||||
@@ -238,7 +238,7 @@ proc processCompile(conf: ConfigRef; filename: string) =
|
||||
extccomp.addExternalFileToCompile(conf, found)
|
||||
|
||||
const
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
|
||||
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
|
||||
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
|
||||
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
|
||||
@@ -262,6 +262,7 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||
of "go": result = conf.selectedGC == gcGo
|
||||
of "none": result = conf.selectedGC == gcNone
|
||||
of "stack", "regions": result = conf.selectedGC == gcRegions
|
||||
of "atomicarc": result = conf.selectedGC == gcAtomicArc
|
||||
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
|
||||
of "opt":
|
||||
case arg.normalize
|
||||
@@ -516,14 +517,7 @@ proc initOrcDefines*(conf: ConfigRef) =
|
||||
if conf.exc == excNone and conf.backend != backendCpp:
|
||||
conf.exc = excGoto
|
||||
|
||||
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
|
||||
if isOrc:
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
else:
|
||||
conf.selectedGC = gcArc
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
|
||||
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
|
||||
defineSymbol(conf.symbols, "gcdestructors")
|
||||
incl conf.globalOptions, optSeqDestructors
|
||||
incl conf.globalOptions, optTinyRtti
|
||||
@@ -562,9 +556,17 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
|
||||
conf.selectedGC = gcMarkAndSweep
|
||||
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||
of "destructors", "arc":
|
||||
registerArcOrc(pass, conf, false)
|
||||
conf.selectedGC = gcArc
|
||||
defineSymbol(conf.symbols, "gcarc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "orc":
|
||||
registerArcOrc(pass, conf, true)
|
||||
conf.selectedGC = gcOrc
|
||||
defineSymbol(conf.symbols, "gcorc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "atomicarc":
|
||||
conf.selectedGC = gcAtomicArc
|
||||
defineSymbol(conf.symbols, "gcatomicarc")
|
||||
registerArcOrc(pass, conf)
|
||||
of "hooks":
|
||||
conf.selectedGC = gcHooks
|
||||
defineSymbol(conf.symbols, "gchooks")
|
||||
|
||||
@@ -154,5 +154,6 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasGenericDefine")
|
||||
defineSymbol("nimHasDefineAliases")
|
||||
defineSymbol("nimHasWarnBareExcept")
|
||||
|
||||
defineSymbol("nimHasDup")
|
||||
defineSymbol("nimHasChecksums")
|
||||
|
||||
|
||||
@@ -493,7 +493,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
|
||||
gen(c, body)
|
||||
if root.kind == skResult:
|
||||
genImplicitReturn(c)
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = c.code # will move
|
||||
else:
|
||||
shallowCopy(result, c.code)
|
||||
|
||||
@@ -66,7 +66,7 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} =
|
||||
result = ast.hasDestructor(t)
|
||||
when toDebug.len > 0:
|
||||
# for more effective debugging
|
||||
if not result and c.graph.config.selectedGC in {gcArc, gcOrc}:
|
||||
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
assert(not containsGarbageCollectedRef(t))
|
||||
|
||||
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||
@@ -425,17 +425,34 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
let tmp = c.getTemp(s, n.typ, n.info)
|
||||
if hasDestructor(c, n.typ):
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
c.finishCopy(m, n, isFromSink = true)
|
||||
result.add m
|
||||
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
let op = getAttachedOp(c.graph, typ, attachedDup)
|
||||
if op != nil:
|
||||
let src = p(n, c, s, normal)
|
||||
result.add newTreeI(nkFastAsgn,
|
||||
src.info, tmp,
|
||||
genOp(c, op, src)
|
||||
)
|
||||
elif typ.kind == tyRef:
|
||||
let src = p(n, c, s, normal)
|
||||
result.add newTreeI(nkFastAsgn,
|
||||
src.info, tmp,
|
||||
newTreeIT(nkCall, src.info, src.typ,
|
||||
newSymNode(createMagic(c.graph, c.idgen, "`=dup`", mDup)),
|
||||
src)
|
||||
)
|
||||
else:
|
||||
result.add c.genWasMoved(tmp)
|
||||
var m = c.genCopy(tmp, n, {})
|
||||
m.add p(n, c, s, normal)
|
||||
c.finishCopy(m, n, isFromSink = true)
|
||||
result.add m
|
||||
if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
|
||||
message(c.graph.config, n.info, hintPerformance,
|
||||
("passing '$1' to a sink parameter introduces an implicit copy; " &
|
||||
"if possible, rearrange your program's control flow to prevent it") % $n)
|
||||
else:
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc}:
|
||||
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
assert(not containsManagedMemory(n.typ))
|
||||
if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
|
||||
@@ -478,7 +495,7 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
|
||||
result = arg
|
||||
|
||||
proc cycleCheck(n: PNode; c: var Con) =
|
||||
if c.graph.config.selectedGC != gcArc: return
|
||||
if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return
|
||||
var value = n[1]
|
||||
if value.kind == nkClosure:
|
||||
value = value[1]
|
||||
@@ -821,7 +838,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
|
||||
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
|
||||
result[0] = copyTree(n[0])
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcOrc}:
|
||||
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
|
||||
let destroyOld = c.genDestroy(result[1])
|
||||
result = newTree(nkStmtList, destroyOld, result)
|
||||
else:
|
||||
|
||||
@@ -2174,6 +2174,13 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
|
||||
genReset(p, n)
|
||||
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
||||
|
||||
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.kind = resVal
|
||||
r.res = p.getTemp()
|
||||
gen(p, n[1], a)
|
||||
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
|
||||
|
||||
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var a: TCompRes
|
||||
r.res = rope("[")
|
||||
@@ -2368,6 +2375,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.kind = resExpr
|
||||
of mMove:
|
||||
genMove(p, n, r)
|
||||
of mDup:
|
||||
genDup(p, n, r)
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
#else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
|
||||
|
||||
@@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
rememberSplit(splitComma)
|
||||
wrSpace em
|
||||
of openPars:
|
||||
if tok.strongSpaceA and not em.endsInWhite and
|
||||
if tsLeading in tok.spacing and not em.endsInWhite and
|
||||
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
|
||||
wrSpace em
|
||||
wr(em, $tok.tokType, ltSomeParLe)
|
||||
@@ -528,7 +528,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
wr(em, $tok.tokType, ltOther)
|
||||
if not em.inquote: wrSpace(em)
|
||||
of tkOpr, tkDotDot:
|
||||
if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and
|
||||
if em.inquote or (tok.spacing == {} and
|
||||
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]):
|
||||
# bug #9504: remember to not spacify a keyword:
|
||||
lastTokWasTerse = true
|
||||
@@ -538,7 +538,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
|
||||
if not em.endsInWhite: wrSpace(em)
|
||||
wr(em, tok.ident.s, ltOpr)
|
||||
template isUnary(tok): bool =
|
||||
tok.strongSpaceB == tsNone and tok.strongSpaceA
|
||||
tok.spacing == {tsLeading}
|
||||
|
||||
if not isUnary(tok):
|
||||
rememberSplit(splitBinary)
|
||||
|
||||
@@ -94,19 +94,18 @@ type
|
||||
base2, base8, base16
|
||||
|
||||
TokenSpacing* = enum
|
||||
tsNone, tsTrailing, tsEof
|
||||
tsLeading, tsTrailing, tsEof
|
||||
|
||||
Token* = object # a Nim token
|
||||
tokType*: TokType # the type of the token
|
||||
base*: NumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
spacing*: set[TokenSpacing] # spaces around token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
# preceded with indentation
|
||||
ident*: PIdent # the parsed identifier
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
base*: NumericalBase # the numerical base; only valid for int
|
||||
# or float literals
|
||||
strongSpaceA*: bool # leading spaces of an operator
|
||||
strongSpaceB*: TokenSpacing # trailing spaces of an operator
|
||||
literal*: string # the parsed (string) literal; and
|
||||
# documentation comments are here too
|
||||
line*, col*: int
|
||||
@@ -178,7 +177,7 @@ proc initToken*(L: var Token) =
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.indent = 0
|
||||
L.strongSpaceA = false
|
||||
L.spacing = {}
|
||||
L.literal = ""
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -191,7 +190,7 @@ proc fillToken(L: var Token) =
|
||||
L.tokType = tkInvalid
|
||||
L.iNumber = 0
|
||||
L.indent = 0
|
||||
L.strongSpaceA = false
|
||||
L.spacing = {}
|
||||
setLen(L.literal, 0)
|
||||
L.fNumber = 0.0
|
||||
L.base = base10
|
||||
@@ -960,13 +959,15 @@ proc getOperator(L: var Lexer, tok: var Token) =
|
||||
tokenEnd(tok, pos-1)
|
||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||
# be an operator too) gets the preceding spaces:
|
||||
tok.strongSpaceB = tsNone
|
||||
tok.spacing = tok.spacing - {tsTrailing, tsEof}
|
||||
var trailing = false
|
||||
while L.buf[pos] == ' ':
|
||||
inc pos
|
||||
if tok.strongSpaceB != tsTrailing:
|
||||
tok.strongSpaceB = tsTrailing
|
||||
trailing = true
|
||||
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||
tok.strongSpaceB = tsEof
|
||||
tok.spacing.incl(tsEof)
|
||||
elif trailing:
|
||||
tok.spacing.incl(tsTrailing)
|
||||
|
||||
proc getPrecedence*(tok: Token): int =
|
||||
## Calculates the precedence of the given token.
|
||||
@@ -1077,7 +1078,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
|
||||
when defined(nimpretty): tok.literal.add "\L"
|
||||
if isDoc:
|
||||
when not defined(nimpretty): tok.literal.add "\n"
|
||||
inc tok.iNumber
|
||||
var c = toStrip
|
||||
while L.buf[pos] == ' ' and c > 0:
|
||||
inc pos
|
||||
@@ -1096,8 +1096,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
|
||||
proc scanComment(L: var Lexer, tok: var Token) =
|
||||
var pos = L.bufpos
|
||||
tok.tokType = tkComment
|
||||
# iNumber contains the number of '\n' in the token
|
||||
tok.iNumber = 0
|
||||
assert L.buf[pos+1] == '#'
|
||||
when defined(nimpretty):
|
||||
tok.commentOffsetA = L.offsetBase + pos
|
||||
@@ -1140,7 +1138,6 @@ proc scanComment(L: var Lexer, tok: var Token) =
|
||||
while L.buf[pos] == ' ' and c > 0:
|
||||
inc pos
|
||||
dec c
|
||||
inc tok.iNumber
|
||||
else:
|
||||
if L.buf[pos] > ' ':
|
||||
L.indentAhead = indent
|
||||
@@ -1153,7 +1150,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
|
||||
proc skip(L: var Lexer, tok: var Token) =
|
||||
var pos = L.bufpos
|
||||
tokenBegin(tok, pos)
|
||||
tok.strongSpaceA = false
|
||||
tok.spacing.excl(tsLeading)
|
||||
when defined(nimpretty):
|
||||
var hasComment = false
|
||||
var commentIndent = L.currLineIndent
|
||||
@@ -1164,8 +1161,7 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
case L.buf[pos]
|
||||
of ' ':
|
||||
inc(pos)
|
||||
if not tok.strongSpaceA:
|
||||
tok.strongSpaceA = true
|
||||
tok.spacing.incl(tsLeading)
|
||||
of '\t':
|
||||
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
|
||||
inc(pos)
|
||||
@@ -1187,7 +1183,7 @@ proc skip(L: var Lexer, tok: var Token) =
|
||||
pos = L.bufpos
|
||||
else:
|
||||
break
|
||||
tok.strongSpaceA = false
|
||||
tok.spacing.excl(tsLeading)
|
||||
when defined(nimpretty):
|
||||
if L.buf[pos] == '#' and tok.line < 0: commentIndent = indent
|
||||
if L.buf[pos] > ' ' and (L.buf[pos] != '#' or L.buf[pos+1] == '#'):
|
||||
|
||||
@@ -159,7 +159,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
|
||||
let f = n.sym
|
||||
let b = if c.kind == attachedTrace: y else: y.dotField(f)
|
||||
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
|
||||
c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or
|
||||
c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
enforceDefaultOp:
|
||||
defaultOp(c, f.typ, body, x.dotField(f), b)
|
||||
else:
|
||||
@@ -463,6 +463,9 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
body.add genWasMovedCall(c, op, x)
|
||||
result = true
|
||||
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
|
||||
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
|
||||
temp.typ = getSysType(c.g, body.info, tyInt)
|
||||
@@ -546,6 +549,8 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
# follow all elements:
|
||||
forallElements(c, t, body, x, y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
|
||||
@@ -584,6 +589,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
return # protect from recursion
|
||||
body.add newHookCall(c, op, x, y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
@@ -600,6 +607,8 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedTrace:
|
||||
discard "strings are atomic and have no inner elements that are to trace"
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc cyclicType*(t: PType): bool =
|
||||
case t.kind
|
||||
@@ -699,7 +708,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
|
||||
#echo "can follow ", elemType, " static ", isFinal(elemType)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
## Closures are really like refs except they always use a virtual destructor
|
||||
@@ -749,6 +759,8 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedTrace:
|
||||
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case c.kind
|
||||
@@ -774,6 +786,8 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
var actions = newNodeI(nkStmtList, c.info)
|
||||
@@ -800,6 +814,8 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
if c.kind == attachedDeepCopy:
|
||||
@@ -811,7 +827,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
call[1] = y
|
||||
body.add newAsgnStmt(x, call)
|
||||
elif (optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcOrc}:
|
||||
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
xx.typ = getSysType(c.g, c.info, tyPointer)
|
||||
case c.kind
|
||||
@@ -835,6 +851,8 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
|
||||
@@ -851,6 +869,8 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
of attachedDeepCopy: assert(false, "cannot happen")
|
||||
of attachedTrace: discard
|
||||
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
|
||||
of attachedDup:
|
||||
assert false, "cannot happen"
|
||||
|
||||
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
case t.kind
|
||||
@@ -859,7 +879,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
tyPtr, tyUncheckedArray, tyVar, tyLent:
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyRef:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
atomicRefOp(c, t, body, x, y)
|
||||
elif (optOwnedRefs in c.g.config.globalOptions and
|
||||
optRefCheck in c.g.config.options):
|
||||
@@ -868,7 +888,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||
defaultOp(c, t, body, x, y)
|
||||
of tyProc:
|
||||
if t.callConv == ccClosure:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc}:
|
||||
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
atomicClosureOp(c, t, body, x, y)
|
||||
else:
|
||||
closureOp(c, t, body, x, y)
|
||||
@@ -966,7 +986,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
|
||||
|
||||
result.typ = newProcType(info, nextTypeId(idgen), owner)
|
||||
result.typ.addParam dest
|
||||
if kind notin {attachedDestructor, attachedWasMoved}:
|
||||
if kind notin {attachedDestructor, attachedWasMoved, attachedDup}:
|
||||
result.typ.addParam src
|
||||
|
||||
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
|
||||
@@ -1006,7 +1026,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
|
||||
let dest = result.typ.n[1].sym
|
||||
let d = newDeref(newSymNode(dest))
|
||||
let src = if kind in {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
let src = if kind in {attachedDestructor, attachedWasMoved, attachedDup}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
|
||||
else: newSymNode(result.typ.n[2].sym)
|
||||
|
||||
# register this operation already:
|
||||
@@ -1019,7 +1039,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
result.ast[bodyPos].add newAsgnStmt(d, src)
|
||||
else:
|
||||
var tk: TTypeKind
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
|
||||
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
|
||||
else:
|
||||
tk = tyNone # no special casing for strings and seqs
|
||||
|
||||
@@ -95,7 +95,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
|
||||
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
|
||||
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
|
||||
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
|
||||
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
|
||||
sym.kind != skResult and # ignore `result`
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
@@ -136,7 +136,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
|
||||
## Check symbol uses match their definition's style.
|
||||
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
|
||||
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
|
||||
sym.kind != skTemp and # ignore temporary variables created by the compiler
|
||||
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
|
||||
sfAnon notin sym.flags: # ignore temporary variables created by the compiler
|
||||
@@ -147,6 +147,10 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
|
||||
if pragmaName != wanted:
|
||||
lintReport(conf, info, wanted, pragmaName)
|
||||
|
||||
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
|
||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||
checkPragmaUseImpl(conf, info, w, pragmaName)
|
||||
template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
|
||||
## Check builtin pragma uses match their definition's style.
|
||||
## Note: This only applies to builtin pragmas, not user pragmas.
|
||||
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
|
||||
hintName in ctx.config.notes and # ignore if name checks are not requested
|
||||
(sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages
|
||||
checkPragmaUseImpl(ctx.config, info, w, pragmaName)
|
||||
|
||||
@@ -226,7 +226,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile)
|
||||
|
||||
proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
|
||||
assert fileIdx.int32 >= 0
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
conf.m.fileInfos[fileIdx.int32].hash = hash
|
||||
else:
|
||||
shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
|
||||
@@ -234,7 +234,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
|
||||
|
||||
proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
|
||||
assert fileIdx.int32 >= 0
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = conf.m.fileInfos[fileIdx.int32].hash
|
||||
else:
|
||||
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
|
||||
|
||||
@@ -22,7 +22,7 @@ proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent
|
||||
let last = first+identLen(line, first)-1
|
||||
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
|
||||
else:
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||
@@ -38,7 +38,7 @@ proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
|
||||
if line[first] != '#': inc first
|
||||
|
||||
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
|
||||
else:
|
||||
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||
|
||||
@@ -184,6 +184,7 @@ type
|
||||
gcRegions = "regions"
|
||||
gcArc = "arc"
|
||||
gcOrc = "orc"
|
||||
gcAtomicArc = "atomicArc"
|
||||
gcMarkAndSweep = "markAndSweep"
|
||||
gcHooks = "hooks"
|
||||
gcRefc = "refc"
|
||||
|
||||
@@ -301,14 +301,13 @@ proc isRightAssociative(tok: Token): bool {.inline.} =
|
||||
proc isUnary(tok: Token): bool =
|
||||
## Check if the given token is a unary operator
|
||||
tok.tokType in {tkOpr, tkDotDot} and
|
||||
tok.strongSpaceB == tsNone and
|
||||
tok.strongSpaceA
|
||||
tok.spacing == {tsLeading}
|
||||
|
||||
proc checkBinary(p: Parser) {.inline.} =
|
||||
## Check if the current parser token is a binary operator.
|
||||
# we don't check '..' here as that's too annoying
|
||||
if p.tok.tokType == tkOpr:
|
||||
if p.tok.strongSpaceB == tsTrailing and not p.tok.strongSpaceA:
|
||||
if p.tok.spacing == {tsTrailing}:
|
||||
parMessage(p, warnInconsistentSpacing, prettyTok(p.tok))
|
||||
|
||||
#| module = stmt ^* (';' / IND{=})
|
||||
@@ -516,7 +515,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode =
|
||||
optInd(p, result)
|
||||
result.add(a)
|
||||
result.add(parseSymbol(p, smAfterDot))
|
||||
if p.tok.tokType == tkBracketLeColon and not p.tok.strongSpaceA:
|
||||
if p.tok.tokType == tkBracketLeColon and tsLeading notin p.tok.spacing:
|
||||
var x = newNodeI(nkBracketExpr, p.parLineInfo)
|
||||
# rewrite 'x.y[:z]()' to 'y[z](x)'
|
||||
x.add result[1]
|
||||
@@ -525,7 +524,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode =
|
||||
var y = newNodeI(nkCall, p.parLineInfo)
|
||||
y.add x
|
||||
y.add result[0]
|
||||
if p.tok.tokType == tkParLe and not p.tok.strongSpaceA:
|
||||
if p.tok.tokType == tkParLe and tsLeading notin p.tok.spacing:
|
||||
exprColonEqExprListAux(p, tkParRi, y)
|
||||
result = y
|
||||
|
||||
@@ -883,7 +882,7 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
case p.tok.tokType
|
||||
of tkParLe:
|
||||
# progress guaranteed
|
||||
if p.tok.strongSpaceA:
|
||||
if tsLeading in p.tok.spacing:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
@@ -895,13 +894,13 @@ proc primarySuffix(p: var Parser, r: PNode,
|
||||
result = parseGStrLit(p, result)
|
||||
of tkBracketLe:
|
||||
# progress guaranteed
|
||||
if p.tok.strongSpaceA:
|
||||
if tsLeading in p.tok.spacing:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||
of tkCurlyLe:
|
||||
# progress guaranteed
|
||||
if p.tok.strongSpaceA:
|
||||
if tsLeading in p.tok.spacing:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
@@ -2525,7 +2524,7 @@ proc parseAll(p: var Parser): PNode =
|
||||
setEndInfo()
|
||||
|
||||
proc checkFirstLineIndentation*(p: var Parser) =
|
||||
if p.tok.indent != 0 and p.tok.strongSpaceA:
|
||||
if p.tok.indent != 0 and tsLeading in p.tok.spacing:
|
||||
parMessage(p, errInvalidIndentation)
|
||||
|
||||
proc parseTopLevelStmt(p: var Parser): PNode =
|
||||
|
||||
@@ -535,7 +535,7 @@ proc processCompile(c: PContext, n: PNode) =
|
||||
n[i] = c.semConstExpr(c, n[i])
|
||||
case n[i].kind
|
||||
of nkStrLit, nkRStrLit, nkTripleStrLit:
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
result = n[i].strVal
|
||||
else:
|
||||
shallowCopy(result, n[i].strVal)
|
||||
@@ -676,6 +676,7 @@ proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
invalidPragma(c, n)
|
||||
|
||||
var userPragma = newSym(skTemplate, it[1].ident, c.idgen, c.module, it.info, c.config.options)
|
||||
styleCheckDef(c, userPragma)
|
||||
userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1])
|
||||
strTableAdd(c.userPragmas, userPragma)
|
||||
|
||||
@@ -863,7 +864,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
else:
|
||||
let k = whichKeyword(ident)
|
||||
if k in validPragmas:
|
||||
checkPragmaUse(c.config, key.info, k, ident.s)
|
||||
checkPragmaUse(c, key.info, k, ident.s, (if sym != nil: sym else: c.module))
|
||||
case k
|
||||
of wExportc, wExportCpp:
|
||||
makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
|
||||
|
||||
@@ -227,7 +227,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
|
||||
if optOwnedRefs in oldGlobalOptions:
|
||||
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
|
||||
defineSymbol(conf.symbols, "nimv2")
|
||||
if conf.selectedGC in {gcArc, gcOrc}:
|
||||
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
|
||||
defineSymbol(conf.symbols, "nimv2")
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
|
||||
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
|
||||
return false
|
||||
let conf = c.config
|
||||
if conf.selectedGC in {gcArc, gcOrc}:
|
||||
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
let d = skipTypes(dst, abstractInst)
|
||||
let s = skipTypes(src, abstractInst)
|
||||
if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal:
|
||||
|
||||
@@ -1480,7 +1480,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||
let param = params[i].sym
|
||||
let typ = param.typ
|
||||
if isSinkTypeForParam(typ) or
|
||||
(t.config.selectedGC in {gcArc, gcOrc} and
|
||||
(t.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
|
||||
(isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)):
|
||||
createTypeBoundOps(t, typ, param.info)
|
||||
if isOutParam(typ) and param.id notin t.init:
|
||||
|
||||
@@ -1815,9 +1815,12 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType =
|
||||
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
let t = s.typ
|
||||
var noError = false
|
||||
let cond = if op in {attachedDestructor, attachedWasMoved}:
|
||||
let cond = case op
|
||||
of {attachedDestructor, attachedWasMoved}:
|
||||
t.len == 2 and t[0] == nil and t[1].kind == tyVar
|
||||
elif op == attachedTrace:
|
||||
of attachedDup:
|
||||
t.len == 2 and t[0] != nil and t[1].kind == tyVar
|
||||
of attachedTrace:
|
||||
t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer
|
||||
else:
|
||||
t.len >= 2 and t[0] == nil
|
||||
@@ -1843,9 +1846,13 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
if not noError and sfSystemModule notin s.owner.flags:
|
||||
if op == attachedTrace:
|
||||
case op
|
||||
of attachedTrace:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"signature for '=trace' must be proc[T: object](x: var T; env: pointer)")
|
||||
of attachedDup:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"signature for '=dup' must be proc[T: object](x: var T): T")
|
||||
else:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
|
||||
@@ -1938,6 +1945,9 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
of "=wasmoved":
|
||||
if s.magic != mWasMoved:
|
||||
bindTypeHook(c, s, n, attachedWasMoved)
|
||||
of "=dup":
|
||||
if s.magic != mDup:
|
||||
bindTypeHook(c, s, n, attachedDup)
|
||||
else:
|
||||
if sfOverriden in s.flags:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
|
||||
@@ -16,6 +16,7 @@ const
|
||||
errIntLiteralExpected = "integer literal expected"
|
||||
errWrongNumberOfVariables = "wrong number of variables"
|
||||
errInvalidOrderInEnumX = "invalid order in enum '$1'"
|
||||
errOverflowInEnumX = "The enum '$1' exceeds its maximum value ($2)"
|
||||
errOrdinalTypeExpected = "ordinal type expected; given: $1"
|
||||
errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements"
|
||||
errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal"
|
||||
@@ -147,7 +148,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
declarePureEnumField(c, e)
|
||||
if (let conflict = strTableInclReportConflict(symbols, e); conflict != nil):
|
||||
wrongRedefinition(c, e.info, e.name.s, conflict.info)
|
||||
inc(counter)
|
||||
if counter == high(typeof(counter)):
|
||||
if i > 1 and result.n[i-2].sym.position == high(int):
|
||||
localError(c.config, n[i].info, errOverflowInEnumX % [e.name.s, $high(typeof(counter))])
|
||||
else:
|
||||
inc(counter)
|
||||
if isPure and sfExported in result.sym.flags:
|
||||
addPureEnum(c, LazySym(sym: result.sym))
|
||||
if tfNotNil in e.typ.flags and not hasNull:
|
||||
@@ -222,8 +227,8 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
|
||||
|
||||
proc fitDefaultNode(c: PContext, n: PNode): PType =
|
||||
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
|
||||
let oldType = n[^1].typ
|
||||
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
|
||||
let oldType = n[^1].typ
|
||||
n[^1].flags.incl nfSem
|
||||
if n[^2].kind != nkEmpty:
|
||||
if expectedType != nil and oldType != expectedType:
|
||||
@@ -963,7 +968,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
t.rawAddSonNoPropagationOfTypeFlags result
|
||||
result = t
|
||||
else: discard
|
||||
if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc}:
|
||||
if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
result.flags.incl tfHasAsgn
|
||||
|
||||
proc findEnforcedStaticType(t: PType): PType =
|
||||
|
||||
@@ -37,7 +37,7 @@ proc spawnResult*(t: PType; inParallel: bool): TSpawnResult =
|
||||
else: srFlowVar
|
||||
|
||||
proc flowVarKind(c: ConfigRef, t: PType): TFlowVarKind =
|
||||
if c.selectedGC in {gcArc, gcOrc}: fvBlob
|
||||
if c.selectedGC in {gcArc, gcOrc, gcAtomicArc}: fvBlob
|
||||
elif t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC
|
||||
elif containsGarbageCollectedRef(t): fvInvalid
|
||||
else: fvBlob
|
||||
@@ -66,7 +66,7 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator;
|
||||
vpart[2] = if varInit.isNil: v else: vpart[1]
|
||||
varSection.add vpart
|
||||
if varInit != nil:
|
||||
if g.config.selectedGC in {gcArc, gcOrc}:
|
||||
if g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
|
||||
# inject destructors pass will do its own analysis
|
||||
varInit.add newFastMoveStmt(g, newSymNode(result), v)
|
||||
else:
|
||||
|
||||
@@ -121,7 +121,7 @@ template decodeBx(k: untyped) {.dirty.} =
|
||||
ensureKind(k)
|
||||
|
||||
template move(a, b: untyped) {.dirty.} =
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
a = move b
|
||||
else:
|
||||
system.shallowCopy(a, b)
|
||||
@@ -550,7 +550,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
# Used to keep track of where the execution is resumed.
|
||||
var savedPC = -1
|
||||
var savedFrame: PStackFrame
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
|
||||
template updateRegsAlias = discard
|
||||
template regs: untyped = tos.slots
|
||||
else:
|
||||
|
||||
@@ -443,6 +443,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int =
|
||||
result = c.constants.len
|
||||
#assert(n.kind != nkCall)
|
||||
n.flags.incl nfAllConst
|
||||
n.flags.excl nfIsRef
|
||||
c.constants.add n
|
||||
internalAssert c.config, result < regBxMax
|
||||
|
||||
@@ -1400,6 +1401,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
# c.gABx(n, opcNodeToReg, a, a)
|
||||
# c.genAsgnPatch(arg, a)
|
||||
c.freeTemp(a)
|
||||
of mDup:
|
||||
let arg = n[1]
|
||||
let a = c.genx(arg)
|
||||
if dest < 0: dest = c.getTemp(arg.typ)
|
||||
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), dest, a)
|
||||
c.freeTemp(a)
|
||||
of mNodeId:
|
||||
c.genUnaryABC(n, dest, opcNodeId)
|
||||
else:
|
||||
|
||||
@@ -364,3 +364,9 @@ tcc.options.always = "-w"
|
||||
clang.options.linker %= "${clang.options.linker} -s"
|
||||
clang.cpp.options.linker %= "${clang.cpp.options.linker} -s"
|
||||
@end
|
||||
|
||||
# Linker: Skip "Build-ID metadata strings" in binaries when build for release.
|
||||
@if release or danger:
|
||||
gcc.options.linker %= "${gcc.options.linker} -Wl,--build-id=none"
|
||||
gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -Wl,--build-id=none"
|
||||
@end
|
||||
|
||||
@@ -7485,6 +7485,37 @@ generates:
|
||||
```
|
||||
|
||||
|
||||
size pragma
|
||||
-----------
|
||||
Nim automatically determines the size of an enum.
|
||||
But when wrapping a C enum type, it needs to be of a specific size.
|
||||
The `size pragma` allows specifying the size of the enum type.
|
||||
|
||||
```Nim
|
||||
type
|
||||
EventType* {.size: sizeof(uint32).} = enum
|
||||
QuitEvent,
|
||||
AppTerminating,
|
||||
AppLowMemory
|
||||
|
||||
doAssert sizeof(EventType) == sizeof(uint32)
|
||||
```
|
||||
|
||||
The `size pragma` can also specify the size of an `importc` incomplete object type
|
||||
so that one can get the size of it at compile time even if it was declared without fields.
|
||||
|
||||
```Nim
|
||||
type
|
||||
AtomicFlag* {.importc: "atomic_flag", header: "<stdatomic.h>", size: 1.} = object
|
||||
|
||||
static:
|
||||
# if AtomicFlag didn't have the size pragma, this code would result in a compile time error.
|
||||
echo sizeof(AtomicFlag)
|
||||
```
|
||||
|
||||
The `size pragma` accepts only the values 1, 2, 4 or 8.
|
||||
|
||||
|
||||
Align pragma
|
||||
------------
|
||||
|
||||
@@ -8041,8 +8072,8 @@ CodegenDecl pragma
|
||||
------------------
|
||||
|
||||
The `codegenDecl` pragma can be used to directly influence Nim's code
|
||||
generator. It receives a format string that determines how the variable
|
||||
or proc is declared in the generated code.
|
||||
generator. It receives a format string that determines how the variable,
|
||||
proc or object type is declared in the generated code.
|
||||
|
||||
For variables, $1 in the format string represents the type of the variable,
|
||||
$2 is the name of the variable, and each appearance of $# represents $1/$2
|
||||
@@ -8077,7 +8108,30 @@ will generate this code:
|
||||
```c
|
||||
__interrupt void myinterrupt()
|
||||
```
|
||||
|
||||
For object types, the $1 represents the name of the object type, $2 is the list of
|
||||
fields and $3 is the base type.
|
||||
|
||||
```nim
|
||||
|
||||
const strTemplate = """
|
||||
struct $1 {
|
||||
$2
|
||||
};
|
||||
"""
|
||||
type Foo {.codegenDecl:strTemplate.} = object
|
||||
a, b: int
|
||||
```
|
||||
|
||||
will generate this code:
|
||||
|
||||
|
||||
```c
|
||||
struct Foo {
|
||||
NI a;
|
||||
NI b;
|
||||
};
|
||||
```
|
||||
|
||||
`cppNonPod` pragma
|
||||
------------------
|
||||
|
||||
@@ -125,7 +125,13 @@ __AVR__
|
||||
NIM_THREADVAR declaration based on
|
||||
http://stackoverflow.com/questions/18298280/how-to-declare-a-variable-as-thread-local-portably
|
||||
*/
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
|
||||
#if defined _WIN32
|
||||
# if defined _MSC_VER || defined __DMC__ || defined __BORLANDC__
|
||||
# define NIM_THREADVAR __declspec(thread)
|
||||
# else
|
||||
# define NIM_THREADVAR __thread
|
||||
# endif
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
|
||||
# define NIM_THREADVAR _Thread_local
|
||||
#elif defined _WIN32 && ( \
|
||||
defined _MSC_VER || \
|
||||
|
||||
@@ -347,6 +347,12 @@ proc arrPut[I: Ordinal;T,S](a: T; i: I;
|
||||
proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} =
|
||||
## Generic `destructor`:idx: implementation that can be overridden.
|
||||
discard
|
||||
|
||||
when defined(nimHasDup):
|
||||
proc `=dup`*[T](x: ref T): ref T {.inline, magic: "Dup".} =
|
||||
## Generic `dup` implementation that can be overridden.
|
||||
discard
|
||||
|
||||
proc `=sink`*[T](x: var T; y: T) {.inline, nodestroy, magic: "Asgn".} =
|
||||
## Generic `sink`:idx: implementation that can be overridden.
|
||||
when defined(gcArc) or defined(gcOrc):
|
||||
|
||||
@@ -57,6 +57,21 @@ elif defined(nimArcIds):
|
||||
|
||||
const traceId = -1
|
||||
|
||||
when defined(gcAtomicArc) and hasThreadSupport:
|
||||
template decrement(cell: Cell): untyped =
|
||||
discard atomicDec(cell.rc, rcIncrement)
|
||||
template increment(cell: Cell): untyped =
|
||||
discard atomicInc(cell.rc, rcIncrement)
|
||||
template count(x: Cell): untyped =
|
||||
atomicLoadN(x.rc.addr, ATOMIC_ACQUIRE) shr rcShift
|
||||
else:
|
||||
template decrement(cell: Cell): untyped =
|
||||
dec(cell.rc, rcIncrement)
|
||||
template increment(cell: Cell): untyped =
|
||||
inc(cell.rc, rcIncrement)
|
||||
template count(x: Cell): untyped =
|
||||
x.rc shr rcShift
|
||||
|
||||
proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
let s = size + hdrSize
|
||||
@@ -69,7 +84,7 @@ proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
|
||||
atomicInc gRefId
|
||||
if head(result).refId == traceId:
|
||||
writeStackTrace()
|
||||
cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).rc shr rcShift)
|
||||
cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).count)
|
||||
when traceCollector:
|
||||
cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result)
|
||||
|
||||
@@ -90,21 +105,21 @@ proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} =
|
||||
atomicInc gRefId
|
||||
if head(result).refId == traceId:
|
||||
writeStackTrace()
|
||||
cfprintf(cstderr, "[nimNewObjUninit] %p %ld\n", result, head(result).rc shr rcShift)
|
||||
cfprintf(cstderr, "[nimNewObjUninit] %p %ld\n", result, head(result).count)
|
||||
|
||||
when traceCollector:
|
||||
cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result)
|
||||
|
||||
proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} =
|
||||
dec head(p).rc, rcIncrement
|
||||
decrement head(p)
|
||||
|
||||
proc nimIncRef(p: pointer) {.compilerRtl, inl.} =
|
||||
when defined(nimArcDebug):
|
||||
if head(p).refId == traceId:
|
||||
writeStackTrace()
|
||||
cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).rc shr rcShift)
|
||||
cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).count)
|
||||
|
||||
inc head(p).rc, rcIncrement
|
||||
increment head(p)
|
||||
when traceCollector:
|
||||
cprintf("[INCREF] %p\n", head(p))
|
||||
|
||||
@@ -173,17 +188,21 @@ proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} =
|
||||
when defined(nimArcDebug):
|
||||
if cell.refId == traceId:
|
||||
writeStackTrace()
|
||||
cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.rc shr rcShift)
|
||||
cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.count)
|
||||
|
||||
if (cell.rc and not rcMask) == 0:
|
||||
if cell.count == 0:
|
||||
result = true
|
||||
when traceCollector:
|
||||
cprintf("[ABOUT TO DESTROY] %p\n", cell)
|
||||
else:
|
||||
dec cell.rc, rcIncrement
|
||||
decrement cell
|
||||
# According to Lins it's correct to do nothing else here.
|
||||
when traceCollector:
|
||||
cprintf("[DeCREF] %p\n", cell)
|
||||
cprintf("[DECREF] %p\n", cell)
|
||||
|
||||
proc nimDupRef(dest: ptr pointer, src: pointer) {.compilerRtl, inl.} =
|
||||
dest[] = src
|
||||
if src != nil: nimIncRef src
|
||||
|
||||
proc GC_unref*[T](x: ref T) =
|
||||
## New runtime only supports this operation for 'ref T'.
|
||||
|
||||
@@ -16,18 +16,21 @@ type
|
||||
d: PCellArray
|
||||
|
||||
proc contains(s: CellSeq, c: PCell): bool {.inline.} =
|
||||
for i in 0 .. s.len-1:
|
||||
if s.d[i] == c: return true
|
||||
for i in 0 ..< s.len:
|
||||
if s.d[i] == c:
|
||||
return true
|
||||
return false
|
||||
|
||||
proc resize(s: var CellSeq) =
|
||||
s.cap = s.cap * 3 div 2
|
||||
let d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
|
||||
copyMem(d, s.d, s.len * sizeof(PCell))
|
||||
dealloc(s.d)
|
||||
s.d = d
|
||||
|
||||
proc add(s: var CellSeq, c: PCell) {.inline.} =
|
||||
if s.len >= s.cap:
|
||||
s.cap = s.cap * 3 div 2
|
||||
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
|
||||
copyMem(d, s.d, s.len * sizeof(PCell))
|
||||
dealloc(s.d)
|
||||
s.d = d
|
||||
# XXX: realloc?
|
||||
resize(s)
|
||||
s.d[s.len] = c
|
||||
inc(s.len)
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
if not em.endsInWhite: wr(" ")
|
||||
wr(tok.ident.s)
|
||||
template isUnary(tok): bool =
|
||||
tok.strongSpaceB == tsNone and tok.strongSpaceA
|
||||
tok.spacing == {tsLeading}
|
||||
|
||||
if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}:
|
||||
wr(" ")
|
||||
|
||||
@@ -272,7 +272,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
if not em.endsInWhite: wr(" ")
|
||||
wr(tok.ident.s)
|
||||
template isUnary(tok): bool =
|
||||
tok.strongSpaceB == tsNone and tok.strongSpaceA
|
||||
tok.spacing == {tsLeading}
|
||||
|
||||
if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}:
|
||||
wr(" ")
|
||||
|
||||
70
tests/arc/tdup.nim
Normal file
70
tests/arc/tdup.nim
Normal file
@@ -0,0 +1,70 @@
|
||||
discard """
|
||||
cmd: "nim c --mm:arc --expandArc:foo --hints:off $file"
|
||||
nimout: '''
|
||||
--expandArc: foo
|
||||
|
||||
var
|
||||
x
|
||||
:tmpD
|
||||
s
|
||||
:tmpD_1
|
||||
x = Ref(id: 8)
|
||||
inc:
|
||||
:tmpD = `=dup`(x)
|
||||
:tmpD
|
||||
inc:
|
||||
let blitTmp = x
|
||||
blitTmp
|
||||
var id_1 = 777
|
||||
s = RefCustom(id_2: addr(id_1))
|
||||
inc_1 :
|
||||
:tmpD_1 = `=dup`(s)
|
||||
:tmpD_1
|
||||
inc_1 :
|
||||
let blitTmp_1 = s
|
||||
blitTmp_1
|
||||
-- end of expandArc ------------------------
|
||||
'''
|
||||
"""
|
||||
|
||||
type
|
||||
Ref = ref object
|
||||
id: int
|
||||
|
||||
RefCustom = object
|
||||
id: ptr int
|
||||
|
||||
proc inc(x: sink Ref) =
|
||||
inc x.id
|
||||
|
||||
proc inc(x: sink RefCustom) =
|
||||
inc x.id[]
|
||||
|
||||
proc `=dup`(x: var RefCustom): RefCustom =
|
||||
result.id = x.id
|
||||
|
||||
proc foo =
|
||||
var x = Ref(id: 8)
|
||||
inc(x)
|
||||
inc(x)
|
||||
var id = 777
|
||||
var s = RefCustom(id: addr id)
|
||||
inc s
|
||||
inc s
|
||||
|
||||
foo()
|
||||
|
||||
proc foo2 =
|
||||
var x = Ref(id: 8)
|
||||
inc(x)
|
||||
doAssert x.id == 9
|
||||
inc(x)
|
||||
doAssert x.id == 10
|
||||
var id = 777
|
||||
var s = RefCustom(id: addr id)
|
||||
inc s
|
||||
doAssert s.id[] == 778
|
||||
inc s
|
||||
doAssert s.id[] == 779
|
||||
|
||||
foo2()
|
||||
@@ -113,8 +113,7 @@ block :tmp:
|
||||
var :tmpD
|
||||
sym = shadowScope.symbols[i]
|
||||
addInterfaceDecl(c):
|
||||
`=wasMoved`(:tmpD)
|
||||
`=copy_1`(:tmpD, sym)
|
||||
:tmpD = `=dup`(sym)
|
||||
:tmpD
|
||||
inc(i, 1)
|
||||
`=destroy`(shadowScope)
|
||||
|
||||
@@ -176,3 +176,11 @@ block: # bug #12589
|
||||
|
||||
when not defined(gcRefc):
|
||||
doAssert $typ() == "wkbPoint25D"
|
||||
|
||||
block: # bug #21280
|
||||
type
|
||||
Test = enum
|
||||
B = 19
|
||||
A = int64.high()
|
||||
|
||||
doAssert ord(A) == int64.high()
|
||||
|
||||
@@ -591,6 +591,29 @@ template main {.dirty.} =
|
||||
|
||||
mainSync()
|
||||
|
||||
block: # bug #21801
|
||||
func evaluate(i: int): float =
|
||||
0.0
|
||||
|
||||
func evaluate(): float =
|
||||
0.0
|
||||
|
||||
type SearchOptions = object
|
||||
evaluation: proc(): float = evaluate
|
||||
|
||||
block:
|
||||
func evaluate(): float =
|
||||
0.0
|
||||
|
||||
type SearchOptions = object
|
||||
evaluation: proc(): float = evaluate
|
||||
|
||||
block:
|
||||
func evaluate(i: int): float =
|
||||
0.0
|
||||
|
||||
type SearchOptions = object
|
||||
evaluation = evaluate
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
1
tests/stylecheck/foreign_package/foreign_package.nim
Normal file
1
tests/stylecheck/foreign_package/foreign_package.nim
Normal file
@@ -0,0 +1 @@
|
||||
include ../thint
|
||||
2
tests/stylecheck/foreign_package/foreign_package.nimble
Normal file
2
tests/stylecheck/foreign_package/foreign_package.nimble
Normal file
@@ -0,0 +1,2 @@
|
||||
# See `tstyleCheck`
|
||||
# Needed to mark `mstyleCheck` as a foreign package.
|
||||
16
tests/stylecheck/tforeign_package.nim
Normal file
16
tests/stylecheck/tforeign_package.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
discard """
|
||||
matrix: "--errorMax:0 --styleCheck:error"
|
||||
action: compile
|
||||
"""
|
||||
|
||||
import foreign_package/foreign_package
|
||||
|
||||
# This call tests that:
|
||||
# - an instantiation of a generic in a foreign package doesn't raise errors
|
||||
# when the generic body contains:
|
||||
# - definition and usage violations
|
||||
# - builtin pragma usage violations
|
||||
# - user pragma usage violations
|
||||
# - definition violations in foreign packages are ignored
|
||||
# - usage violations in foreign packages are ignored
|
||||
genericProc[int]()
|
||||
43
tests/stylecheck/thint.nim
Normal file
43
tests/stylecheck/thint.nim
Normal file
@@ -0,0 +1,43 @@
|
||||
discard """
|
||||
matrix: "--styleCheck:hint"
|
||||
action: compile
|
||||
"""
|
||||
|
||||
# Test violating ident definition:
|
||||
{.pragma: user_pragma.} #[tt.Hint
|
||||
^ 'user_pragma' should be: 'userPragma' [Name] ]#
|
||||
|
||||
# Test violating ident usage style matches definition style:
|
||||
{.userPragma.} #[tt.Hint
|
||||
^ 'userPragma' should be: 'user_pragma' [template declared in thint.nim(7, 9)] [Name] ]#
|
||||
|
||||
# Test violating builtin pragma usage style:
|
||||
{.no_side_effect.}: #[tt.Hint
|
||||
^ 'no_side_effect' should be: 'noSideEffect' [Name] ]#
|
||||
discard 0
|
||||
|
||||
# Test:
|
||||
# - definition style violation
|
||||
# - user pragma usage style violation
|
||||
# - builtin pragma usage style violation
|
||||
proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Hint
|
||||
^ 'generic_proc' should be: 'genericProc' [Name]; tt.Hint
|
||||
^ 'no_destroy' should be: 'nodestroy' [Name]; tt.Hint
|
||||
^ 'userPragma' should be: 'user_pragma' [template declared in thint.nim(7, 9)] [Name] ]#
|
||||
# Test definition style violation:
|
||||
let snake_case = 0 #[tt.Hint
|
||||
^ 'snake_case' should be: 'snakeCase' [Name] ]#
|
||||
# Test user pragma definition style violation:
|
||||
{.pragma: another_user_pragma.} #[tt.Hint
|
||||
^ 'another_user_pragma' should be: 'anotherUserPragma' [Name] ]#
|
||||
# Test user pragma usage style violation:
|
||||
{.anotherUserPragma.} #[tt.Hint
|
||||
^ 'anotherUserPragma' should be: 'another_user_pragma' [template declared in thint.nim(31, 11)] [Name] ]#
|
||||
# Test violating builtin pragma usage style:
|
||||
{.no_side_effect.}: #[tt.Hint
|
||||
^ 'no_side_effect' should be: 'noSideEffect' [Name] ]#
|
||||
# Test usage style violation:
|
||||
discard snakeCase #[tt.Hint
|
||||
^ 'snakeCase' should be: 'snake_case' [let declared in thint.nim(28, 7)] [Name] ]#
|
||||
|
||||
generic_proc[int]()
|
||||
69
tests/vm/t21704.nim
Normal file
69
tests/vm/t21704.nim
Normal file
@@ -0,0 +1,69 @@
|
||||
discard """
|
||||
matrix: "--hints:off"
|
||||
nimout: '''
|
||||
Found 2 tests to run.
|
||||
Found 3 benches to compile.
|
||||
|
||||
--passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow
|
||||
|
||||
--passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow
|
||||
|
||||
--passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow
|
||||
'''
|
||||
"""
|
||||
# bug #21704
|
||||
import std/strformat
|
||||
|
||||
const testDesc: seq[string] = @[
|
||||
"tests/t_hash_sha256_vs_openssl.nim",
|
||||
"tests/t_cipher_chacha20.nim"
|
||||
]
|
||||
const benchDesc = [
|
||||
"bench_sha256",
|
||||
"bench_hash_to_curve",
|
||||
"bench_ethereum_bls_signatures"
|
||||
]
|
||||
|
||||
proc setupTestCommand(flags, path: string): string =
|
||||
return "nim c -r " &
|
||||
flags &
|
||||
&" --nimcache:nimcache/{path} " & # Commenting this out also solves the issue
|
||||
path
|
||||
|
||||
proc testBatch(commands: var string, flags, path: string) =
|
||||
commands &= setupTestCommand(flags, path) & '\n'
|
||||
|
||||
proc setupBench(benchName: string): string =
|
||||
var runFlags = if false: " -r "
|
||||
else: " " # taking this branch is needed to trigger the bug
|
||||
|
||||
echo runFlags # Somehow runflags isn't reset in corner cases
|
||||
runFlags &= " --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow "
|
||||
echo runFlags
|
||||
|
||||
return "nim c " &
|
||||
runFlags &
|
||||
&" benchmarks/{benchName}.nim"
|
||||
|
||||
proc buildBenchBatch(commands: var string, benchName: string) =
|
||||
let command = setupBench(benchName)
|
||||
commands &= command & '\n'
|
||||
|
||||
proc addTestSet(cmdFile: var string) =
|
||||
echo "Found " & $testDesc.len & " tests to run."
|
||||
|
||||
for path in testDesc:
|
||||
var flags = "" # This is important
|
||||
cmdFile.testBatch(flags, path)
|
||||
|
||||
proc addBenchSet(cmdFile: var string) =
|
||||
echo "Found " & $benchDesc.len & " benches to compile."
|
||||
for bd in benchDesc:
|
||||
cmdFile.buildBenchBatch(bd)
|
||||
|
||||
proc task_bug() =
|
||||
var cmdFile: string
|
||||
cmdFile.addTestSet() # Comment this out and there is no bug
|
||||
cmdFile.addBenchSet()
|
||||
|
||||
static: task_bug()
|
||||
Reference in New Issue
Block a user