diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-08-11 14:50:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-11 14:50:46 +0200 |
commit | 813f16a2a39f1375b241cf50845f641ea44d890e (patch) | |
tree | a5c45d5ead15167ded8d9d9dcef87dbf52013a38 | |
parent | 963db9e7dac39f4238f013addfae36439318b67f (diff) | |
parent | b022576ce96f5c166c7f5684bef9de682704cb1b (diff) | |
download | Nim-813f16a2a39f1375b241cf50845f641ea44d890e.tar.gz |
Fix #8473 (#15169)
* Make explicit {.nimcall.} a seperate calling convention * Add testcase for #5688 * Fix bootstrapping * Remove little lies :) * Use typeflag instead
-rw-r--r-- | compiler/ast.nim | 5 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 2 | ||||
-rw-r--r-- | compiler/cgmeth.nim | 2 | ||||
-rw-r--r-- | compiler/evalffi.nim | 2 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 5 | ||||
-rw-r--r-- | compiler/pragmas.nim | 10 | ||||
-rw-r--r-- | compiler/semdata.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 2 | ||||
-rw-r--r-- | compiler/transf.nim | 2 | ||||
-rw-r--r-- | compiler/types.nim | 2 | ||||
-rw-r--r-- | compiler/vmops.nim | 18 | ||||
-rw-r--r-- | tests/closure/tinvalidclosure.nim | 2 | ||||
-rw-r--r-- | tests/closure/tinvalidclosure4.nim | 9 | ||||
-rw-r--r-- | tests/closure/tinvalidclosure5.nim | 10 | ||||
-rw-r--r-- | tests/closure/tnested.nim | 17 |
16 files changed, 67 insertions, 25 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 1e619e51b..62c1e3894 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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] diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 33231b1bc..a97d15d70 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index f1dc85818..fad6093ed 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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") diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index edf9db383..9b871a898 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -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 diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index f89451f51..0d471cf98 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -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: diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c1cd07583..c23ca52cb 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -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: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c9fe3a5e1..44ff90010 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -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) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5bd6c4cf2..b99ddcba3 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7d97944ce..786cca01f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 diff --git a/compiler/transf.nim b/compiler/transf.nim index 29344e7a1..3333acbf1 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -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) diff --git a/compiler/types.nim b/compiler/types.nim index 94fe8fd54..3545b0703 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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") diff --git a/compiler/vmops.nim b/compiler/vmops.nim index e49d1e38c..298a02bb6 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -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, diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim index b2d8bd28d..47f3f105f 100644 --- a/tests/closure/tinvalidclosure.nim +++ b/tests/closure/tinvalidclosure.nim @@ -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 """ diff --git a/tests/closure/tinvalidclosure4.nim b/tests/closure/tinvalidclosure4.nim new file mode 100644 index 000000000..7985a2488 --- /dev/null +++ b/tests/closure/tinvalidclosure4.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "illegal capture 'v'" + line: 7 +""" + +proc outer(v: int) = + proc b {.nimcall.} = echo v + b() +outer(5) diff --git a/tests/closure/tinvalidclosure5.nim b/tests/closure/tinvalidclosure5.nim new file mode 100644 index 000000000..d03d93867 --- /dev/null +++ b/tests/closure/tinvalidclosure5.nim @@ -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 + diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim index dbbe9ba58..7a1881a60 100644 --- a/tests/closure/tnested.nim +++ b/tests/closure/tnested.nim @@ -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() + |