fixes a long-standing bug about procvar checking

This commit is contained in:
Araq 2013-03-25 01:44:52 +01:00
commit 3051c52f51
8 changed files with 45 additions and 22 deletions

View file

@ -764,7 +764,7 @@ const
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5! dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit} nkCommand, nkCallStrLit, nkHiddenCallConv}
nkLambdaKinds* = {nkLambda, nkDo} nkLambdaKinds* = {nkLambda, nkDo}
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}

View file

@ -201,7 +201,7 @@ proc myOpen(module: PSym): PPassContext =
if c.p != nil: InternalError(module.info, "sem.myOpen") if c.p != nil: InternalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr c.semConstExpr = semConstExpr
c.semExpr = semExpr c.semExpr = semExpr
c.semExprWithType = semExprWithType c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall c.semOverloadedCall = semOverloadedCall
c.semTypeNode = semTypeNode c.semTypeNode = semTypeNode

View file

@ -69,7 +69,7 @@ type
libs*: TLinkedList # all libs used by this module libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.} filter: TSymKinds): PNode {.nimcall.}

View file

@ -19,7 +19,20 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
var smoduleId = getModule(s).id
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
smoduleId != c.module.id and smoduleId != c.friendModule.id:
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
proc semProcvarCheck(c: PContext, n: PNode) =
let n = n.skipConv
if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skIterator,
skConverter}:
performProcvarCheck(c, n, n.sym)
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags) result = semExpr(c, n, flags)
if result.kind == nkEmpty: if result.kind == nkEmpty:
# do not produce another redundant error message: # do not produce another redundant error message:
@ -33,15 +46,32 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
result.typ = errorType(c) result.typ = errorType(c)
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags) result = semExpr(c, n, flags)
if result.kind == nkEmpty: if result.kind == nkEmpty:
# do not produce another redundant error message:
#raiseRecoverableError("")
result = errorNode(c, n)
if result.typ != nil:
# XXX tyGenericInst here?
semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result)
else:
LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags)
if result.kind == nkEmpty:
# do not produce another redundant error message: # do not produce another redundant error message:
result = errorNode(c, n) result = errorNode(c, n)
if result.typ == nil: if result.typ == nil:
LocalError(n.info, errExprXHasNoType, LocalError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments})) renderTree(result, {renderNoComments}))
result.typ = errorType(c) result.typ = errorType(c)
else:
semProcvarCheck(c, result)
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
@ -50,15 +80,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.ast) result = copyTree(s.ast)
result.typ = s.typ result.typ = s.typ
result.info = n.info result.info = n.info
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
# XXX this not correct; it's valid to pass to templates and macros.
# We really need another post nkCallConv check for this. Or maybe do it
# in transform().
var smoduleId = getModule(s).id
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
smoduleId != c.module.id and smoduleId != c.friendModule.id:
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
case s.kind case s.kind
@ -468,7 +489,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
result = n result = n
case n.kind case n.kind
of nkSym: of nkSym:
# n.sym.typ can be nil in 'check' mode ... # n.sym.typ can be nil in 'check' mode ...
if n.sym.typ != nil and if n.sym.typ != nil and
skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
@ -512,6 +533,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
LocalError(n.sons[i].info, errVarForOutParamNeeded) LocalError(n.sons[i].info, errVarForOutParamNeeded)
return return
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
semProcvarCheck(c, n.sons[i])
if i < sonsLen(t) and if i < sonsLen(t) and
skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
if n.sons[i].kind != nkHiddenAddr: if n.sons[i].kind != nkHiddenAddr:
@ -1728,7 +1750,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
semCaptureSym(s, c.p.owner) semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags) result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skIterator, skConverter}: if s.kind in {skProc, skMethod, skIterator, skConverter}:
performProcvarCheck(c, n, s) #performProcvarCheck(c, n, s)
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
if result.kind == nkSym: if result.kind == nkSym:
markIndirect(c, result.sym) markIndirect(c, result.sym)

View file

@ -14,9 +14,7 @@ import
# Second semantic checking pass over the AST. Necessary because the old # Second semantic checking pass over the AST. Necessary because the old
# way had some inherent problems. Performs: # way had some inherent problems. Performs:
# #
# * procvar checks
# * effect+exception tracking # * effect+exception tracking
# * closure analysis
# * checks for invalid usages of compiletime magics (not implemented) # * checks for invalid usages of compiletime magics (not implemented)
# * checks for invalid usages of PNimNode (not implemented) # * checks for invalid usages of PNimNode (not implemented)
# * later: will do an escape analysis for closures at least # * later: will do an escape analysis for closures at least

View file

@ -177,12 +177,12 @@ proc NotFoundError*(c: PContext, n: PNode) =
add(result, renderTree(n.sons[i].sons[0])) add(result, renderTree(n.sons[i].sons[0]))
add(result, ": ") add(result, ": ")
if nt.isNil: if nt.isNil:
n.sons[i].sons[1] = c.semExprWithType(c, n.sons[i].sons[1]) n.sons[i].sons[1] = c.semOperand(c, n.sons[i].sons[1])
nt = n.sons[i].sons[1].typ nt = n.sons[i].sons[1].typ
n.sons[i].typ = nt n.sons[i].typ = nt
else: else:
if nt.isNil: if nt.isNil:
n.sons[i] = c.semExprWithType(c, n.sons[i]) n.sons[i] = c.semOperand(c, n.sons[i])
nt = n.sons[i].typ nt = n.sons[i].typ
if nt.kind == tyError: return if nt.kind == tyError: return
add(result, typeToString(nt)) add(result, typeToString(nt))
@ -812,13 +812,13 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
# a.typ == nil is valid # a.typ == nil is valid
result = a result = a
elif a.typ.isNil: elif a.typ.isNil:
result = c.semExprWithType(c, a, {efDetermineType}) result = c.semOperand(c, a, {efDetermineType})
else: else:
result = a result = a
proc prepareOperand(c: PContext; a: PNode): PNode = proc prepareOperand(c: PContext; a: PNode): PNode =
if a.typ.isNil: if a.typ.isNil:
result = c.semExprWithType(c, a, {efDetermineType}) result = c.semOperand(c, a, {efDetermineType})
else: else:
result = a result = a

View file

@ -3,3 +3,5 @@ type
line*: int line*: int
filename*: string filename*: string
buffer: cstring buffer: cstring
proc noProcVar*(): int = 18

View file

@ -13,6 +13,7 @@ version 0.9.2
- acyclic vs prunable; introduce GC hints - acyclic vs prunable; introduce GC hints
- CGEN: ``restrict`` pragma + backend support; computed goto support - CGEN: ``restrict`` pragma + backend support; computed goto support
- document NimMain and check whether it works for threading - document NimMain and check whether it works for threading
- a project wide override option for 'dynlib'
Bugs Bugs