diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 7a647c3740..7586e82c75 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -82,6 +82,7 @@ type guards: TModel # nested guards locked: seq[PNode] # locked locations gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool + canRaiseDefect: bool # defects are deliberately omitted from `exc` isInnerProc: bool inEnforcedNoSideEffects: bool isArrayIndexing: bool @@ -140,6 +141,11 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info) createTypeBoundOps(tracked.graph, tracked.c, typ, info, tracked.c.idgen) + for kind in TTypeAttachedOp: + let op = getAttachedOp(tracked.graph, typ, kind) + if op != nil and sfNeverRaises notin op.flags: + tracked.canRaiseDefect = true + break if (tfHasAsgn in typ.flags) or optSeqDestructors in tracked.config.globalOptions: tracked.owner.flags.incl sfInjectDestructors @@ -191,6 +197,23 @@ proc shouldWarnRangeConversion(conf: ConfigRef; info: TLineInfo; formalType, arg else: result = false +proc conversionCanRaiseDefect(conf: ConfigRef; destType, sourceType: PType): bool = + ## Keep this in sync with the range checks introduced by `transformConv`. + let + dest = destType.skipTypes(abstractVarRange) + source = sourceType.skipTypes(abstractVarRange) + case dest.kind + of tyInt..tyInt64, tyEnum, tyChar, tyUInt8..tyUInt32: + if not source.isOrdinalType: + result = dest.kind in tyInt..tyInt64 + else: + result = firstOrd(conf, destType) > firstOrd(conf, sourceType) or + lastOrd(conf, sourceType) > lastOrd(conf, destType) + of tyFloat..tyFloat128: + result = destType.skipTypes(abstractVar).kind == tyRange + else: + result = false + proc lockLocations(a: PEffects; pragma: PNode) = if pragma.kind != nkExprColonExpr: localError(a.config, pragma.info, "locks pragma without argument") @@ -493,7 +516,9 @@ proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) = if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): return if e.typ != nil: - if not isDefectException(e.typ): + if isDefectException(e.typ): + a.canRaiseDefect = true + else: throws(a.exc, e, comesFrom) proc skipHiddenConv(n: PNode): PNode = @@ -1109,6 +1134,32 @@ proc trackCall(tracked: PEffects; n: PNode) = markSideEffect(tracked, a, n.info) # p's effects are ours too: var a = n[0] + if a.kind == nkSym: + let s = a.sym + case s.magic + of mNone: + if {sfNeverRaises, sfImportc, sfCompilerProc} * s.flags == {} and + (sfSystemModule notin getModule(s).flags or + sfSystemRaisesDefect in s.flags): + tracked.canRaiseDefect = true + of mUnaryMinusI..mAbsI, mAddI..mPred: + if optOverflowCheck in tracked.currOptions: + tracked.canRaiseDefect = true + of mInc, mDec: + let typ = n[1].typ.skipTypes({tyGenericInst, tyAlias, tySink, + tyVar, tyLent, tyRange, tyDistinct}) + if optOverflowCheck in tracked.currOptions and + typ.kind notin {tyUInt..tyUInt64}: + tracked.canRaiseDefect = true + of mDivU, mModU: + tracked.canRaiseDefect = true + of mAddF64..mDivF64: + if {optNaNCheck, optInfCheck} * tracked.currOptions != {}: + tracked.canRaiseDefect = true + else: + discard + else: + tracked.canRaiseDefect = true #if canRaise(a): # echo "this can raise ", tracked.config $ n.info let op = a.typ @@ -1347,6 +1398,7 @@ proc track(tracked: PEffects, n: PNode) = else: track(tracked, n[0]) of nkRaiseStmt: + tracked.canRaiseDefect = true if n[0].kind != nkEmpty: n[0].info = n.info #throws(tracked.exc, n[0]) @@ -1375,6 +1427,8 @@ proc track(tracked: PEffects, n: PNode) = for i in 0..