Merge pull request #8039 from yglukhov/proc-pragmas

Fixed stacktrace/linetrace proc pragmas when appended by macro pragma
This commit is contained in:
Andreas Rumpf 2018-06-16 01:59:06 +02:00 • committed by GitHub
commit ee16e62061
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 144 additions and 66 deletions

View file

@ -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,35 +313,46 @@ 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)
let opts = pragmaToOptions(sw)
if opts != {}:
onOff(c, n, opts, resOptions)
else:
case sw case sw
of wChecks: onOff(c, n, ChecksOptions)
of wObjChecks: onOff(c, n, {optObjCheck})
of wFieldChecks: onOff(c, n, {optFieldCheck})
of wRangechecks: onOff(c, n, {optRangeCheck})
of wBoundchecks: onOff(c, n, {optBoundsCheck})
of wOverflowchecks: onOff(c, n, {optOverflowCheck})
of wNilchecks: onOff(c, n, {optNilCheck})
of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
of wNanChecks: onOff(c, n, {optNaNCheck})
of wInfChecks: onOff(c, n, {optInfCheck})
of wMovechecks: onOff(c, n, {optMoveCheck})
of wAssertions: onOff(c, n, {optAssert})
of wWarnings: onOff(c, n, {optWarns})
of wHints: onOff(c, n, {optHints})
of wCallconv: processCallConv(c, n) of wCallconv: processCallConv(c, n)
of wLinedir: onOff(c, n, {optLineDir})
of wStacktrace: onOff(c, n, {optStackTrace})
of wLinetrace: onOff(c, n, {optLineTrace})
of wDebugger: onOff(c, n, {optEndb})
of wProfiler: onOff(c, n, {optProfiler, optMemTracker})
of wMemTracker: onOff(c, n, {optMemTracker})
of wByRef: onOff(c, n, {optByRef})
of wDynlib: processDynLib(c, n, nil) of wDynlib: processDynLib(c, n, nil)
of wOptimization: of wOptimization:
if n.sons[1].kind != nkIdent: if n.sons[1].kind != nkIdent:
@ -349,18 +360,21 @@ proc processOption(c: PContext, n: PNode): bool =
else: else:
case n.sons[1].ident.s.normalize case n.sons[1].ident.s.normalize
of "speed": of "speed":
incl(c.config.options, optOptimizeSpeed) incl(resOptions, optOptimizeSpeed)
excl(c.config.options, optOptimizeSize) excl(resOptions, optOptimizeSize)
of "size": of "size":
excl(c.config.options, optOptimizeSpeed) excl(resOptions, optOptimizeSpeed)
incl(c.config.options, optOptimizeSize) incl(resOptions, optOptimizeSize)
of "none": of "none":
excl(c.config.options, optOptimizeSpeed) excl(resOptions, optOptimizeSpeed)
excl(c.config.options, optOptimizeSize) excl(resOptions, optOptimizeSize)
else: localError(c.config, n.info, "'none', 'speed' or 'size' expected") else: localError(c.config, n.info, "'none', 'speed' or 'size' expected")
of wImplicitStatic: onOff(c, n, {optImplicitStatic}) else: result = false
of wPatterns: onOff(c, n, {optPatterns})
else: result = true proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
if not tryProcessOption(c, n, resOptions):
# calling conventions (boring...):
localError(c.config, n.info, "option expected")
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:

View file

@ -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 {'.', '('}:

View file

@ -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"