mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-01 19:02:18 +00:00
* Make explicit {.nimcall.} a seperate calling convention
* Add testcase for #5688
* Fix bootstrapping
* Remove little lies :)
* Use typeflag instead
This commit is contained in:
@@ -17,7 +17,7 @@ export int128
|
||||
|
||||
type
|
||||
TCallingConvention* = enum
|
||||
ccDefault, # proc has no explicit calling convention
|
||||
ccNimCall, # nimcall, also the default
|
||||
ccStdCall, # procedure is stdcall
|
||||
ccCDecl, # cdecl
|
||||
ccSafeCall, # safecall
|
||||
@@ -30,7 +30,7 @@ type
|
||||
ccNoConvention # needed for generating proper C procs sometimes
|
||||
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["nimcall", "stdcall",
|
||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall",
|
||||
"closure", "noconv"]
|
||||
|
||||
@@ -560,6 +560,7 @@ type
|
||||
tfCompleteStruct
|
||||
# (for importc types); type is fully specified, allowing to compute
|
||||
# sizeof, alignof, offsetof at CT
|
||||
tfExplicitCallConv
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
|
||||
@@ -1240,7 +1240,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
|
||||
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
|
||||
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
|
||||
# convention at least:
|
||||
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccDefault:
|
||||
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccNimCall:
|
||||
localError(p.module.config, a.lode.info,
|
||||
"the destructor that is turned into a finalizer needs " &
|
||||
"to have the 'nimcall' calling convention")
|
||||
|
||||
@@ -1297,7 +1297,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
|
||||
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
|
||||
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
|
||||
# convention at least:
|
||||
if theProc.typ == nil or theProc.typ.callConv != ccDefault:
|
||||
if theProc.typ == nil or theProc.typ.callConv != ccNimCall:
|
||||
localError(m.config, info,
|
||||
theProc.name.s & " needs to have the 'nimcall' calling convention")
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ proc createDispatcher(s: PSym): PSym =
|
||||
excl(disp.flags, sfExported)
|
||||
disp.typ = copyType(disp.typ, disp.typ.owner, false)
|
||||
# we can't inline the dispatcher itself (for now):
|
||||
if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
|
||||
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
|
||||
disp.ast = copyTree(s.ast)
|
||||
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
|
||||
disp.loc.r = nil
|
||||
|
||||
@@ -104,7 +104,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
|
||||
|
||||
proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI =
|
||||
case cc
|
||||
of ccDefault: result = DEFAULT_ABI
|
||||
of ccNimCall: result = DEFAULT_ABI
|
||||
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
|
||||
of ccCDecl: result = DEFAULT_ABI
|
||||
else:
|
||||
|
||||
@@ -293,7 +293,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
|
||||
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
|
||||
" safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") %
|
||||
[s.name.s, typeToString(s.typ), g.config$s.info])
|
||||
elif owner.typ.callConv notin {ccClosure, ccDefault}:
|
||||
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
|
||||
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
|
||||
incl(owner.typ.flags, tfCapturesEnv)
|
||||
@@ -822,7 +822,8 @@ proc semCaptureSym*(s, owner: PSym) =
|
||||
var o = owner.skipGenericOwner
|
||||
while o != nil and o.kind != skModule:
|
||||
if s.owner == o:
|
||||
if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
|
||||
if owner.typ.callConv == ccClosure or owner.kind == skIterator or
|
||||
owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags:
|
||||
owner.typ.callConv = ccClosure
|
||||
propagateClosure(owner.skipGenericOwner, s.owner)
|
||||
else:
|
||||
|
||||
@@ -247,7 +247,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
|
||||
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
|
||||
# this assumes that the order of special words and calling conventions is
|
||||
# the same
|
||||
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
|
||||
TCallingConvention(ord(ccNimCall) + ord(sw) - ord(wNimcall))
|
||||
|
||||
proc isTurnedOn(c: PContext, n: PNode): bool =
|
||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
||||
@@ -326,7 +326,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||
# a calling convention that doesn't introduce custom name mangling
|
||||
# cdecl is the default - the user can override this explicitly
|
||||
if sym.kind in routineKinds and sym.typ != nil and
|
||||
sym.typ.callConv == ccDefault:
|
||||
tfExplicitCallConv notin sym.typ.flags:
|
||||
sym.typ.callConv = ccCDecl
|
||||
|
||||
proc processNote(c: PContext, n: PNode) =
|
||||
@@ -978,7 +978,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
incl(sym.flags, sfProcvar)
|
||||
if sym.typ != nil:
|
||||
incl(sym.typ.flags, tfThread)
|
||||
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault
|
||||
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
|
||||
of wGcSafe:
|
||||
noVal(c, it)
|
||||
if sym != nil:
|
||||
@@ -1061,7 +1061,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of FirstCallConv..LastCallConv:
|
||||
assert(sym != nil)
|
||||
if sym.typ == nil: invalidPragma(c, it)
|
||||
else: sym.typ.callConv = wordToCallConv(k)
|
||||
else:
|
||||
sym.typ.callConv = wordToCallConv(k)
|
||||
sym.typ.flags.incl tfExplicitCallConv
|
||||
of wEmit: pragmaEmit(c, it)
|
||||
of wUnroll: pragmaUnroll(c, it)
|
||||
of wLinearScanEnd, wComputedGoto: noVal(c, it)
|
||||
|
||||
@@ -212,7 +212,7 @@ proc considerGenSyms*(c: PContext; n: PNode) =
|
||||
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
|
||||
new(result)
|
||||
result.options = conf.options
|
||||
result.defaultCC = ccDefault
|
||||
result.defaultCC = ccNimCall
|
||||
result.dynlib = nil
|
||||
result.notes = conf.notes
|
||||
result.warningAsErrors = conf.warningAsErrors
|
||||
|
||||
@@ -639,7 +639,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
return isNone
|
||||
elif f.callConv != a.callConv:
|
||||
# valid to pass a 'nimcall' thingie to 'closure':
|
||||
if f.callConv == ccClosure and a.callConv == ccDefault:
|
||||
if f.callConv == ccClosure and a.callConv == ccNimCall:
|
||||
result = if result == isInferred: isInferredConvertible
|
||||
elif result == isBothMetaConvertible: isBothMetaConvertible
|
||||
else: isConvertible
|
||||
|
||||
@@ -539,7 +539,7 @@ proc transformConv(c: PTransf, n: PNode): PNode =
|
||||
# happens sometimes for generated assignments, etc.
|
||||
of tyProc:
|
||||
result = transformSons(c, n)
|
||||
if dest.callConv == ccClosure and source.callConv == ccDefault:
|
||||
if dest.callConv == ccClosure and source.callConv == ccNimCall:
|
||||
result = generateThunk(c, result[1], dest)
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
|
||||
@@ -679,7 +679,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if i < t.len - 1: result.add(", ")
|
||||
result.add(')')
|
||||
if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
|
||||
var prag = if t.callConv == ccDefault: "" else: CallingConvToStr[t.callConv]
|
||||
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: CallingConvToStr[t.callConv]
|
||||
if tfNoSideEffect in t.flags:
|
||||
addSep(prag)
|
||||
prag.add("noSideEffect")
|
||||
|
||||
@@ -85,12 +85,14 @@ template wrap2svoid(op, modop) {.dirty.} =
|
||||
modop op
|
||||
|
||||
template wrapDangerous(op, modop) {.dirty.} =
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck):
|
||||
if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck):
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
discard
|
||||
else:
|
||||
modop op
|
||||
else:
|
||||
proc `op Wrapper`(a: VmArgs) {.nimcall.} =
|
||||
op(getString(a, 0), getString(a, 1))
|
||||
modop op
|
||||
modop op
|
||||
|
||||
proc getCurrentExceptionMsgWrapper(a: VmArgs) {.nimcall.} =
|
||||
setResult(a, if a.currentException.isNil: ""
|
||||
@@ -186,9 +188,9 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
|
||||
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
|
||||
when defined(nimHasInvariant):
|
||||
registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) {.nimcall.} =
|
||||
registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) =
|
||||
setResult(a, querySettingImpl(c.config, getInt(a, 0)))
|
||||
registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) {.nimcall.} =
|
||||
registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) =
|
||||
setResult(a, querySettingSeqImpl(c.config, getInt(a, 0)))
|
||||
|
||||
if defined(nimsuggest) or c.config.cmd == cmdCheck:
|
||||
@@ -200,14 +202,14 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||
registerCallback c, "stdlib.os.getCurrentCompilerExe", proc (a: VmArgs) {.nimcall.} =
|
||||
setResult(a, getAppFilename())
|
||||
|
||||
registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) {.nimcall.} =
|
||||
registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) =
|
||||
let n = getNode(a, 0)
|
||||
if n.kind != nkSym:
|
||||
stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr,
|
||||
"symBodyHash() requires a symbol. '" & $n & "' is of kind '" & $n.kind & "'", n.info)
|
||||
setResult(a, $symBodyDigest(c.graph, n.sym))
|
||||
|
||||
registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) {.nimcall.} =
|
||||
registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) =
|
||||
let n = getNode(a, 0)
|
||||
if n.kind != nkSym:
|
||||
stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got <proc (x: int){.gcsafe, locks: 0.}>"
|
||||
errormsg: "type mismatch: got <proc (x: int){.nimcall, gcsafe, locks: 0.}>"
|
||||
line: 12
|
||||
"""
|
||||
|
||||
|
||||
9
tests/closure/tinvalidclosure4.nim
Normal file
9
tests/closure/tinvalidclosure4.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
discard """
|
||||
errormsg: "illegal capture 'v'"
|
||||
line: 7
|
||||
"""
|
||||
|
||||
proc outer(v: int) =
|
||||
proc b {.nimcall.} = echo v
|
||||
b()
|
||||
outer(5)
|
||||
10
tests/closure/tinvalidclosure5.nim
Normal file
10
tests/closure/tinvalidclosure5.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
discard """
|
||||
errormsg: "type mismatch: got <proc (){.closure, gcsafe, locks: 0.}> but expected 'A = proc (){.nimcall.}'"
|
||||
line: 9
|
||||
"""
|
||||
|
||||
type A = proc() {.nimcall.}
|
||||
proc main =
|
||||
let b = 1
|
||||
let a: A = proc() = echo b
|
||||
|
||||
@@ -33,6 +33,7 @@ py
|
||||
py
|
||||
px
|
||||
6
|
||||
proc (){.closure, gcsafe, locks: 0.}
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -177,3 +178,19 @@ block tclosure2:
|
||||
|
||||
|
||||
outer2()
|
||||
|
||||
# bug #5688
|
||||
|
||||
import typetraits
|
||||
|
||||
proc myDiscard[T](a: T) = discard
|
||||
|
||||
proc foo() =
|
||||
let a = 5
|
||||
let f = (proc() =
|
||||
myDiscard (proc() = echo a)
|
||||
)
|
||||
echo name(type(f))
|
||||
|
||||
foo()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user