From 3051c52f517be70b4efb8d5823a3f4cb5cb7cd5e Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 25 Mar 2013 01:44:52 +0100 Subject: fixes a long-standing bug about procvar checking --- compiler/ast.nim | 2 +- compiler/sem.nim | 2 +- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 48 +++++++++++++++++++++++++++++++++++------------- compiler/sempass2.nim | 2 -- compiler/sigmatch.nim | 8 ++++---- tests/reject/mopaque.nim | 2 ++ todo.txt | 1 + 8 files changed, 45 insertions(+), 22 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index b59c93950..8816d461a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -764,7 +764,7 @@ const dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5! nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, - nkCommand, nkCallStrLit} + nkCommand, nkCallStrLit, nkHiddenCallConv} nkLambdaKinds* = {nkLambda, nkDo} nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} diff --git a/compiler/sem.nim b/compiler/sem.nim index f20ab9a05..60ece4b30 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -201,7 +201,7 @@ proc myOpen(module: PSym): PPassContext = if c.p != nil: InternalError(module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr - c.semExprWithType = semExprWithType + c.semOperand = semOperand c.semConstBoolExpr = semConstBoolExpr c.semOverloadedCall = semOverloadedCall c.semTypeNode = semTypeNode diff --git a/compiler/semdata.nim b/compiler/semdata.nim index dd5f76172..ce91fb8af 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -69,7 +69,7 @@ type libs*: TLinkedList # all libs used by this module semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas 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 semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, filter: TSymKinds): PNode {.nimcall.} diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7d5fdc4f2..7bd732161 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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 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) if result.kind == nkEmpty: # do not produce another redundant error message: @@ -33,15 +46,32 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = renderTree(result, {renderNoComments})) 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) 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: result = errorNode(c, n) if result.typ == nil: LocalError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) + else: + semProcvarCheck(c, result) proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s, scClosed) @@ -50,15 +80,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.ast) result.typ = s.typ 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 = case s.kind @@ -468,7 +489,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n case n.kind - of nkSym: + of nkSym: # n.sym.typ can be nil in 'check' mode ... if n.sym.typ != nil and skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: @@ -512,6 +533,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = LocalError(n.sons[i].info, errVarForOutParamNeeded) return for i in countup(1, sonsLen(n) - 1): + semProcvarCheck(c, n.sons[i]) if i < sonsLen(t) and skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: if n.sons[i].kind != nkHiddenAddr: @@ -1728,7 +1750,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = semCaptureSym(s, c.p.owner) result = semSym(c, n, s, flags) if s.kind in {skProc, skMethod, skIterator, skConverter}: - performProcvarCheck(c, n, s) + #performProcvarCheck(c, n, s) result = symChoice(c, n, s, scClosed) if result.kind == nkSym: markIndirect(c, result.sym) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b2fd0fb04..f43820fa7 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -14,9 +14,7 @@ import # Second semantic checking pass over the AST. Necessary because the old # way had some inherent problems. Performs: # -# * procvar checks # * effect+exception tracking -# * closure analysis # * checks for invalid usages of compiletime magics (not implemented) # * checks for invalid usages of PNimNode (not implemented) # * later: will do an escape analysis for closures at least diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 882f582cb..f479267a0 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -177,12 +177,12 @@ proc NotFoundError*(c: PContext, n: PNode) = add(result, renderTree(n.sons[i].sons[0])) add(result, ": ") 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 n.sons[i].typ = nt else: 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 if nt.kind == tyError: return add(result, typeToString(nt)) @@ -812,13 +812,13 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode = # a.typ == nil is valid result = a elif a.typ.isNil: - result = c.semExprWithType(c, a, {efDetermineType}) + result = c.semOperand(c, a, {efDetermineType}) else: result = a proc prepareOperand(c: PContext; a: PNode): PNode = if a.typ.isNil: - result = c.semExprWithType(c, a, {efDetermineType}) + result = c.semOperand(c, a, {efDetermineType}) else: result = a diff --git a/tests/reject/mopaque.nim b/tests/reject/mopaque.nim index b7c5180fd..7eee4bd96 100644 --- a/tests/reject/mopaque.nim +++ b/tests/reject/mopaque.nim @@ -3,3 +3,5 @@ type line*: int filename*: string buffer: cstring + +proc noProcVar*(): int = 18 diff --git a/todo.txt b/todo.txt index de9210314..af126381b 100644 --- a/todo.txt +++ b/todo.txt @@ -13,6 +13,7 @@ version 0.9.2 - acyclic vs prunable; introduce GC hints - CGEN: ``restrict`` pragma + backend support; computed goto support - document NimMain and check whether it works for threading +- a project wide override option for 'dynlib' Bugs -- cgit 1.4.1-2-gfad0 '>178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228