diff options
author | Dominik Picheta <dominikpicheta@googlemail.com> | 2017-02-07 18:34:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-07 18:34:05 +0100 |
commit | d5bb5e832bdc42153794a7ce08661d4515a46662 (patch) | |
tree | 131cb69514f840f427f542f8584b5998f10b9fe8 /compiler | |
parent | b7d7feffee9d02c60f80745606edf4ac00321aae (diff) | |
parent | 7c15120247f93cc1b729d33f0af592bc8e5e9937 (diff) | |
download | Nim-d5bb5e832bdc42153794a7ce08661d4515a46662.tar.gz |
Merge branch 'devel' into feature/3691
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 8 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 36 | ||||
-rw-r--r-- | compiler/ccgthreadvars.nim | 4 | ||||
-rw-r--r-- | compiler/ccgtrav.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 107 | ||||
-rw-r--r-- | compiler/ccgutils.nim | 56 | ||||
-rw-r--r-- | compiler/cgen.nim | 49 | ||||
-rw-r--r-- | compiler/cgendata.nim | 14 | ||||
-rw-r--r-- | compiler/commands.nim | 16 | ||||
-rw-r--r-- | compiler/condsyms.nim | 1 | ||||
-rw-r--r-- | compiler/docgen.nim | 40 | ||||
-rw-r--r-- | compiler/extccomp.nim | 14 | ||||
-rw-r--r-- | compiler/installer.ini | 12 | ||||
-rw-r--r-- | compiler/main.nim | 4 | ||||
-rw-r--r-- | compiler/modulegraphs.nim | 9 | ||||
-rw-r--r-- | compiler/msgs.nim | 4 | ||||
-rw-r--r-- | compiler/ndi.nim | 40 | ||||
-rw-r--r-- | compiler/nim.nim | 12 | ||||
-rw-r--r-- | compiler/nimconf.nim | 106 | ||||
-rw-r--r-- | compiler/options.nim | 13 | ||||
-rw-r--r-- | compiler/pragmas.nim | 10 | ||||
-rw-r--r-- | compiler/scriptconfig.nim | 19 | ||||
-rw-r--r-- | compiler/semexprs.nim | 2 | ||||
-rw-r--r-- | compiler/seminst.nim | 11 | ||||
-rw-r--r-- | compiler/semtempl.nim | 11 | ||||
-rw-r--r-- | compiler/semtypes.nim | 13 | ||||
-rw-r--r-- | compiler/suggest.nim | 14 | ||||
-rw-r--r-- | compiler/vm.nim | 8 | ||||
-rw-r--r-- | compiler/vmgen.nim | 18 |
30 files changed, 411 insertions, 245 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 4ea68dc99..8fbec64cf 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1541,7 +1541,8 @@ proc skipGenericOwner*(s: PSym): PSym = ## Generic instantiations are owned by their originating generic ## symbol. This proc skips such owners and goes straight to the owner ## of the generic itself (the module or the enclosing proc). - result = if s.kind in skProcKinds and sfFromGeneric in s.flags: + result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags == + {sfFromGeneric}: s.owner.owner else: s.owner diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index eabcdd66a..ade2cb41f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1210,7 +1210,7 @@ proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) = proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) = var elem, a, arr: TLoc - if t.kind == nkBracket: + if t.sons[1].kind == nkBracket: t.sons[1].typ = t.typ genSeqConstr(p, t.sons[1], d) return @@ -1383,7 +1383,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = var a, b: TLoc assert(d.k == locNone) - initLocExpr(p, e.sons[1], a) + var x = e.sons[1] + if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] + initLocExpr(p, x, a) initLocExpr(p, e.sons[2], b) let t = skipTypes(e.sons[1].typ, {tyVar}) let setLenPattern = if not p.module.compileToCpp: @@ -2001,7 +2003,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sfThread in sym.flags: accessThreadLocalVar(p, sym) if emulatedThreadVars(): - putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r) + putIntoDest(p, d, sym.loc.t, "NimTV_->" & sym.loc.r) else: putLocIntoDest(p, d, sym.loc) else: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index b3d21c35e..45d675f64 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -64,7 +64,7 @@ proc genVarTuple(p: BProc, n: PNode) = field.r = "$1.Field$2" % [rdLoc(tup), rope(i)] else: if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple") - field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)] + field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)] putLocIntoDest(p, v.loc, field) proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) @@ -102,7 +102,7 @@ proc assignLabel(b: var TBlock): Rope {.inline.} = proc blockBody(b: var TBlock): Rope = result = b.sections[cpsLocals] if b.frameLen > 0: - result.addf("FR.len+=$1;$n", [b.frameLen.rope]) + result.addf("FR_.len+=$1;$n", [b.frameLen.rope]) result.add(b.sections[cpsInit]) result.add(b.sections[cpsStmts]) @@ -123,7 +123,7 @@ proc endBlock(p: BProc) = ~"}$n" let frameLen = p.blocks[topBlock].frameLen if frameLen > 0: - blockEnd.addf("FR.len-=$1;$n", [frameLen.rope]) + blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) endBlock(p, blockEnd) proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = @@ -156,7 +156,7 @@ proc genGotoState(p: BProc, n: PNode) = initLocExpr(p, n.sons[0], a) lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)]) p.beforeRetNeeded = true - lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", []) + lineF(p, cpsStmts, "case -1: goto BeforeRet_;$n", []) for i in 0 .. lastOrd(n.sons[0].typ): lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)]) lineF(p, cpsStmts, "}$n", []) @@ -373,7 +373,7 @@ proc genReturnStmt(p: BProc, t: PNode) = # consume it before we return. var safePoint = p.finallySafePoints[p.finallySafePoints.len-1] linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint) - lineF(p, cpsStmts, "goto BeforeRet;$n", []) + lineF(p, cpsStmts, "goto BeforeRet_;$n", []) proc genGotoForCase(p: BProc; caseStmt: PNode) = for i in 1 .. <caseStmt.len: @@ -411,11 +411,11 @@ proc genComputedGoto(p: BProc; n: PNode) = localError(n.info, "no case statement found for computed goto"); return var id = p.labels+1 inc p.labels, arraySize+1 - let tmp = "TMP$1" % [id.rope] + let tmp = "TMP$1_" % [id.rope] var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope] for i in 1..arraySize-1: - gotoArray.addf("&&TMP$#, ", [(id+i).rope]) - gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope]) + gotoArray.addf("&&TMP$#_, ", [(id+i).rope]) + gotoArray.addf("&&TMP$#_};$n", [(id+arraySize).rope]) line(p, cpsLocals, gotoArray) let topBlock = p.blocks.len-1 @@ -445,7 +445,7 @@ proc genComputedGoto(p: BProc; n: PNode) = localError(it.info, "range notation not available for computed goto") return let val = getOrdValue(it.sons[j]) - lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)]) + lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)]) genStmts(p, it.lastSon) #for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB #for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA @@ -600,7 +600,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc, for i in 1..until: # bug #4230: avoid false sharing between branches: if d.k == locTemp and isEmptyType(t.typ): d.k = locNone - lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)]) + lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)]) if t.sons[i].kind == nkOfBranch: var length = sonsLen(t.sons[i]) exprBlock(p, t.sons[i].sons[length - 1], d) @@ -618,15 +618,15 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc, inc(p.labels) if t.sons[i].kind == nkOfBranch: # else statement genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, - "LA" & rope(p.labels)) + "LA" & rope(p.labels) & "_") else: - lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)]) + lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)]) if until < t.len-1: inc(p.labels) var gotoTarget = p.labels - lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)]) + lineF(p, cpsStmts, "goto LA$1_;$n", [rope(gotoTarget)]) result = genCaseSecondPass(p, t, d, labId, until) - lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)]) + lineF(p, cpsStmts, "LA$1_: ;$n", [rope(gotoTarget)]) else: result = genCaseSecondPass(p, t, d, labId, until) @@ -664,7 +664,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) = for i in countup(1, sonsLen(t) - 1): inc(p.labels) if t.sons[i].kind == nkOfBranch: - genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels), + genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels) & "_", branches) else: # else statement: nothing to do yet @@ -678,7 +678,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) = [intLiteral(j), branches[j]]) lineF(p, cpsStmts, "}$n", []) # else statement: if t.sons[sonsLen(t)-1].kind != nkOfBranch: - lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)]) + lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)]) # third pass: generate statements var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1) fixLabel(p, lend) @@ -802,7 +802,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let length = sonsLen(t) endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc])) if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n") + linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") inc p.inExceptBlock var i = 1 var catchAllPresent = false @@ -910,7 +910,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = startBlock(p, "else {$n") linefmt(p, cpsStmts, "#popSafePoint();$n") if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n") + linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") inc p.inExceptBlock var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 81af89249..3efddbf30 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -19,9 +19,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) = if emulatedThreadVars() and not p.threadVarAccessed: p.threadVarAccessed = true incl p.module.flags, usesThreadVars - addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", []) + addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", []) add(p.procSec(cpsInit), - ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n")) + ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n")) var nimtv: Rope # Nim thread vars; the struct body diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 6dab003fd..547504afb 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -145,7 +145,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope = if sfThread in s.flags and emulatedThreadVars(): accessThreadLocalVar(p, s) - sLoc = "NimTV->" & sLoc + sLoc = "NimTV_->" & sLoc c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n" c.p = p diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8a11f954f..e30fe5598 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -22,12 +22,10 @@ proc isKeyword(w: PIdent): bool = ord(wInline): return true else: return false -proc mangleField(name: PIdent): string = +proc mangleField(m: BModule; name: PIdent): string = result = mangle(name.s) - if isKeyword(name): - result[0] = result[0].toUpperAscii - # Mangling makes everything lowercase, - # but some identifiers are C keywords + if isKeyword(name) or m.g.config.cppDefines.contains(result): + result.add "_0" when false: proc hashOwner(s: PSym): SigHash = @@ -67,55 +65,50 @@ proc idOrSig(m: BModule; s: PSym): Rope = proc mangleName(m: BModule; s: PSym): Rope = result = s.loc.r if result == nil: - let keepOrigName = s.kind in skLocalVars - {skForVar} and - {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and - not isKeyword(s.name) - # Even with all these inefficient checks, the bootstrap - # time is actually improved. This is probably because so many - # rope concatenations are now eliminated. - # - # sfFromGeneric is needed in order to avoid multiple - # definitions of certain variables generated in transf with - # names such as: - # `r`, `res` - # I need to study where these come from. - # - # about sfShadowed: - # consider the following Nim code: - # var x = 10 - # block: - # var x = something(x) - # The generated C code will be: - # NI x; - # x = 10; - # { - # NI x; - # x = something(x); // Oops, x is already shadowed here - # } - # Right now, we work-around by not keeping the original name - # of the shadowed variable, but we can do better - we can - # create an alternative reference to it in the outer scope and - # use that in the inner scope. - # - # about isCKeyword: - # Nim variable names can be C keywords. - # We need to avoid such names in the generated code. - # - # about sfGlobal: - # This seems to be harder - a top level extern variable from - # another modules can have the same name as a local one. - # Maybe we should just implement sfShadowed for them too. - # - # about skForVar: - # These are not properly scoped now - we need to add blocks - # around for loops in transf result = s.name.s.mangle.rope - if keepOrigName: - result.add "0" - else: - add(result, m.idOrSig(s)) + add(result, m.idOrSig(s)) + s.loc.r = result + writeMangledName(m.ndi, s) + +proc mangleParamName(m: BModule; s: PSym): Rope = + ## we cannot use 'sigConflicts' here since we have a BModule, not a BProc. + ## Fortunately C's scoping rules are sane enough so that that doesn't + ## cause any trouble. + result = s.loc.r + if result == nil: + var res = s.name.s.mangle + if isKeyword(s.name) or m.g.config.cppDefines.contains(res): + res.add "_0" + result = res.rope + s.loc.r = result + writeMangledName(m.ndi, s) + +proc mangleLocalName(p: BProc; s: PSym): Rope = + assert s.kind in skLocalVars+{skTemp} + assert sfGlobal notin s.flags + result = s.loc.r + if result == nil: + var key = s.name.s.mangle + shallow(key) + let counter = p.sigConflicts.getOrDefault(key) + result = key.rope + if s.kind == skTemp: + # speed up conflict search for temps (these are quite common): + if counter != 0: result.add "_" & rope(counter+1) + elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key): + result.add "_" & rope(counter+1) + p.sigConflicts.inc(key) s.loc.r = result + if s.kind != skTemp: writeMangledName(p.module.ndi, s) +proc scopeMangledParam(p: BProc; param: PSym) = + ## parameter generation only takes BModule, not a BProc, so we have to + ## remember these parameter names are already in scope to be able to + ## generate unique identifiers reliably (consider that ``var a = a`` is + ## even an idiom in Nim). + var key = param.name.s.mangle + shallow(key) + p.sigConflicts.inc(key) const irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation, @@ -393,7 +386,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, var param = t.n.sons[i].sym if isCompileTimeOnly(param.typ): continue if params != nil: add(params, ~", ") - fillLoc(param.loc, locParam, param.typ, mangleName(m, param), + fillLoc(param.loc, locParam, param.typ, mangleParamName(m, param), param.paramStorageLoc) if ccgIntroducedPtr(param): add(params, getTypeDescWeak(m, param.typ, check)) @@ -436,12 +429,12 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, else: add(params, ")") params = "(" & params -proc mangleRecFieldName(field: PSym, rectype: PType): Rope = +proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope = if (rectype.sym != nil) and ({sfImportc, sfExportc} * rectype.sym.flags != {}): result = field.loc.r else: - result = rope(mangleField(field.name)) + result = rope(mangleField(m, field.name)) if result == nil: internalError(field.info, "mangleRecFieldName") proc genRecordFieldsAux(m: BModule, n: PNode, @@ -480,7 +473,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, let field = n.sym if field.typ.kind == tyVoid: return #assert(field.ast == nil) - let sname = mangleRecFieldName(field, rectype) + let sname = mangleRecFieldName(m, field, rectype) let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname] else: sname fillLoc(field.loc, locField, field.typ, ae, OnUnknown) @@ -1103,13 +1096,11 @@ proc genTypeInfo(m: BModule, t: PType): Rope = discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") addf(m.s[cfsVars], "extern TNimType $1;$n", [result]) - #return "(&".rope & result & ")".rope - #result = "NTI$1" % [rope($sig)] # also store in local type section: m.typeInfoMarker[sig] = result return "(&".rope & result & ")".rope - result = "NTI$1" % [rope($sig)] + result = "NTI$1_" % [rope($sig)] m.typeInfoMarker[sig] = result let owner = t.skipTypes(typedescPtrs).owner.getModule diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 4d6ba858c..d42f0438f 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -164,28 +164,50 @@ proc makeSingleLineCString*(s: string): string = result.add('\"') proc mangle*(name: string): string = - ## Lowercases the given name and manges any non-alphanumeric characters - ## so they are represented as `HEX____`. If the name starts with a number, - ## `N` is prepended result = newStringOfCap(name.len) - case name[0] - of Letters: - result.add(name[0]) - of Digits: - result.add("N" & name[0]) - else: - result = "HEX" & toHex(ord(name[0]), 2) - for i in 1..(name.len-1): + var start = 0 + if name[0] in Digits: + result.add("X" & name[0]) + start = 1 + var requiresUnderscore = false + template special(x) = + result.add x + requiresUnderscore = true + for i in start..(name.len-1): let c = name[i] case c - of 'A'..'Z': - add(result, c.toLowerAscii) - of '_': - discard - of 'a'..'z', '0'..'9': + of 'a'..'z', '0'..'9', 'A'..'Z': add(result, c) + of '_': + # we generate names like 'foo_9' for scope disambiguations and so + # disallow this here: + if i < name.len-1 and name[i] in Digits: + discard + else: + add(result, c) + of '$': special "dollar" + of '%': special "percent" + of '&': special "amp" + of '^': special "roof" + of '!': special "emark" + of '?': special "qmark" + of '*': special "star" + of '+': special "plus" + of '-': special "minus" + of '/': special "slash" + of '=': special "eq" + of '<': special "lt" + of '>': special "gt" + of '~': special "tilde" + of ':': special "colon" + of '.': special "dot" + of '@': special "at" + of '|': special "bar" else: - add(result, "HEX" & toHex(ord(c), 2)) + add(result, "X" & toHex(ord(c), 2)) + requiresUnderscore = true + if requiresUnderscore: + result.add "_" proc makeLLVMString*(s: string): Rope = const MaxLineLength = 64 diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 476b1362f..62ed9ad6e 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -14,7 +14,7 @@ import nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, - lowerings, semparallel, tables + lowerings, semparallel, tables, sets, ndi import strutils except `%` # collides with ropes.`%` @@ -216,7 +216,7 @@ proc genLineDir(p: BProc, t: PNode) = {optLineTrace, optStackTrace}) and (p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0: if freshLineInfo(p, tt.info): - linefmt(p, cpsStmts, "nimln($1, $2);$n", + linefmt(p, cpsStmts, "nimln_($1, $2);$n", line.rope, tt.info.quotedFilename) proc postStmtActions(p: BProc) {.inline.} = @@ -338,7 +338,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) - result.r = "LOC" & rope(p.labels) + result.r = "T" & rope(p.labels) & "_" linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp result.t = t @@ -347,12 +347,12 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = constructLoc(p, result, not needsInit) proc initGCFrame(p: BProc): Rope = - if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType] + if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType] proc deinitGCFrame(p: BProc): Rope = if p.gcFrameId > 0: result = ropecg(p.module, - "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n") + "if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n") proc localDebugInfo(p: BProc, s: PSym) = if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return @@ -361,7 +361,7 @@ proc localDebugInfo(p: BProc, s: PSym) = var a = "&" & s.loc.r if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r lineF(p, cpsInit, - "FR.s[$1].address = (void*)$3; FR.s[$1].typ = $4; FR.s[$1].name = $2;$n", + "FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n", [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a, genTypeInfo(p.module, s.loc.t)]) inc(p.maxFrameLen) @@ -369,7 +369,7 @@ proc localDebugInfo(p: BProc, s: PSym) = proc localVarDecl(p: BProc; s: PSym): Rope = if s.loc.k == locNone: - fillLoc(s.loc, locLocalVar, s.typ, mangleName(p.module, s), OnStack) + fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), OnStack) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) result = getTypeDesc(p.module, s.typ) if s.constraint.isNil: @@ -434,6 +434,7 @@ proc assignGlobalVar(p: BProc, s: PSym) = proc assignParam(p: BProc, s: PSym) = assert(s.loc.r != nil) + scopeMangledParam(p, s) localDebugInfo(p, s) proc fillProcLoc(m: BModule; sym: PSym) = @@ -442,7 +443,7 @@ proc fillProcLoc(m: BModule; sym: PSym) = proc getLabel(p: BProc): TLabel = inc(p.labels) - result = "LA" & rope(p.labels) + result = "LA" & rope(p.labels) & "_" proc fixLabel(p: BProc, labl: TLabel) = lineF(p, cpsStmts, "$1: ;$n", [labl]) @@ -520,7 +521,7 @@ proc mangleDynLibProc(sym: PSym): Rope = # NOTE: sym.loc.r is the external name! result = rope(sym.name.s) else: - result = "Dl_$1" % [rope(sym.id)] + result = "Dl_$1_" % [rope(sym.id)] proc symInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -608,11 +609,11 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope = discard cgsym(p.module, "nimFrame") if p.maxFrameLen > 0: discard cgsym(p.module, "VarSlot") - result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N", + result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4)$N", procname, filename, p.maxFrameLen.rope, p.blocks[0].frameLen.rope) else: - result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename) + result = rfmt(nil, "\tnimfr_($1, $2)$N", procname, filename) proc deinitFrame(p: BProc): Rope = result = rfmt(p.module, "\t#popFrame();$n") @@ -707,7 +708,7 @@ proc genProcAux(m: BModule, prc: PSym) = if p.beforeRetNeeded: add(generatedProc, "{") add(generatedProc, p.s(cpsInit)) add(generatedProc, p.s(cpsStmts)) - if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n") + if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet_: ;$n") add(generatedProc, deinitGCFrame(p)) if optStackTrace in prc.options: add(generatedProc, deinitFrame(p)) add(generatedProc, returnStmt) @@ -846,7 +847,8 @@ proc genVarPrototype(m: BModule, sym: PSym) = genVarPrototypeAux(m, sym) proc addIntTypes(result: var Rope) {.inline.} = - addf(result, "#define NIM_INTBITS $1" & tnl, [ + addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl & + "#define NIM_INTBITS $1" & tnl, [ platform.CPU[targetCPU].intSize.rope]) proc getCopyright(cfile: Cfile): Rope = @@ -1058,7 +1060,7 @@ proc genInitCode(m: BModule) = var procname = makeCString(m.module.name.s) add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename)) else: - add(prc, ~"\tTFrame FR; FR.len = 0;$N") + add(prc, ~"\tTFrame FR_; FR_.len = 0;$N") add(prc, genSectionStart(cpsInit)) add(prc, m.preInitProc.s(cpsInit)) @@ -1123,7 +1125,7 @@ proc initProcOptions(m: BModule): TOptions = proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = new(result) - result.tmpBase = rope("T" & $hashOwner(module) & "_") + result.tmpBase = rope("TM" & $hashOwner(module) & "_") initLinkedList(result.headerFiles) result.declaredThings = initIntSet() result.declaredProtos = initIntSet() @@ -1150,6 +1152,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = incl result.flags, preventStackTrace excl(result.preInitProc.options, optStackTrace) excl(result.postInitProc.options, optStackTrace) + let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi") + else: "" + open(result.ndi, ndiName) proc nullify[T](arr: var T) = for i in low(arr)..high(arr): @@ -1212,16 +1217,16 @@ proc newModule(g: BModuleList; module: PSym): BModule = if (sfDeadCodeElim in module.flags): internalError("added pending module twice: " & module.filename) -template injectG() {.dirty.} = +template injectG(config) {.dirty.} = if graph.backend == nil: - graph.backend = newModuleList() + graph.backend = newModuleList(config) let g = BModuleList(graph.backend) proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = - injectG() + injectG(graph.config) result = newModule(g, module) if optGenIndex in gGlobalOptions and g.generatedHeader == nil: - let f = if headerFile.len > 0: headerFile else: gProjectFull + let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull g.generatedHeader = rawNewModule(g, module, changeFileExt(completeCFilePath(f), hExt)) incl g.generatedHeader.flags, isHeaderFile @@ -1258,7 +1263,7 @@ proc getCFile(m: BModule): string = result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = - injectG() + injectG(graph.config) assert optSymbolFiles in gGlobalOptions var m = newModule(g, module) readMergeInfo(getCFile(m), m) @@ -1341,6 +1346,7 @@ proc writeModule(m: BModule, pending: bool) = var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {}) if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached} addFileToCompile(cf) + close(m.ndi) proc updateCachedModule(m: BModule) = let cfile = getCFile(m) @@ -1373,11 +1379,12 @@ proc myClose(b: PPassContext, n: PNode): PNode = for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) genMainProc(m) -proc cgenWriteModules*(backend: RootRef) = +proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = let g = BModuleList(backend) # we need to process the transitive closure because recursive module # deps are allowed (and the system module is processed in the wrong # order anyway) + g.config = config if g.generatedHeader != nil: finishModule(g.generatedHeader) while g.forwardedProcsCounter > 0: for m in cgenModules(g): diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 94d34c5cf..565399ead 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -11,7 +11,7 @@ import ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes, - tables + tables, ndi from msgs import TLineInfo @@ -56,7 +56,7 @@ type BProc* = ref TCProc TBlock*{.final.} = object id*: int # the ID of the label; positive means that it - label*: Rope # generated text for the label + label*: Rope # generated text for the label # nil if label is not used sections*: TCProcSections # the code beloging isLoop*: bool # whether block is a loop @@ -76,7 +76,7 @@ type # leaving such scopes by raise or by return must # execute any applicable finally blocks finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when - # using return in finally statements + # using return in finally statements labels*: Natural # for generating unique labels in the C proc blocks*: seq[TBlock] # nested blocks breakIdx*: int # the block that will be exited @@ -92,6 +92,7 @@ type # (yes, C++ is weird like that) gcFrameId*: Natural # for the GC stack marking gcFrameType*: Rope # the struct {} we put the GC markers into + sigConflicts*: CountTable[string] TTypeSeq* = seq[PType] TypeCache* = Table[SigHash, Rope] @@ -115,6 +116,7 @@ type breakPointId*: int breakpoints*: Rope # later the breakpoints are inserted into the main proc typeInfoMarker*: TypeCache + config*: ConfigRef TCGen = object of TPassContext # represents a C source file s*: TCFileSections # sections of the C file @@ -144,6 +146,7 @@ type injectStmt*: Rope sigConflicts*: CountTable[SigHash] g*: BModuleList + ndi*: NdiFile proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} = # section in the current block @@ -162,9 +165,10 @@ proc newProc*(prc: PSym, module: BModule): BProc = newSeq(result.blocks, 1) result.nestedTryStmts = @[] result.finallySafePoints = @[] + result.sigConflicts = initCountTable[string]() -proc newModuleList*(): BModuleList = - BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope]()) +proc newModuleList*(config: ConfigRef): BModuleList = + BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config) iterator cgenModules*(g: BModuleList): BModule = for i in 0..high(g.modules): diff --git a/compiler/commands.nim b/compiler/commands.nim index 61189fba1..74503a414 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -47,7 +47,8 @@ type passPP # preprocessor called processCommand() proc processCommand*(switch: string, pass: TCmdLinePass) -proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) +proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; + config: ConfigRef = nil) # implementation @@ -312,7 +313,8 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = expectArg(switch, arg, pass, info) options.inclDynlibOverride(arg) -proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = +proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; + config: ConfigRef = nil) = var theOS: TSystemOS cpu: TSystemCPU @@ -509,10 +511,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) of "passc", "t": expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg) + if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg) of "passl", "l": expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg) + if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg) of "cincludes": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info) @@ -523,7 +525,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info) of "header": - headerFile = arg + if config != nil: config.headerFile = arg incl(gGlobalOptions, optGenIndex) of "index": processOnOffSwitchG({optGenIndex}, arg, pass, info) @@ -646,6 +648,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optNoCppExceptions) defineSymbol("noCppExceptions") + of "cppdefine": + expectArg(switch, arg, pass, info) + if config != nil: + config.cppDefine(arg) else: if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 98c72f862..a738ddb48 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -101,3 +101,4 @@ proc initDefines*() = defineSymbol("nimImmediateDeprecated") defineSymbol("nimNewShiftOps") defineSymbol("nimDistros") + defineSymbol("nimHasCppDefine") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 211544924..26dd889ce 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -209,26 +209,26 @@ proc getPlainDocstring(n: PNode): string = result = getPlainDocstring(n.sons[i]) if result.len > 0: return - -proc findDocComment(n: PNode): PNode = - if n == nil: return nil - if not isNil(n.comment) and startsWith(n.comment, "##"): return n - for i in countup(0, safeLen(n)-1): - result = findDocComment(n.sons[i]) - if result != nil: return - -proc extractDocComment*(s: PSym, d: PDoc = nil): string = - let n = findDocComment(s.ast) - result = "" - if not n.isNil: - if not d.isNil: - var dummyHasToc: bool - renderRstToOut(d[], parseRst(n.comment, toFilename(n.info), - toLinenumber(n.info), toColumn(n.info), - dummyHasToc, d.options + {roSkipPounds}), - result) - else: - result = n.comment.substr(2).replace("\n##", "\n").strip +when false: + proc findDocComment(n: PNode): PNode = + if n == nil: return nil + if not isNil(n.comment) and startsWith(n.comment, "##"): return n + for i in countup(0, safeLen(n)-1): + result = findDocComment(n.sons[i]) + if result != nil: return + + proc extractDocComment*(s: PSym, d: PDoc = nil): string = + let n = findDocComment(s.ast) + result = "" + if not n.isNil: + if not d.isNil: + var dummyHasToc: bool + renderRstToOut(d[], parseRst(n.comment, toFilename(n.info), + toLinenumber(n.info), toColumn(n.info), + dummyHasToc, d.options + {roSkipPounds}), + result) + else: + result = n.comment.substr(2).replace("\n##", "\n").strip proc isVisible(n: PNode): bool = result = false diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 8ca34223b..0f283b208 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -392,6 +392,8 @@ type var externalToLink: TLinkedList # files to link in addition to the file # we compiled + linkOptionsCmd: string = "" + compileOptionsCmd: seq[string] = @[] linkOptions: string = "" compileOptions: string = "" ccompilerpath: string = "" @@ -450,6 +452,12 @@ proc addCompileOption*(option: string) = if strutils.find(compileOptions, option, 0) < 0: addOpt(compileOptions, option) +proc addLinkOptionCmd*(option: string) = + addOpt(linkOptionsCmd, option) + +proc addCompileOptionCmd*(option: string) = + compileOptionsCmd.add(option) + proc initVars*() = # we need to define the symbol here, because ``CC`` may have never been set! for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) @@ -524,6 +532,10 @@ proc add(s: var string, many: openArray[string]) = proc cFileSpecificOptions(cfilename: string): string = result = compileOptions + for option in compileOptionsCmd: + if strutils.find(result, option, 0) < 0: + addOpt(result, option) + var trunk = splitFile(cfilename).name if optCDebug in gGlobalOptions: var key = trunk & ".debug" @@ -544,7 +556,7 @@ proc getCompileOptions: string = result = cFileSpecificOptions("__dummy__") proc getLinkOptions: string = - result = linkOptions + result = linkOptions & " " & linkOptionsCmd & " " for linkedLib in items(cLinkedLibs): result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell) for libDir in items(cLibs): diff --git a/compiler/installer.ini b/compiler/installer.ini index 2263e030f..31c6f7728 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -46,7 +46,7 @@ Start: "doc/html/overview.html" [Other] -Files: "readme.txt;install.txt;contributors.txt;copying.txt" +Files: "readme.txt;copying.txt" Files: "makefile" Files: "koch.nim" Files: "install_nimble.nims" @@ -94,15 +94,17 @@ Files: "bin/vccexe.exe" Files: "koch.exe" Files: "finish.exe" +Files: "downloader.exe" + ; Files: "dist/mingw" Files: r"tools\start.bat" BinPath: r"bin;dist\mingw\bin;dist" ; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry -Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html" -Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip" -Download: r"Support DLLs|bin|nim_dlls.zip|479|http://nim-lang.org/download/dlls.zip" -Download: r"Aporia Text Editor|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe" +Download: r"Documentation|doc|docs.zip|13824|https://nim-lang.org/download/docs-${version}.zip|overview.html" +Download: r"C Compiler (MingW)|dist|mingw.zip|82944|https://nim-lang.org/download/${mingw}.zip" +Download: r"Support DLLs|bin|nim_dlls.zip|479|https://nim-lang.org/download/dlls.zip" +Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe" ; for now only NSIS supports optional downloads [WinBin] diff --git a/compiler/main.nim b/compiler/main.nim index 888f89ad5..2acb7620c 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -72,7 +72,7 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) = #registerPass(cleanupPass()) compileProject(graph, cache) - cgenWriteModules(graph.backend) + cgenWriteModules(graph.backend, graph.config) if gCmd != cmdRun: let proj = changeFileExt(gProjectFull, "") extccomp.callCCompiler(proj) @@ -294,4 +294,4 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = resetAttributes() -proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache()) +proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache()) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 466e12e64..87a35b290 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -25,7 +25,7 @@ ## - Its dependent module stays the same. ## -import ast, intsets, tables +import ast, intsets, tables, options type ModuleGraph* = ref object @@ -39,16 +39,21 @@ type importStack*: seq[int32] # The current import stack. Used for detecting recursive # module dependencies. backend*: RootRef # minor hack so that a backend can extend this easily + config*: ConfigRef {.this: g.} -proc newModuleGraph*(): ModuleGraph = +proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result = ModuleGraph() initStrTable(result.packageSyms) result.deps = initIntSet() result.modules = @[] result.importStack = @[] result.inclToMod = initTable[int32, int32]() + if config.isNil: + result.config = newConfigRef() + else: + result.config = config proc resetAllModules*(g: ModuleGraph) = initStrTable(packageSyms) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index e6a2b75a6..49e4fa184 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -12,7 +12,7 @@ import type TMsgKind* = enum - errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, + errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated, errXCompilerDoesNotSupportCpp, errStringLiteralExpected, errIntLiteralExpected, errInvalidCharacterConstant, errClosingTripleQuoteExpected, errClosingQuoteExpected, @@ -135,8 +135,8 @@ type const MsgKindToStr*: array[TMsgKind, string] = [ errUnknown: "unknown error", - errIllFormedAstX: "illformed AST: $1", errInternal: "internal error: $1", + errIllFormedAstX: "illformed AST: $1", errCannotOpenFile: "cannot open \'$1\'", errGenerated: "$1", errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++", diff --git a/compiler/ndi.nim b/compiler/ndi.nim new file mode 100644 index 000000000..a7ca02193 --- /dev/null +++ b/compiler/ndi.nim @@ -0,0 +1,40 @@ +# +# +# The Nim Compiler +# (c) Copyright 2017 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the generation of ``.ndi`` files for better debugging +## support of Nim code. "ndi" stands for "Nim debug info". + +import ast, msgs, ropes + +type + NdiFile* = object + enabled: bool + f: File + buf: string + +proc doWrite(f: var NdiFile; s: PSym) = + f.buf.setLen 0 + f.buf.add s.info.line.int + f.buf.add "\t" + f.buf.add s.info.col.int + f.f.write(s.name.s, "\t") + f.f.writeRope(s.loc.r) + f.f.writeLine("\t", s.info.toFullPath, "\t", f.buf) + +template writeMangledName*(f: NdiFile; s: PSym) = + if f.enabled: doWrite(f, s) + +proc open*(f: var NdiFile; filename: string) = + f.enabled = filename.len > 0 + if f.enabled: + f.f = open(filename, fmWrite, 8000) + f.buf = newStringOfCap(20) + +proc close*(f: var NdiFile) = + if f.enabled: close(f.f) diff --git a/compiler/nim.nim b/compiler/nim.nim index c458f76f9..56885e9f1 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -37,7 +37,7 @@ proc prependCurDir(f: string): string = else: result = f -proc handleCmdLine(cache: IdentCache) = +proc handleCmdLine(cache: IdentCache; config: ConfigRef) = if paramCount() == 0: writeCommandLineUsage() else: @@ -59,22 +59,22 @@ proc handleCmdLine(cache: IdentCache) = gProjectName = p.name else: gProjectPath = canonicalizePath getCurrentDir() - loadConfigs(DefaultConfig) # load all config files + loadConfigs(DefaultConfig, config) # load all config files let scriptFile = gProjectFull.changeFileExt("nims") if fileExists(scriptFile): - runNimScript(cache, scriptFile, freshDefines=false) + runNimScript(cache, scriptFile, freshDefines=false, config) # 'nim foo.nims' means to just run the NimScript file and do nothing more: if scriptFile == gProjectFull: return elif fileExists(gProjectPath / "config.nims"): # directory wide NimScript file - runNimScript(cache, gProjectPath / "config.nims", freshDefines=false) + runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config) # now process command line arguments again, because some options in the # command line can overwite the config file's settings extccomp.initVars() processCmdLine(passCmd2, "") if options.command == "": rawMessage(errNoCommand, command) - mainCommand(newModuleGraph(), cache) + mainCommand(newModuleGraph(config), cache) if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics()) #echo(GC_getStatistics()) if msgs.gErrorCounter == 0: @@ -118,5 +118,5 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"): condsyms.initDefines() when not defined(selftest): - handleCmdLine(newIdentCache()) + handleCmdLine(newIdentCache(), newConfigRef()) msgQuit(int8(msgs.gErrorCounter > 0)) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 4bf2fbc9a..808159b8f 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -21,37 +21,37 @@ proc ppGetTok(L: var TLexer, tok: var TToken) = rawGetTok(L, tok) while tok.tokType in {tkComment}: rawGetTok(L, tok) -proc parseExpr(L: var TLexer, tok: var TToken): bool -proc parseAtom(L: var TLexer, tok: var TToken): bool = +proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool +proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool = if tok.tokType == tkParLe: ppGetTok(L, tok) - result = parseExpr(L, tok) + result = parseExpr(L, tok, config) if tok.tokType == tkParRi: ppGetTok(L, tok) else: lexMessage(L, errTokenExpected, "\')\'") elif tok.ident.id == ord(wNot): ppGetTok(L, tok) - result = not parseAtom(L, tok) + result = not parseAtom(L, tok, config) else: result = isDefined(tok.ident) ppGetTok(L, tok) -proc parseAndExpr(L: var TLexer, tok: var TToken): bool = - result = parseAtom(L, tok) +proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool = + result = parseAtom(L, tok, config) while tok.ident.id == ord(wAnd): ppGetTok(L, tok) # skip "and" - var b = parseAtom(L, tok) + var b = parseAtom(L, tok, config) result = result and b -proc parseExpr(L: var TLexer, tok: var TToken): bool = - result = parseAndExpr(L, tok) +proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool = + result = parseAndExpr(L, tok, config) while tok.ident.id == ord(wOr): ppGetTok(L, tok) # skip "or" - var b = parseAndExpr(L, tok) + var b = parseAndExpr(L, tok, config) result = result or b -proc evalppIf(L: var TLexer, tok: var TToken): bool = +proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool = ppGetTok(L, tok) # skip 'if' or 'elif' - result = parseExpr(L, tok) + result = parseExpr(L, tok, config) if tok.tokType == tkColon: ppGetTok(L, tok) else: lexMessage(L, errTokenExpected, "\':\'") @@ -66,20 +66,20 @@ type TJumpDest = enum jdEndif, jdElseEndif -proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) -proc doElse(L: var TLexer, tok: var TToken) = +proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) +proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) = if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") ppGetTok(L, tok) if tok.tokType == tkColon: ppGetTok(L, tok) - if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif) + if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config) -proc doElif(L: var TLexer, tok: var TToken) = +proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) = if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if") - var res = evalppIf(L, tok) - if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif) + var res = evalppIf(L, tok, config) + if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config) else: condStack[high(condStack)] = true -proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = +proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) = var nestedIfs = 0 while true: if tok.ident != nil and tok.ident.s == "@": @@ -89,11 +89,11 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = inc(nestedIfs) of wElse: if dest == jdElseEndif and nestedIfs == 0: - doElse(L, tok) + doElse(L, tok, config) break of wElif: if dest == jdElseEndif and nestedIfs == 0: - doElif(L, tok) + doElif(L, tok, config) break of wEnd: if nestedIfs == 0: @@ -108,16 +108,16 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = else: ppGetTok(L, tok) -proc parseDirective(L: var TLexer, tok: var TToken) = +proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) = ppGetTok(L, tok) # skip @ case whichKeyword(tok.ident) of wIf: setLen(condStack, len(condStack) + 1) - let res = evalppIf(L, tok) + let res = evalppIf(L, tok, config) condStack[high(condStack)] = res - if not res: jumpToDirective(L, tok, jdElseEndif) - of wElif: doElif(L, tok) - of wElse: doElse(L, tok) + if not res: jumpToDirective(L, tok, jdElseEndif, config) + of wElif: doElif(L, tok, config) + of wElse: doElse(L, tok, config) of wEnd: doEnd(L, tok) of wWrite: ppGetTok(L, tok) @@ -146,58 +146,58 @@ proc parseDirective(L: var TLexer, tok: var TToken) = ppGetTok(L, tok) else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok)) -proc confTok(L: var TLexer, tok: var TToken) = +proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) = ppGetTok(L, tok) while tok.ident != nil and tok.ident.s == "@": - parseDirective(L, tok) # else: give the token to the parser + parseDirective(L, tok, config) # else: give the token to the parser proc checkSymbol(L: TLexer, tok: TToken) = if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}: lexMessage(L, errIdentifierExpected, tokToStr(tok)) -proc parseAssignment(L: var TLexer, tok: var TToken) = +proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) = if tok.ident.s == "-" or tok.ident.s == "--": - confTok(L, tok) # skip unnecessary prefix + confTok(L, tok, config) # skip unnecessary prefix var info = getLineInfo(L, tok) # save for later in case of an error checkSymbol(L, tok) var s = tokToStr(tok) - confTok(L, tok) # skip symbol + confTok(L, tok, config) # skip symbol var val = "" while tok.tokType == tkDot: add(s, '.') - confTok(L, tok) + confTok(L, tok, config) checkSymbol(L, tok) add(s, tokToStr(tok)) - confTok(L, tok) + confTok(L, tok, config) if tok.tokType == tkBracketLe: # BUGFIX: val, not s! # BUGFIX: do not copy '['! - confTok(L, tok) + confTok(L, tok, config) checkSymbol(L, tok) add(val, tokToStr(tok)) - confTok(L, tok) - if tok.tokType == tkBracketRi: confTok(L, tok) + confTok(L, tok, config) + if tok.tokType == tkBracketRi: confTok(L, tok, config) else: lexMessage(L, errTokenExpected, "']'") add(val, ']') let percent = tok.ident != nil and tok.ident.s == "%=" if tok.tokType in {tkColon, tkEquals} or percent: if len(val) > 0: add(val, ':') - confTok(L, tok) # skip ':' or '=' or '%' + confTok(L, tok, config) # skip ':' or '=' or '%' checkSymbol(L, tok) add(val, tokToStr(tok)) - confTok(L, tok) # skip symbol + confTok(L, tok, config) # skip symbol while tok.ident != nil and tok.ident.s == "&": - confTok(L, tok) + confTok(L, tok, config) checkSymbol(L, tok) add(val, tokToStr(tok)) - confTok(L, tok) + confTok(L, tok, config) if percent: processSwitch(s, strtabs.`%`(val, options.gConfigVars, - {useEnvironment, useEmpty}), passPP, info) + {useEnvironment, useEmpty}), passPP, info, config) else: - processSwitch(s, val, passPP, info) + processSwitch(s, val, passPP, info, config) -proc readConfigFile(filename: string; cache: IdentCache) = +proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) = var L: TLexer tok: TToken @@ -207,8 +207,8 @@ proc readConfigFile(filename: string; cache: IdentCache) = initToken(tok) openLexer(L, filename, stream, cache) tok.tokType = tkEof # to avoid a pointless warning - confTok(L, tok) # read in the first token - while tok.tokType != tkEof: parseAssignment(L, tok) + confTok(L, tok, config) # read in the first token + while tok.tokType != tkEof: parseAssignment(L, tok, config) if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end") closeLexer(L) rawMessage(hintConf, filename) @@ -225,22 +225,22 @@ proc getSystemConfigPath(filename: string): string = if not existsFile(result): result = joinPath([p, "etc", filename]) if not existsFile(result): result = "/etc/" & filename -proc loadConfigs*(cfg: string; cache: IdentCache) = +proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) = setDefaultLibpath() if optSkipConfigFile notin gGlobalOptions: - readConfigFile(getSystemConfigPath(cfg), cache) + readConfigFile(getSystemConfigPath(cfg), cache, config) if optSkipUserConfigFile notin gGlobalOptions: - readConfigFile(getUserConfigPath(cfg), cache) + readConfigFile(getUserConfigPath(cfg), cache, config) var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir() if optSkipParentConfigFiles notin gGlobalOptions: for dir in parentDirs(pd, fromRoot=true, inclusive=false): - readConfigFile(dir / cfg, cache) + readConfigFile(dir / cfg, cache, config) if optSkipProjConfigFile notin gGlobalOptions: - readConfigFile(pd / cfg, cache) + readConfigFile(pd / cfg, cache, config) if gProjectName.len != 0: # new project wide config file: @@ -251,8 +251,8 @@ proc loadConfigs*(cfg: string; cache: IdentCache) = projectConfig = changeFileExt(gProjectFull, "nimrod.cfg") if fileExists(projectConfig): rawMessage(warnDeprecated, projectConfig) - readConfigFile(projectConfig, cache) + readConfigFile(projectConfig, cache, config) -proc loadConfigs*(cfg: string) = +proc loadConfigs*(cfg: string; config: ConfigRef = nil) = # for backwards compatibility only. - loadConfigs(cfg, newIdentCache()) + loadConfigs(cfg, newIdentCache(), config) diff --git a/compiler/options.nim b/compiler/options.nim index 746ee9044..2295bbf93 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -102,6 +102,17 @@ type ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, ideHighlight, ideOutline + ConfigRef* = ref object ## eventually all global configuration should be moved here + cppDefines*: HashSet[string] + headerFile*: string + +proc newConfigRef*(): ConfigRef = + result = ConfigRef(cppDefines: initSet[string](), + headerFile: "") + +proc cppDefine*(c: ConfigRef; define: string) = + c.cppDefines.incl define + var gIdeCmd*: IdeCmd @@ -122,7 +133,7 @@ var outFile*: string = "" docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \ # The string uses the formatting variables `path` and `line`. - headerFile*: string = "" + #headerFile*: string = "" gVerbosity* = 1 # how verbose the compiler is gNumberOfProcessors*: int # number of processors gWholeProject*: bool # for 'doc2': output any dependency diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index e750cc390..04dbd3612 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -665,9 +665,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wExportc: makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) incl(sym.flags, sfUsed) # avoid wrong hints - of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info) + of wImportc: + let name = getOptionalStr(c, it, "$1") + cppDefine(c.graph.config, name) + makeExternImport(sym, name, it.info) of wImportCompilerProc: - processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info) + let name = getOptionalStr(c, it, "$1") + cppDefine(c.graph.config, name) + processImportCompilerProc(sym, name, it.info) of wExtern: setExternName(sym, expectStrLit(c, it), it.info) of wImmediate: if sym.kind in {skTemplate, skMacro}: @@ -758,6 +763,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, processDynLib(c, it, sym) of wCompilerproc: noVal(it) # compilerproc may not get a string! + cppDefine(c.graph.config, sym.name.s) if sfFromGeneric notin sym.flags: markCompilerProc(sym) of wProcVar: noVal(it) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 75ecf4b02..9e94f1c19 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -25,7 +25,8 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = if kind in filter: result.add path setResult(a, result) -proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext = +proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; + config: ConfigRef = nil): PEvalContext = # For Nimble we need to export 'setupVM'. result = newCtx(module, cache) result.mode = emRepl @@ -109,10 +110,13 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext let arg = a.getString 1 if arg.len > 0: gProjectName = arg + let path = + if gProjectName.isAbsolute: gProjectName + else: gProjectPath / gProjectName try: - gProjectFull = canonicalizePath(gProjectPath / gProjectName) + gProjectFull = canonicalizePath(path) except OSError: - gProjectFull = gProjectName + gProjectFull = path cbconf getCommand: setResult(a, options.command) cbconf switch: @@ -133,12 +137,15 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext gModuleOverrides[key] = val cbconf selfExe: setResult(a, os.getAppFilename()) + cbconf cppDefine: + if config != nil: + options.cppDefine(config, a.getString(0)) proc runNimScript*(cache: IdentCache; scriptName: string; - freshDefines=true) = + freshDefines=true; config: ConfigRef=nil) = passes.gIncludeFile = includeModule passes.gImportModule = importModule - let graph = newModuleGraph() + let graph = newModuleGraph(config) if freshDefines: initDefines() defineSymbol("nimscript") @@ -150,7 +157,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string; var m = graph.makeModule(scriptName) incl(m.flags, sfMainModule) - vm.globalCtx = setupVM(m, cache, scriptName) + vm.globalCtx = setupVM(m, cache, scriptName, config) graph.compileSystemModule(cache) discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 54a301322..57674735a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1052,6 +1052,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # work without now. template/tsymchoicefield doesn't like an early exit # here at all! #if isSymChoice(n.sons[1]): return + when defined(nimsuggest): + if gCmd == cmdIdeTools: suggestExpr(c, n) var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule}) if s != nil: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index e1a65da74..9c57be023 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -97,10 +97,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation; if inst.compilesId == id and sameInstantiation(entry, inst[]): return inst.sym +when false: + proc `$`(x: PSym): string = + result = x.name.s & " " & " id " & $x.id + proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) = # we need to create a fresh set of gensym'ed symbols: - if n.kind == nkSym and sfGenSym in n.sym.flags and - (n.sym.owner == orig or n.sym.owner.kind == skPackage): + #if n.kind == nkSym and sfGenSym in n.sym.flags: + # if n.sym.owner != orig: + # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner + if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and + # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}): let s = n.sym var x = PSym(idTableGet(symMap, s)) if x == nil: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index c9a70e9bc..a69fe477b 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -112,6 +112,7 @@ type toBind, toMixin, toInject: IntSet owner: PSym cursorInBody: bool # only for nimsuggest + scopeN: int bracketExpr: PNode template withBracketExpr(ctx, x, body: untyped) = @@ -141,8 +142,13 @@ proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} = proc semTemplBody(c: var TemplCtx, n: PNode): PNode -proc openScope(c: var TemplCtx) = openScope(c.c) -proc closeScope(c: var TemplCtx) = closeScope(c.c) +proc openScope(c: var TemplCtx) = + openScope(c.c) + inc c.scopeN + +proc closeScope(c: var TemplCtx) = + dec c.scopeN + closeScope(c.c) proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode = openScope(c) @@ -166,6 +172,7 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = result = newSym(kind, considerQuotedIdent(n), c.owner, n.info) incl(result.flags, sfGenSym) incl(result.flags, sfShadowed) + if c.scopeN == 0: incl(result.flags, sfFromGeneric) proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = # locals default to 'gensym': diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 028baa555..17c065b49 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -659,7 +659,8 @@ proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, addInheritedFieldsAux(c, check, pos, obj.n) proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = - if n.sonsLen == 0: return newConstraint(c, tyObject) + if n.sonsLen == 0: + return newConstraint(c, tyObject) var check = initIntSet() var pos = 0 var base, realBase: PType = nil @@ -1159,8 +1160,16 @@ proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType = result.sym = prev.sym assignType(prev, result) +proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) = + if prev != nil: + let result = newTypeS(tyAlias, c) + result.rawAddSon typExpr.typ + result.sym = prev.sym + assignType(prev, result) + proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil + if gCmd == cmdIdeTools: suggestExpr(c, n) case n.kind of nkEmpty: discard @@ -1168,6 +1177,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = # for ``type(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1) let typExpr = semExprWithType(c, n.sons[0], {efInTypeof}) + fixupTypeOf(c, prev, typExpr) result = typExpr.typ of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) @@ -1234,6 +1244,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = elif op.id == ord(wType): checkSonsLen(n, 2) let typExpr = semExprWithType(c, n.sons[1], {efInTypeof}) + fixupTypeOf(c, prev, typExpr) result = typExpr.typ else: result = semTypeExpr(c, n, prev) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index f3c03d680..66876b9b5 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -41,6 +41,20 @@ var template origModuleName(m: PSym): string = m.name.s +proc findDocComment(n: PNode): PNode = + if n == nil: return nil + if not isNil(n.comment): return n + for i in countup(0, safeLen(n)-1): + result = findDocComment(n.sons[i]) + if result != nil: return + +proc extractDocComment(s: PSym): string = + let n = findDocComment(s.ast) + if not n.isNil: + result = n.comment.replace("\n##", "\n").strip + else: + result = "" + proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; quality: range[0..100]): Suggest = result.section = parseIdeCmd(section) diff --git a/compiler/vm.nim b/compiler/vm.nim index 7ce96f7df..ea82a3155 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -559,7 +559,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if regs[rb].node.kind == nkRefTy: regs[ra].node = regs[rb].node.sons[0] else: - stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers") + ensureKind(rkNode) + regs[ra].node = regs[rb].node else: stackTrace(c, tos, pc, errNilAccess) of opcWrDeref: @@ -932,7 +933,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = c.module var macroCall = newNodeI(nkCall, c.debug[pc]) macroCall.add(newSymNode(prc)) - for i in 1 .. rc-1: macroCall.add(regs[rb+i].regToNode) + for i in 1 .. rc-1: + let node = regs[rb+i].regToNode + node.info = c.debug[pc] + macroCall.add(node) let a = evalTemplate(macroCall, prc, genSymOwner) a.recSetFlagIsRef ensureKind(rkNode) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index e0f737f08..125fe8ae0 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1259,6 +1259,13 @@ proc isTemp(c: PCtx; dest: TDest): bool = template needsAdditionalCopy(n): untyped = not c.isTemp(dest) and not fitsRegister(n.typ) +proc genAdditionalCopy(c: PCtx; n: PNode; opc: TOpcode; + dest, idx, value: TRegister) = + var cc = c.getTemp(n.typ) + c.gABC(n, whichAsgnOpc(n), cc, value, 0) + c.gABC(n, opc, dest, idx, cc) + c.freeTemp(cc) + proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode; dest, idx, value: TRegister) = # opcLdObj et al really means "load address". We sometimes have to create a @@ -1266,10 +1273,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode; # mylocal = a.b # needs a copy of the data! assert n.typ != nil if needsAdditionalCopy(n): - var cc = c.getTemp(n.typ) - c.gABC(n, whichAsgnOpc(n), cc, value, 0) - c.gABC(n, opc, dest, idx, cc) - c.freeTemp(cc) + genAdditionalCopy(c, n, opc, dest, idx, value) else: c.gABC(n, opc, dest, idx, value) @@ -1352,7 +1356,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = c.gABx(n, opcLdGlobal, dest, s.position) if s.ast != nil: let tmp = c.genx(s.ast) - c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp) + c.genAdditionalCopy(n, opcWrDeref, dest, 0, tmp) c.freeTemp(dest) c.freeTemp(tmp) @@ -1506,7 +1510,7 @@ proc genVarSection(c: PCtx; n: PNode) = #assert(a.sons[0].kind == nkSym) can happen for transformed vars if a.kind == nkVarTuple: for i in 0 .. a.len-3: - setSlot(c, a[i].sym) + if not a[i].sym.isGlobal: setSlot(c, a[i].sym) checkCanEval(c, a[i]) c.gen(lowerTupleUnpacking(a, c.getOwner)) elif a.sons[0].kind == nkSym: @@ -1525,7 +1529,7 @@ proc genVarSection(c: PCtx; n: PNode) = if a.sons[2].kind != nkEmpty: let tmp = c.genx(a.sons[0], {gfAddrOf}) let val = c.genx(a.sons[2]) - c.preventFalseAlias(a.sons[2], opcWrDeref, tmp, 0, val) + c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val) c.freeTemp(val) c.freeTemp(tmp) else: |