Merge pull request #8039 from yglukhov/proc-pragmas
Fixed stacktrace/linetrace proc pragmas when appended by macro pragma
This commit is contained in:
commit
ee16e62061
3 changed files with 144 additions and 66 deletions
|
|
@ -223,9 +223,9 @@ proc isTurnedOn(c: PContext, n: PNode): bool =
|
||||||
if x.kind == nkIntLit: return x.intVal != 0
|
if x.kind == nkIntLit: return x.intVal != 0
|
||||||
localError(c.config, n.info, "'on' or 'off' expected")
|
localError(c.config, n.info, "'on' or 'off' expected")
|
||||||
|
|
||||||
proc onOff(c: PContext, n: PNode, op: TOptions) =
|
proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
|
||||||
if isTurnedOn(c, n): c.config.options = c.config.options + op
|
if isTurnedOn(c, n): resOptions = resOptions + op
|
||||||
else: c.config.options = c.config.options - op
|
else: resOptions = resOptions - op
|
||||||
|
|
||||||
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
|
proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
|
||||||
if isTurnedOn(c, n): incl(c.module.flags, flag)
|
if isTurnedOn(c, n): incl(c.module.flags, flag)
|
||||||
|
|
@ -313,54 +313,68 @@ proc processNote(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
invalidPragma(c, n)
|
invalidPragma(c, n)
|
||||||
|
|
||||||
proc processOption(c: PContext, n: PNode): bool =
|
proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
|
||||||
if n.kind notin nkPragmaCallKinds or n.len != 2: result = true
|
case w
|
||||||
|
of wChecks: ChecksOptions
|
||||||
|
of wObjChecks: {optObjCheck}
|
||||||
|
of wFieldChecks: {optFieldCheck}
|
||||||
|
of wRangechecks: {optRangeCheck}
|
||||||
|
of wBoundchecks: {optBoundsCheck}
|
||||||
|
of wOverflowchecks: {optOverflowCheck}
|
||||||
|
of wNilchecks: {optNilCheck}
|
||||||
|
of wFloatchecks: {optNaNCheck, optInfCheck}
|
||||||
|
of wNanChecks: {optNaNCheck}
|
||||||
|
of wInfChecks: {optInfCheck}
|
||||||
|
of wMovechecks: {optMoveCheck}
|
||||||
|
of wAssertions: {optAssert}
|
||||||
|
of wWarnings: {optWarns}
|
||||||
|
of wHints: {optHints}
|
||||||
|
of wLinedir: {optLineDir}
|
||||||
|
of wStacktrace: {optStackTrace}
|
||||||
|
of wLinetrace: {optLineTrace}
|
||||||
|
of wDebugger: {optEndb}
|
||||||
|
of wProfiler: {optProfiler, optMemTracker}
|
||||||
|
of wMemTracker: {optMemTracker}
|
||||||
|
of wByRef: {optByRef}
|
||||||
|
of wImplicitStatic: {optImplicitStatic}
|
||||||
|
of wPatterns: {optPatterns}
|
||||||
|
else: {}
|
||||||
|
|
||||||
|
proc tryProcessOption(c: PContext, n: PNode, resOptions: var TOptions): bool =
|
||||||
|
result = true
|
||||||
|
if n.kind notin nkPragmaCallKinds or n.len != 2: result = false
|
||||||
elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
|
elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
|
||||||
elif n.sons[0].kind != nkIdent: result = true
|
elif n.sons[0].kind != nkIdent: result = false
|
||||||
else:
|
else:
|
||||||
let sw = whichKeyword(n.sons[0].ident)
|
let sw = whichKeyword(n.sons[0].ident)
|
||||||
case sw
|
let opts = pragmaToOptions(sw)
|
||||||
of wChecks: onOff(c, n, ChecksOptions)
|
if opts != {}:
|
||||||
of wObjChecks: onOff(c, n, {optObjCheck})
|
onOff(c, n, opts, resOptions)
|
||||||
of wFieldChecks: onOff(c, n, {optFieldCheck})
|
else:
|
||||||
of wRangechecks: onOff(c, n, {optRangeCheck})
|
case sw
|
||||||
of wBoundchecks: onOff(c, n, {optBoundsCheck})
|
of wCallconv: processCallConv(c, n)
|
||||||
of wOverflowchecks: onOff(c, n, {optOverflowCheck})
|
of wDynlib: processDynLib(c, n, nil)
|
||||||
of wNilchecks: onOff(c, n, {optNilCheck})
|
of wOptimization:
|
||||||
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
|
if n.sons[1].kind != nkIdent:
|
||||||
of wNanChecks: onOff(c, n, {optNaNCheck})
|
invalidPragma(c, n)
|
||||||
of wInfChecks: onOff(c, n, {optInfCheck})
|
else:
|
||||||
of wMovechecks: onOff(c, n, {optMoveCheck})
|
case n.sons[1].ident.s.normalize
|
||||||
of wAssertions: onOff(c, n, {optAssert})
|
of "speed":
|
||||||
of wWarnings: onOff(c, n, {optWarns})
|
incl(resOptions, optOptimizeSpeed)
|
||||||
of wHints: onOff(c, n, {optHints})
|
excl(resOptions, optOptimizeSize)
|
||||||
of wCallconv: processCallConv(c, n)
|
of "size":
|
||||||
of wLinedir: onOff(c, n, {optLineDir})
|
excl(resOptions, optOptimizeSpeed)
|
||||||
of wStacktrace: onOff(c, n, {optStackTrace})
|
incl(resOptions, optOptimizeSize)
|
||||||
of wLinetrace: onOff(c, n, {optLineTrace})
|
of "none":
|
||||||
of wDebugger: onOff(c, n, {optEndb})
|
excl(resOptions, optOptimizeSpeed)
|
||||||
of wProfiler: onOff(c, n, {optProfiler, optMemTracker})
|
excl(resOptions, optOptimizeSize)
|
||||||
of wMemTracker: onOff(c, n, {optMemTracker})
|
else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
|
||||||
of wByRef: onOff(c, n, {optByRef})
|
else: result = false
|
||||||
of wDynlib: processDynLib(c, n, nil)
|
|
||||||
of wOptimization:
|
proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
|
||||||
if n.sons[1].kind != nkIdent:
|
if not tryProcessOption(c, n, resOptions):
|
||||||
invalidPragma(c, n)
|
# calling conventions (boring...):
|
||||||
else:
|
localError(c.config, n.info, "option expected")
|
||||||
case n.sons[1].ident.s.normalize
|
|
||||||
of "speed":
|
|
||||||
incl(c.config.options, optOptimizeSpeed)
|
|
||||||
excl(c.config.options, optOptimizeSize)
|
|
||||||
of "size":
|
|
||||||
excl(c.config.options, optOptimizeSpeed)
|
|
||||||
incl(c.config.options, optOptimizeSize)
|
|
||||||
of "none":
|
|
||||||
excl(c.config.options, optOptimizeSpeed)
|
|
||||||
excl(c.config.options, optOptimizeSize)
|
|
||||||
else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
|
|
||||||
of wImplicitStatic: onOff(c, n, {optImplicitStatic})
|
|
||||||
of wPatterns: onOff(c, n, {optPatterns})
|
|
||||||
else: result = true
|
|
||||||
|
|
||||||
proc processPush(c: PContext, n: PNode, start: int) =
|
proc processPush(c: PContext, n: PNode, start: int) =
|
||||||
if n.sons[start-1].kind in nkPragmaCallKinds:
|
if n.sons[start-1].kind in nkPragmaCallKinds:
|
||||||
|
|
@ -373,7 +387,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||||
x.notes = c.config.notes
|
x.notes = c.config.notes
|
||||||
c.optionStack.add(x)
|
c.optionStack.add(x)
|
||||||
for i in countup(start, sonsLen(n) - 1):
|
for i in countup(start, sonsLen(n) - 1):
|
||||||
if processOption(c, n.sons[i]):
|
if not tryProcessOption(c, n.sons[i], c.config.options):
|
||||||
# simply store it somewhere:
|
# simply store it somewhere:
|
||||||
if x.otherPragmas.isNil:
|
if x.otherPragmas.isNil:
|
||||||
x.otherPragmas = newNodeI(nkPragma, n.info)
|
x.otherPragmas = newNodeI(nkPragma, n.info)
|
||||||
|
|
@ -964,13 +978,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
of wCodegenDecl: processCodegenDecl(c, it, sym)
|
||||||
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wMovechecks,
|
wLinedir, wOptimization, wMovechecks, wCallconv, wDebugger, wProfiler,
|
||||||
wCallconv,
|
wFloatchecks, wNanChecks, wInfChecks, wPatterns:
|
||||||
wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
|
processOption(c, it, c.config.options)
|
||||||
wPatterns:
|
of wStacktrace, wLinetrace:
|
||||||
if processOption(c, it):
|
if sym.kind in {skProc, skMethod, skConverter}:
|
||||||
# calling conventions (boring...):
|
processOption(c, it, sym.options)
|
||||||
localError(c.config, it.info, "option expected")
|
else:
|
||||||
|
processOption(c, it, c.config.options)
|
||||||
of FirstCallConv..LastCallConv:
|
of FirstCallConv..LastCallConv:
|
||||||
assert(sym != nil)
|
assert(sym != nil)
|
||||||
if sym.typ == nil: invalidPragma(c, it)
|
if sym.typ == nil: invalidPragma(c, it)
|
||||||
|
|
@ -1000,7 +1015,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
of wByRef:
|
of wByRef:
|
||||||
noVal(c, it)
|
noVal(c, it)
|
||||||
if sym == nil or sym.typ == nil:
|
if sym == nil or sym.typ == nil:
|
||||||
if processOption(c, it): localError(c.config, it.info, "option expected")
|
processOption(c, it, c.config.options)
|
||||||
else:
|
else:
|
||||||
incl(sym.typ.flags, tfByRef)
|
incl(sym.typ.flags, tfByRef)
|
||||||
of wByCopy:
|
of wByCopy:
|
||||||
|
|
|
||||||
|
|
@ -1486,10 +1486,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
s.ast = n
|
s.ast = n
|
||||||
#s.scope = c.currentScope
|
#s.scope = c.currentScope
|
||||||
|
|
||||||
|
s.options = c.config.options
|
||||||
|
|
||||||
# before compiling the proc body, set as current the scope
|
# before compiling the proc body, set as current the scope
|
||||||
# where the proc was declared
|
# where the proc was declared
|
||||||
let oldScope = c.currentScope
|
let oldScope = c.currentScope
|
||||||
let oldOptions = c.config.options
|
|
||||||
#c.currentScope = s.scope
|
#c.currentScope = s.scope
|
||||||
pushOwner(c, s)
|
pushOwner(c, s)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -1558,6 +1559,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
addParams(c, proto.typ.n, proto.kind)
|
addParams(c, proto.typ.n, proto.kind)
|
||||||
proto.info = s.info # more accurate line information
|
proto.info = s.info # more accurate line information
|
||||||
s.typ = proto.typ
|
s.typ = proto.typ
|
||||||
|
proto.options = s.options
|
||||||
s = proto
|
s = proto
|
||||||
n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
|
n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
|
||||||
n.sons[paramsPos] = proto.ast.sons[paramsPos]
|
n.sons[paramsPos] = proto.ast.sons[paramsPos]
|
||||||
|
|
@ -1569,8 +1571,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
proto.ast = n # needed for code generation
|
proto.ast = n # needed for code generation
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
pushOwner(c, s)
|
pushOwner(c, s)
|
||||||
s.options = c.config.options
|
|
||||||
c.config.options = oldOptions
|
|
||||||
|
|
||||||
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
|
||||||
if s.name.s[0] in {'.', '('}:
|
if s.name.s[0] in {'.', '('}:
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,84 @@
|
||||||
discard """
|
discard """
|
||||||
file: "toverflw.nim"
|
file: "toverflw.nim"
|
||||||
output: "the computation overflowed"
|
output: "ok"
|
||||||
|
cmd: "nim $target -d:release $options $file"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Tests nim's ability to detect overflows
|
# Tests nim's ability to detect overflows
|
||||||
|
|
||||||
{.push overflowChecks: on.}
|
{.push overflowChecks: on.}
|
||||||
|
|
||||||
var
|
var
|
||||||
a, b: int
|
a = high(int)
|
||||||
a = high(int)
|
b = -2
|
||||||
b = -2
|
overflowDetected = false
|
||||||
|
|
||||||
try:
|
try:
|
||||||
writeLine(stdout, b - a)
|
writeLine(stdout, b - a)
|
||||||
except OverflowError:
|
except OverflowError:
|
||||||
writeLine(stdout, "the computation overflowed")
|
overflowDetected = true
|
||||||
|
|
||||||
{.pop.} # overflow check
|
{.pop.} # overflow check
|
||||||
#OUT the computation overflowed
|
|
||||||
|
doAssert(overflowDetected)
|
||||||
|
|
||||||
|
block: # Overflow checks in a proc
|
||||||
|
var
|
||||||
|
a = high(int)
|
||||||
|
b = -2
|
||||||
|
overflowDetected = false
|
||||||
|
|
||||||
|
{.push overflowChecks: on.}
|
||||||
|
proc foo() =
|
||||||
|
let c = b - a
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
try:
|
||||||
|
foo()
|
||||||
|
except OverflowError:
|
||||||
|
overflowDetected = true
|
||||||
|
|
||||||
|
doAssert(overflowDetected)
|
||||||
|
|
||||||
|
block: # Overflow checks in a forward declared proc
|
||||||
|
var
|
||||||
|
a = high(int)
|
||||||
|
b = -2
|
||||||
|
overflowDetected = false
|
||||||
|
|
||||||
|
proc foo()
|
||||||
|
|
||||||
|
{.push overflowChecks: on.}
|
||||||
|
proc foo() =
|
||||||
|
let c = b - a
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
try:
|
||||||
|
foo()
|
||||||
|
except OverflowError:
|
||||||
|
overflowDetected = true
|
||||||
|
|
||||||
|
doAssert(overflowDetected)
|
||||||
|
|
||||||
|
block: # Overflow checks doesn't affect fwd declaration
|
||||||
|
var
|
||||||
|
a = high(int)
|
||||||
|
b = -2
|
||||||
|
overflowDetected = false
|
||||||
|
|
||||||
|
{.push overflowChecks: on.}
|
||||||
|
proc foo()
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
proc foo() =
|
||||||
|
let c = b - a
|
||||||
|
|
||||||
|
try:
|
||||||
|
foo()
|
||||||
|
except OverflowError:
|
||||||
|
overflowDetected = true
|
||||||
|
|
||||||
|
doAssert(not overflowDetected)
|
||||||
|
|
||||||
|
|
||||||
|
echo "ok"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue