diff options
Diffstat (limited to 'compiler/ccgstmts.nim')
-rw-r--r-- | compiler/ccgstmts.nim | 299 |
1 files changed, 186 insertions, 113 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index fbdb9a347..883108f2c 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -8,7 +8,6 @@ # # included from cgen.nim - const RangeExpandLimit = 256 # do not generate ranges # over 'RangeExpandLimit' elements @@ -36,7 +35,9 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = if n.kind == nkEmpty: result = false elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc: - if isInvalidReturnType(conf, n[0].typ, true): + if n[0].kind == nkSym and sfConstructor in n[0].sym.flags: + result = true + elif isInvalidReturnType(conf, n[0].typ, true): # var v = f() # is transformed into: var v; f(addr v) # where 'f' **does not** initialize the result! @@ -49,6 +50,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = result = true proc inExceptBlockLen(p: BProc): int = + result = 0 for x in p.nestedTryStmts: if x.inExcept: result.inc @@ -70,7 +72,6 @@ template startBlock(p: BProc, start: FormatStr = "{$n", proc endBlock(p: BProc) proc genVarTuple(p: BProc, n: PNode) = - var tup, field: TLoc if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple") # if we have a something that's been captured, use the lowering instead: @@ -82,7 +83,7 @@ proc genVarTuple(p: BProc, n: PNode) = # check only the first son var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym) let hcrCond = if forHcr: getTempName(p.module) else: "" - var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] + var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[] # determine if the tuple is constructed at top-level scope or inside of a block (if/while/block) let isGlobalInBlock = forHcr and p.blocks.len > 2 # do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block) @@ -94,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) = startBlock(p) genLineDir(p, n) - initLocExpr(p, n[^1], tup) + var tup = initLocExpr(p, n[^1]) var t = tup.t.skipTypes(abstractInst) for i in 0..<n.len-2: let vn = n[i] @@ -107,12 +108,12 @@ proc genVarTuple(p: BProc, n: PNode) = else: assignLocalVar(p, vn) initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1])) - initLoc(field, locExpr, vn, tup.storage) + var field = initLoc(locExpr, vn, tup.storage) if t.kind == tyTuple: - field.r = "$1.Field$2" % [rdLoc(tup), rope(i)] + field.snippet = "$1.Field$2" % [rdLoc(tup), rope(i)] else: if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple") - field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)] + field.snippet = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)] putLocIntoDest(p, v.loc, field) if forHcr or isGlobalInBlock: hcrGlobals.add((loc: v.loc, tp: "NULL")) @@ -127,7 +128,7 @@ proc genVarTuple(p: BProc, n: PNode) = lineCg(p, cpsLocals, "NIM_BOOL $1 = NIM_FALSE;$n", [hcrCond]) for curr in hcrGlobals: lineCg(p, cpsLocals, "$1 |= hcrRegisterGlobal($4, \"$2\", sizeof($3), $5, (void**)&$2);$N", - [hcrCond, curr.loc.r, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp]) + [hcrCond, curr.loc.snippet, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp]) proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = @@ -168,7 +169,7 @@ proc endBlock(p: BProc, blockEnd: Rope) = proc endBlock(p: BProc) = let topBlock = p.blocks.len - 1 let frameLen = p.blocks[topBlock].frameLen - var blockEnd: Rope + var blockEnd: Rope = "" if frameLen > 0: blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) if p.blocks[topBlock].label.len != 0: @@ -243,8 +244,7 @@ proc genGotoState(p: BProc, n: PNode) = # switch (x.state) { # case 0: goto STATE0; # ... - var a: TLoc - initLocExpr(p, n[0], a) + var a: TLoc = initLocExpr(p, n[0]) lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)]) p.flags.incl beforeRetNeeded lineF(p, cpsStmts, "case -1:$n", []) @@ -263,15 +263,15 @@ proc genGotoState(p: BProc, n: PNode) = proc genBreakState(p: BProc, n: PNode, d: var TLoc) = var a: TLoc - initLoc(d, locExpr, n, OnUnknown) + d = initLoc(locExpr, n, OnUnknown) if n[0].kind == nkClosure: - initLocExpr(p, n[0][1], a) - d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)] + a = initLocExpr(p, n[0][1]) + d.snippet = "(((NI*) $1)[1] < 0)" % [rdLoc(a)] else: - initLocExpr(p, n[0], a) + a = initLocExpr(p, n[0]) # the environment is guaranteed to contain the 'state' field at offset 1: - d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)] + d.snippet = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)] proc genGotoVar(p: BProc; value: PNode) = if value.kind notin {nkCharLit..nkUInt64Lit}: @@ -289,11 +289,46 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) = #echo "New code produced for ", v.name.s, " ", p.config $ value.info genBracedInit(p, value, isConst = false, v.typ, result) +proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string = + result = "" + var argsCounter = 0 + let typ = skipTypes(call[0].typ, abstractInst) + assert(typ.kind == tyProc) + for i in 1..<call.len: + #if it's a type we can just generate here another initializer as we are in an initializer context + if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType: + if argsCounter > 0: result.add "," + result.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp) + else: + #We need to test for temp in globals, see: #23657 + let param = + if typ[i].kind in {tyVar} and call[i].kind == nkHiddenAddr: + call[i][0] + else: + call[i] + if param.kind != nkBracketExpr or param.typ.kind in + {tyRef, tyPtr, tyUncheckedArray, tyArray, tyOpenArray, + tyVarargs, tySequence, tyString, tyCstring, tyTuple}: + let tempLoc = initLocExprSingleUse(p, param) + didGenTemp = didGenTemp or tempLoc.k == locTemp + genOtherArg(p, call, i, typ, result, argsCounter) + +proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope, didGenTemp: var bool) = + let params = genCppParamsForCtor(p, call, didGenTemp) + if params.len == 0: + decl = runtimeFormat("$#;\n", [decl]) + else: + decl = runtimeFormat("$#($#);\n", [decl, params]) + proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = if sfGoto in v.flags: # translate 'var state {.goto.} = X' into 'goto LX': genGotoVar(p, value) return + let imm = isAssignedImmediately(p.config, value) + let isCppCtorCall = p.module.compileToCpp and imm and + value.kind in nkCallKinds and value[0].kind == nkSym and + v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags var targetProc = p var valueAsRope = "" potentialValueInit(p, v, value, valueAsRope) @@ -305,7 +340,18 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = if sfPure in v.flags: # v.owner.kind != skModule: targetProc = p.module.preInitProc - assignGlobalVar(targetProc, vn, valueAsRope) + if isCppCtorCall and not containsHiddenPointer(v.typ): + var didGenTemp = false + callGlobalVarCppCtor(targetProc, v, vn, value, didGenTemp) + if didGenTemp: + message(p.config, vn.info, warnGlobalVarConstructorTemporary, vn.sym.name.s) + #We fail to call the constructor in the global scope so we do the call inside the main proc + assignGlobalVar(targetProc, vn, valueAsRope) + var loc = initLocExprSingleUse(targetProc, value) + genAssignment(targetProc, v.loc, loc, {}) + else: + assignGlobalVar(targetProc, vn, valueAsRope) + # XXX: be careful here. # Global variables should not be zeromem-ed within loops # (see bug #20). @@ -314,13 +360,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # global variables will be initialized to zero. if valueAsRope.len == 0: var loc = v.loc - # When the native TLS is unavailable, a global thread-local variable needs # one more layer of indirection in order to access the TLS block. # Only do this for complex types that may need a call to `objectInit` if sfThread in v.flags and emulatedThreadVars(p.config) and isComplexValueType(v.typ): - initLocExprSingleUse(p.module.preInitProc, vn, loc) + loc = initLocExprSingleUse(p.module.preInitProc, vn) genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj) # Alternative construction using default constructor (which may zeromem): # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) @@ -328,31 +373,25 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = genVarPrototype(p.module.g.generatedHeader, vn) registerTraverseProc(p, v) else: - let imm = isAssignedImmediately(p.config, value) if imm and p.module.compileToCpp and p.splitDecls == 0 and - not containsHiddenPointer(v.typ): + not containsHiddenPointer(v.typ) and + nimErrorFlagAccessed notin p.flags: # C++ really doesn't like things like 'Foo f; f = x' as that invokes a # parameterless constructor followed by an assignment operator. So we # generate better code here: 'Foo f = x;' genLineDir(p, vn) - let decl = localVarDecl(p, vn) + var decl = localVarDecl(p, vn) var tmp: TLoc - if value.kind in nkCallKinds and value[0].kind == nkSym and - sfConstructor in value[0].sym.flags: - var params = newRopeAppender() - var argsCounter = 0 - let typ = skipTypes(value[0].typ, abstractInst) - assert(typ.kind == tyProc) - for i in 1..<value.len: - assert(typ.len == typ.n.len) - genOtherArg(p, value, i, typ, params, argsCounter) - if params.len == 0: - lineF(p, cpsStmts, "$#;$n", [decl]) - else: - lineF(p, cpsStmts, "$#($#);$n", [decl, params]) + if isCppCtorCall: + var didGenTemp = false + genCppVarForCtor(p, value, decl, didGenTemp) + line(p, cpsStmts, decl) else: - initLocExprSingleUse(p, value, tmp) - lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc]) + tmp = initLocExprSingleUse(p, value) + if value.kind == nkEmpty: + lineF(p, cpsStmts, "$#;\n", [decl]) + else: + lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc]) return assignLocalVar(p, vn) initLocalVar(p, v, imm) @@ -366,7 +405,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # put it in the locals section - mainly because of loops which # use the var in a call to resetLoc() in the statements section lineCg(targetProc, cpsLocals, "hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1);$n", - [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) + [v.loc.snippet, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) # nothing special left to do later on - let's avoid closing and reopening blocks forHcr = false @@ -375,11 +414,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # be able to re-run it but without the top level code - just the init of globals if forHcr: lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N", - [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) + [v.loc.snippet, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) startBlock(targetProc) if value.kind != nkEmpty and valueAsRope.len == 0: genLineDir(targetProc, vn) - loadInto(targetProc, vn, value, v.loc) + if not isCppCtorCall: + loadInto(targetProc, vn, value, v.loc) if forHcr: endBlock(targetProc) @@ -396,8 +436,7 @@ proc genSingleVar(p: BProc, a: PNode) = proc genClosureVar(p: BProc, a: PNode) = var immediateAsgn = a[2].kind != nkEmpty - var v: TLoc - initLocExpr(p, a[0], v) + var v: TLoc = initLocExpr(p, a[0]) genLineDir(p, a) if immediateAsgn: loadInto(p, a[0], a[2], v) @@ -432,7 +471,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = a: TLoc lelse: TLabel if not isEmptyType(n.typ) and d.k == locNone: - getTemp(p, n.typ, d) + d = getTemp(p, n.typ) genLineDir(p, n) let lend = getLabel(p) for it in n.sons: @@ -440,7 +479,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = if d.k == locTemp and isEmptyType(n.typ): d.k = locNone if it.len == 2: startBlock(p) - initLocExprSingleUse(p, it[0], a) + a = initLocExprSingleUse(p, it[0]) lelse = getLabel(p) inc(p.labels) lineF(p, cpsStmts, "if (!$1) goto $2;$n", @@ -508,7 +547,7 @@ proc genComputedGoto(p: BProc; n: PNode) = # wrapped inside stmt lists by inject destructors won't be recognised let n = n.flattenStmts() var casePos = -1 - var arraySize: int + var arraySize: int = 0 for i in 0..<n.len: let it = n[i] if it.kind == nkCaseStmt: @@ -542,8 +581,7 @@ proc genComputedGoto(p: BProc; n: PNode) = genStmts(p, n[j]) let caseStmt = n[casePos] - var a: TLoc - initLocExpr(p, caseStmt[0], a) + var a: TLoc = initLocExpr(p, caseStmt[0]) # first goto: lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc]) @@ -581,8 +619,7 @@ proc genComputedGoto(p: BProc; n: PNode) = else: genStmts(p, it) - var a: TLoc - initLocExpr(p, caseStmt[0], a) + var a: TLoc = initLocExpr(p, caseStmt[0]) lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc]) endBlock(p) @@ -610,11 +647,11 @@ proc genWhileStmt(p: BProc, t: PNode) = else: p.breakIdx = startBlock(p, "while (1) {$n") p.blocks[p.breakIdx].isLoop = true - initLocExpr(p, t[0], a) + a = initLocExpr(p, t[0]) if (t[0].kind != nkIntLit) or (t[0].intVal == 0): lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)]) assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts)) - lineF(p, cpsStmts, ";$n", []) + appcg(p, cpsStmts, ";$n", []) genStmts(p, loopBody) if optProfiler in p.options: @@ -629,7 +666,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) = # bug #4505: allocate the temp in the outer scope # so that it can escape the generated {}: if d.k == locNone: - getTemp(p, n.typ, d) + d = getTemp(p, n.typ) d.flags.incl(lfEnforceDeref) preserveBreakIdx: p.breakIdx = startBlock(p) @@ -649,14 +686,13 @@ proc genParForStmt(p: BProc, t: PNode) = preserveBreakIdx: let forLoopVar = t[0].sym - var rangeA, rangeB: TLoc assignLocalVar(p, t[0]) #initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack) #discard mangleName(forLoopVar) let call = t[1] - assert(call.len in {4, 5}) - initLocExpr(p, call[1], rangeA) - initLocExpr(p, call[2], rangeB) + assert(call.len == 4 or call.len == 5) + var rangeA = initLocExpr(p, call[1]) + var rangeB = initLocExpr(p, call[2]) # $n at the beginning because of #9710 if call.len == 4: # procName(a, b, annotation) @@ -673,8 +709,7 @@ proc genParForStmt(p: BProc, t: PNode) = rangeA.rdLoc, rangeB.rdLoc, call[3].getStr.rope]) else: # `||`(a, b, step, annotation) - var step: TLoc - initLocExpr(p, call[3], step) + var step: TLoc = initLocExpr(p, call[3]) lineF(p, cpsStmts, "$n#pragma omp $5$n" & "for ($1 = $2; $1 <= $3; $1 += $4)", [forLoopVar.loc.rdLoc, @@ -720,6 +755,18 @@ proc raiseExit(p: BProc) = lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n", [p.nestedTryStmts[^1].label]) +proc raiseExitCleanup(p: BProc, destroy: string) = + assert p.config.exc == excGoto + if nimErrorFlagDisabled notin p.flags: + p.flags.incl nimErrorFlagAccessed + if p.nestedTryStmts.len == 0: + p.flags.incl beforeRetNeeded + # easy case, simply goto 'ret': + lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$1; goto BeforeRet_;}$n", [destroy]) + else: + lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$2; goto LA$1_;}$n", + [p.nestedTryStmts[^1].label, destroy]) + proc finallyActions(p: BProc) = if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: # if the current try stmt have a finally block, @@ -744,16 +791,19 @@ proc raiseInstr(p: BProc; result: var Rope) = proc genRaiseStmt(p: BProc, t: PNode) = if t[0].kind != nkEmpty: - var a: TLoc - initLocExprSingleUse(p, t[0], a) + var a: TLoc = initLocExprSingleUse(p, t[0]) finallyActions(p) var e = rdLoc(a) discard getTypeDesc(p.module, t[0].typ) var typ = skipTypes(t[0].typ, abstractPtrs) - # XXX For reasons that currently escape me, this is only required by the new - # C++ based exception handling: - if p.config.exc == excCpp: + case p.config.exc + of excCpp: blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen) + of excGoto: + blockLeaveActions(p, howManyTrys = 0, + howManyExcepts = (if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: 1 else: 0)) + else: + discard genLineDir(p, t) if isImportedException(typ, p.config): lineF(p, cpsStmts, "throw $1;$n", [e]) @@ -767,11 +817,7 @@ proc genRaiseStmt(p: BProc, t: PNode) = else: finallyActions(p) genLineDir(p, t) - # reraise the last exception: - if p.config.exc == excCpp: - line(p, cpsStmts, "throw;\n") - else: - linefmt(p, cpsStmts, "#reraiseException();$n", []) + linefmt(p, cpsStmts, "#reraiseException();$n", []) raiseInstr(p, p.s(cpsStmts)) template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, @@ -779,12 +825,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, var x, y: TLoc for i in 0..<b.len - 1: if b[i].kind == nkRange: - initLocExpr(p, b[i][0], x) - initLocExpr(p, b[i][1], y) + x = initLocExpr(p, b[i][0]) + y = initLocExpr(p, b[i][1]) lineCg(p, cpsStmts, rangeFormat, [rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl]) else: - initLocExpr(p, b[i], x) + x = initLocExpr(p, b[i]) lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl]) proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc, @@ -826,8 +872,7 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc, template genCaseGeneric(p: BProc, t: PNode, d: var TLoc, rangeFormat, eqFormat: FormatStr) = - var a: TLoc - initLocExpr(p, t[0], a) + var a: TLoc = initLocExpr(p, t[0]) var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a) fixLabel(p, lend) @@ -837,8 +882,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, var x: TLoc for i in 0..<b.len - 1: assert(b[i].kind != nkRange) - initLocExpr(p, b[i], x) - var j: int + x = initLocExpr(p, b[i]) + var j: int = 0 case b[i].kind of nkStrLit..nkTripleStrLit: j = int(hashString(p.config, b[i].strVal) and high(branches)) @@ -861,8 +906,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) = var bitMask = math.nextPowerOfTwo(strings) - 1 var branches: seq[Rope] newSeq(branches, bitMask + 1) - var a: TLoc - initLocExpr(p, t[0], a) # fist pass: generate ifs+goto: + var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto: var labId = p.labels for i in 1..<t.len: inc(p.labels) @@ -898,6 +942,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) = genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n") proc branchHasTooBigRange(b: PNode): bool = + result = false for it in b: # last son is block if (it.kind == nkRange) and @@ -905,6 +950,7 @@ proc branchHasTooBigRange(b: PNode): bool = return true proc ifSwitchSplitPoint(p: BProc, n: PNode): int = + result = 0 for i in 1..<n.len: var branch = n[i] var stmtBlock = lastSon(branch) @@ -940,8 +986,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = var splitPoint = ifSwitchSplitPoint(p, n) # generate if part (might be empty): - var a: TLoc - initLocExpr(p, n[0], a) + var a: TLoc = initLocExpr(p, n[0]) var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d, rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n", eqFormat = "if ($1 == $2) goto $3;$n", @@ -963,15 +1008,18 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = hasDefault = true exprBlock(p, branch.lastSon, d) lineF(p, cpsStmts, "break;$n", []) - if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault: - lineF(p, cpsStmts, "default: __assume(0);$n", []) + if not hasDefault: + if hasBuiltinUnreachable in CC[p.config.cCompiler].props: + lineF(p, cpsStmts, "default: __builtin_unreachable();$n", []) + elif hasAssume in CC[p.config.cCompiler].props: + lineF(p, cpsStmts, "default: __assume(0);$n", []) lineF(p, cpsStmts, "}$n", []) if lend != "": fixLabel(p, lend) proc genCase(p: BProc, t: PNode, d: var TLoc) = genLineDir(p, t) if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) case skipTypes(t[0].typ, abstractVarRange).kind of tyString: genStringCase(p, t, tyString, d) @@ -997,7 +1045,7 @@ proc genRestoreFrameAfterException(p: BProc) = proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = #[ code to generate: - std::exception_ptr error = nullptr; + std::exception_ptr error; try { body; } catch (Exception e) { @@ -1022,13 +1070,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = p.module.includeHeader("<exception>") if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) genLineDir(p, t) inc(p.labels, 2) let etmp = p.labels - - p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp])) + #init on locals, fixes #23306 + lineCg(p, cpsLocals, "std::exception_ptr T$1_;$n", [etmp]) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) @@ -1062,7 +1110,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if hasIf: lineF(p, cpsStmts, "else ", []) startBlock(p) # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) expr(p, t[i][0], d) linefmt(p, cpsStmts, "#popCurrentException();$n", []) endBlock(p) @@ -1082,7 +1129,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(typeNode.typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1125,7 +1172,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if t[i].len == 1: # general except section: - startBlock(p, "catch (...) {", []) + startBlock(p, "catch (...) {$n", []) genExceptBranchBody(t[i][0]) endBlock(p) catchAllPresent = true @@ -1151,7 +1198,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # general finally block: if t.len > 0 and t[^1].kind == nkFinally: if not catchAllPresent: - startBlock(p, "catch (...) {", []) + startBlock(p, "catch (...) {$n", []) genRestoreFrameAfterException(p) linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) endBlock(p) @@ -1188,7 +1235,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = expr(p, body, d) if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) genLineDir(p, t) cgsym(p.module, "popCurrentExceptionEx") let fin = if t[^1].kind == nkFinally: t[^1] else: nil @@ -1266,7 +1313,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = p.flags.incl nimErrorFlagAccessed if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) expr(p, t[0], d) @@ -1301,7 +1348,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(t[i][j].typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", + [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1372,7 +1420,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # propagateCurrentException(); # if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) let quirkyExceptions = p.config.exc == excQuirky or (t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags) if not quirkyExceptions: @@ -1381,7 +1429,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = p.flags.incl noSafePoints genLineDir(p, t) cgsym(p.module, "Exception") - var safePoint: Rope + var safePoint: Rope = "" if not quirkyExceptions: safePoint = getTempName(p.module) linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) @@ -1446,7 +1494,8 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(t[i][j].typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", + [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) @@ -1477,28 +1526,31 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = var res = "" - for it in t.sons: + let offset = + if isAsmStmt: 1 # first son is pragmas + else: 0 + + for i in offset..<t.len: + let it = t[i] case it.kind of nkStrLit..nkTripleStrLit: res.add(it.strVal) of nkSym: var sym = it.sym if sym.kind in {skProc, skFunc, skIterator, skMethod}: - var a: TLoc - initLocExpr(p, it, a) + var a: TLoc = initLocExpr(p, it) res.add($rdLoc(a)) elif sym.kind == skType: res.add($getTypeDesc(p.module, sym.typ)) else: discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs)) fillBackendName(p.module, sym) - res.add($sym.loc.r) + res.add($sym.loc.snippet) of nkTypeOfExpr: res.add($getTypeDesc(p.module, it.typ)) else: discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs)) - var a: TLoc - initLocExpr(p, it, a) + var a: TLoc = initLocExpr(p, it) res.add($a.rdLoc) if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props: @@ -1523,6 +1575,21 @@ proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) genLineDir(p, t) var s = newRopeAppender() + + var asmSyntax = "" + if (let p = t[0]; p.kind == nkPragma): + for i in p: + if whichPragma(i) == wAsmSyntax: + asmSyntax = i[1].strVal + + if asmSyntax != "" and + not ( + asmSyntax == "gcc" and hasGnuAsm in CC[p.config.cCompiler].props or + asmSyntax == "vcc" and hasGnuAsm notin CC[p.config.cCompiler].props): + localError( + p.config, t.info, + "Your compiler does not support the specified inline assembler") + genAsmOrEmitStmt(p, t, isAsmStmt=true, s) # see bug #2362, "top level asm statements" seem to be a mis-feature # but even if we don't do this, the example in #2362 cannot possibly @@ -1538,7 +1605,7 @@ proc determineSection(n: PNode): TCFileSection = result = cfsProcHeaders if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: let sec = n[0].strVal - if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes + if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND elif sec.startsWith("/*VARSECTION*/"): result = cfsVars elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders @@ -1555,9 +1622,14 @@ proc genEmit(p: BProc, t: PNode) = line(p, cpsStmts, s) proc genPragma(p: BProc, n: PNode) = - for it in n.sons: + for i in 0..<n.len: + let it = n[i] case whichPragma(it) of wEmit: genEmit(p, it) + of wPush: + processPushBackendOption(p.config, p.optionsStack, p.options, n, i+1) + of wPop: + processPopBackendOption(p.config, p.optionsStack, p.options) else: discard @@ -1575,6 +1647,8 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType, "#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n", [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field), lit]) + if p.config.exc == excGoto: + raiseExit(p) when false: proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) = @@ -1593,13 +1667,12 @@ when false: expr(p, call, d) proc asgnFieldDiscriminant(p: BProc, e: PNode) = - var a, tmp: TLoc var dotExpr = e[0] if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0] - initLocExpr(p, e[0], a) - getTemp(p, a.t, tmp) + var a = initLocExpr(p, e[0]) + var tmp: TLoc = getTemp(p, a.t) expr(p, e[1], tmp) - if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0: + if p.inUncheckedAssignSection == 0: let field = dotExpr[1].sym genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field) message(p.config, e.info, warnCaseTransition) @@ -1615,11 +1688,11 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = else: let le = e[0] let ri = e[1] - var a: TLoc - discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar) - initLoc(a, locNone, le, OnUnknown) + var a: TLoc = initLoc(locNone, le, OnUnknown) + discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) + genLineDir(p, le) # it can be a nkBracketExpr, which may raise expr(p, le, a) a.flags.excl(lfPrepareForMutation) if fastAsgn: incl(a.flags, lfNoDeepCopy) @@ -1628,7 +1701,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = loadInto(p, le, ri, a) proc genStmts(p: BProc, t: PNode) = - var a: TLoc + var a: TLoc = default(TLoc) let isPush = p.config.hasHint(hintExtendedContext) if isPush: pushInfoContext(p.config, t.info) |