summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim5
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/cgmeth.nim2
-rw-r--r--compiler/evalffi.nim2
-rw-r--r--compiler/lambdalifting.nim5
-rw-r--r--compiler/pragmas.nim10
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/sigmatch.nim2
-rw-r--r--compiler/transf.nim2
-rw-r--r--compiler/types.nim2
-rw-r--r--compiler/vmops.nim18
-rw-r--r--tests/closure/tinvalidclosure.nim2
-rw-r--r--tests/closure/tinvalidclosure4.nim9
-rw-r--r--tests/closure/tinvalidclosure5.nim10
-rw-r--r--tests/closure/tnested.nim17
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()
+