Make explicit {.nimcall.} a seperate calling convention
This commit is contained in:
parent
ef6358f0b0
commit
38068f9778
12 changed files with 29 additions and 17 deletions
|
|
@ -17,7 +17,8 @@ export int128
|
||||||
|
|
||||||
type
|
type
|
||||||
TCallingConvention* = enum
|
TCallingConvention* = enum
|
||||||
ccDefault, # proc has no explicit calling convention
|
ccImplicit, # proc has no explicit calling convention
|
||||||
|
ccNimCall, # proc was explicitly marked as nimcall
|
||||||
ccStdCall, # procedure is stdcall
|
ccStdCall, # procedure is stdcall
|
||||||
ccCDecl, # cdecl
|
ccCDecl, # cdecl
|
||||||
ccSafeCall, # safecall
|
ccSafeCall, # safecall
|
||||||
|
|
@ -30,10 +31,12 @@ type
|
||||||
ccNoConvention # needed for generating proper C procs sometimes
|
ccNoConvention # needed for generating proper C procs sometimes
|
||||||
|
|
||||||
const
|
const
|
||||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
ccDefault* = {ccImplicit, ccNimCall}
|
||||||
|
CallingConvToStr*: array[TCallingConvention, string] = ["", "nimcall", "stdcall",
|
||||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall",
|
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "thiscall",
|
||||||
"closure", "noconv"]
|
"closure", "noconv"]
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TNodeKind* = enum # order is extremely important, because ranges are used
|
TNodeKind* = enum # order is extremely important, because ranges are used
|
||||||
# to check whether a node belongs to a certain class
|
# to check whether a node belongs to a certain class
|
||||||
|
|
|
||||||
|
|
@ -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
|
# 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
|
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
|
||||||
# convention at least:
|
# convention at least:
|
||||||
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccDefault:
|
if bt.destructor.typ == nil or bt.destructor.typ.callConv notin ccDefault:
|
||||||
localError(p.module.config, a.lode.info,
|
localError(p.module.config, a.lode.info,
|
||||||
"the destructor that is turned into a finalizer needs " &
|
"the destructor that is turned into a finalizer needs " &
|
||||||
"to have the 'nimcall' calling convention")
|
"to have the 'nimcall' calling convention")
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
const
|
const
|
||||||
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
|
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", "N_NIMCALL",
|
||||||
"N_STDCALL", "N_CDECL", "N_SAFECALL",
|
"N_STDCALL", "N_CDECL", "N_SAFECALL",
|
||||||
"N_SYSCALL", # this is probably not correct for all platforms,
|
"N_SYSCALL", # this is probably not correct for all platforms,
|
||||||
# but one can #define it to what one wants
|
# but one can #define it to what one wants
|
||||||
|
|
@ -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
|
# 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
|
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
|
||||||
# convention at least:
|
# convention at least:
|
||||||
if theProc.typ == nil or theProc.typ.callConv != ccDefault:
|
if theProc.typ == nil or theProc.typ.callConv notin ccDefault:
|
||||||
localError(m.config, info,
|
localError(m.config, info,
|
||||||
theProc.name.s & " needs to have the 'nimcall' calling convention")
|
theProc.name.s & " needs to have the 'nimcall' calling convention")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ proc createDispatcher(s: PSym): PSym =
|
||||||
excl(disp.flags, sfExported)
|
excl(disp.flags, sfExported)
|
||||||
disp.typ = copyType(disp.typ, disp.typ.owner, false)
|
disp.typ = copyType(disp.typ, disp.typ.owner, false)
|
||||||
# we can't inline the dispatcher itself (for now):
|
# 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 = copyTree(s.ast)
|
||||||
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
|
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
|
||||||
disp.loc.r = nil
|
disp.loc.r = nil
|
||||||
|
|
|
||||||
|
|
@ -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" &
|
("'$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") %
|
" safety, declared here: $3; using '-d:nimWorkaround14447' helps in some cases") %
|
||||||
[s.name.s, typeToString(s.typ), g.config$s.info])
|
[s.name.s, typeToString(s.typ), g.config$s.info])
|
||||||
elif owner.typ.callConv notin {ccClosure, ccDefault}:
|
elif owner.typ.callConv notin {ccClosure, ccImplicit}:
|
||||||
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
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]])
|
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
|
||||||
incl(owner.typ.flags, tfCapturesEnv)
|
incl(owner.typ.flags, tfCapturesEnv)
|
||||||
|
|
@ -822,7 +822,7 @@ proc semCaptureSym*(s, owner: PSym) =
|
||||||
var o = owner.skipGenericOwner
|
var o = owner.skipGenericOwner
|
||||||
while o != nil and o.kind != skModule:
|
while o != nil and o.kind != skModule:
|
||||||
if s.owner == o:
|
if s.owner == o:
|
||||||
if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
|
if owner.typ.callConv in {ccClosure, ccImplicit} or owner.kind == skIterator:
|
||||||
owner.typ.callConv = ccClosure
|
owner.typ.callConv = ccClosure
|
||||||
propagateClosure(owner.skipGenericOwner, s.owner)
|
propagateClosure(owner.skipGenericOwner, s.owner)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
|
||||||
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
|
proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
|
||||||
# this assumes that the order of special words and calling conventions is
|
# this assumes that the order of special words and calling conventions is
|
||||||
# the same
|
# the same
|
||||||
result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
|
TCallingConvention(ord(ccNimCall) + ord(sw) - ord(wNimcall))
|
||||||
|
|
||||||
proc isTurnedOn(c: PContext, n: PNode): bool =
|
proc isTurnedOn(c: PContext, n: PNode): bool =
|
||||||
if n.kind in nkPragmaCallKinds and n.len == 2:
|
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
|
# a calling convention that doesn't introduce custom name mangling
|
||||||
# cdecl is the default - the user can override this explicitly
|
# cdecl is the default - the user can override this explicitly
|
||||||
if sym.kind in routineKinds and sym.typ != nil and
|
if sym.kind in routineKinds and sym.typ != nil and
|
||||||
sym.typ.callConv == ccDefault:
|
sym.typ.callConv == ccImplicit:
|
||||||
sym.typ.callConv = ccCDecl
|
sym.typ.callConv = ccCDecl
|
||||||
|
|
||||||
proc processNote(c: PContext, n: PNode) =
|
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)
|
incl(sym.flags, sfProcvar)
|
||||||
if sym.typ != nil:
|
if sym.typ != nil:
|
||||||
incl(sym.typ.flags, tfThread)
|
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:
|
of wGcSafe:
|
||||||
noVal(c, it)
|
noVal(c, it)
|
||||||
if sym != nil:
|
if sym != nil:
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ proc considerGenSyms*(c: PContext; n: PNode) =
|
||||||
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
|
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
|
||||||
new(result)
|
new(result)
|
||||||
result.options = conf.options
|
result.options = conf.options
|
||||||
result.defaultCC = ccDefault
|
result.defaultCC = ccImplicit
|
||||||
result.dynlib = nil
|
result.dynlib = nil
|
||||||
result.notes = conf.notes
|
result.notes = conf.notes
|
||||||
result.warningAsErrors = conf.warningAsErrors
|
result.warningAsErrors = conf.warningAsErrors
|
||||||
|
|
|
||||||
|
|
@ -639,11 +639,11 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
elif f.callConv != a.callConv:
|
elif f.callConv != a.callConv:
|
||||||
# valid to pass a 'nimcall' thingie to 'closure':
|
# valid to pass a 'nimcall' thingie to 'closure':
|
||||||
if f.callConv == ccClosure and a.callConv == ccDefault:
|
if f.callConv == ccClosure and a.callConv in ccDefault:
|
||||||
result = if result == isInferred: isInferredConvertible
|
result = if result == isInferred: isInferredConvertible
|
||||||
elif result == isBothMetaConvertible: isBothMetaConvertible
|
elif result == isBothMetaConvertible: isBothMetaConvertible
|
||||||
else: isConvertible
|
else: isConvertible
|
||||||
else:
|
elif not(f.callConv in ccDefault and a.callConv in ccDefault):
|
||||||
return isNone
|
return isNone
|
||||||
when useEffectSystem:
|
when useEffectSystem:
|
||||||
if compatibleEffects(f, a) != efCompat: return isNone
|
if compatibleEffects(f, a) != efCompat: return isNone
|
||||||
|
|
|
||||||
|
|
@ -539,7 +539,7 @@ proc transformConv(c: PTransf, n: PNode): PNode =
|
||||||
# happens sometimes for generated assignments, etc.
|
# happens sometimes for generated assignments, etc.
|
||||||
of tyProc:
|
of tyProc:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
if dest.callConv == ccClosure and source.callConv == ccDefault:
|
if dest.callConv == ccClosure and source.callConv in ccDefault:
|
||||||
result = generateThunk(c, result[1], dest)
|
result = generateThunk(c, result[1], dest)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
|
|
||||||
|
|
@ -679,7 +679,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
if i < t.len - 1: result.add(", ")
|
if i < t.len - 1: result.add(", ")
|
||||||
result.add(')')
|
result.add(')')
|
||||||
if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
|
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 == ccImplicit: "" else: CallingConvToStr[t.callConv]
|
||||||
if tfNoSideEffect in t.flags:
|
if tfNoSideEffect in t.flags:
|
||||||
addSep(prag)
|
addSep(prag)
|
||||||
prag.add("noSideEffect")
|
prag.add("noSideEffect")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "type mismatch: got <proc (x: int){.gcsafe, locks: 0.}>"
|
errormsg: "type mismatch: got <proc (x: int){.nimcall, gcsafe, locks: 0.}>"
|
||||||
line: 12
|
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)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue