summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJuan M Gómez <info@jmgomez.me>2023-07-23 15:42:20 +0100
committerGitHub <noreply@github.com>2023-07-23 16:42:20 +0200
commit49a108b3027914eec18fab4bc47d9b4846eb362e (patch)
tree3d72015c55c30ee56bcf8ef0b1390b2a29ba59dd
parent808c9c6c2a93e6076c17b6f9bbab367df4c27772 (diff)
downloadNim-49a108b3027914eec18fab4bc47d9b4846eb362e.tar.gz
Expands codegenDecl to work in function params. fixes #22306 (#22307)
* Expands codegenDecl to work in function params. fixes #22306

* makes the test more concrete so T{lit} params dont match

* adds sfCodegenDecl
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/ccgtypes.nim34
-rw-r--r--compiler/cgen.nim4
-rw-r--r--compiler/pragmas.nim3
-rw-r--r--compiler/semtypes.nim4
-rw-r--r--compiler/sigmatch.nim2
-rw-r--r--tests/cpp/tcodegendecl.nim17
7 files changed, 47 insertions, 18 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 0be260391..706c0d38f 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -314,6 +314,7 @@ type
                       # an infinite loop, this flag is used as a sentinel to stop it.
     sfVirtual         # proc is a C++ virtual function
     sfByCopy          # param is marked as pass bycopy
+    sfCodegenDecl     # type, proc, global or proc param is marked as codegenDecl
 
   TSymFlags* = set[TSymFlag]
 
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 307d1f2e0..e4a0fe84b 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -483,6 +483,9 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
         res.add(substr(frmt, start, i - 1))
     frmt = res
 
+template cgDeclFrmt*(s: PSym): string =
+  s.constraint.strVal
+
 proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string,
                    check: var IntSet, declareEnvironment=true;
                    weakDep=false;) =
@@ -535,7 +538,10 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
     name = param.loc.r
     types.add typ
     names.add name
-    args.add types[^1] & " " & names[^1]
+    if sfCodegenDecl notin param.flags:
+      args.add types[^1] & " " & names[^1]
+    else:
+      args.add runtimeFormat(param.cgDeclFrmt, [types[^1], names[^1]])
 
   multiFormat(params, @['\'', '#'], [types, names])
   multiFormat(superCall, @['\'', '#'], [types, names])
@@ -570,19 +576,24 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
     fillParamName(m, param)
     fillLoc(param.loc, locParam, t.n[i],
             param.paramStorageLoc)
+    var typ: Rope
     if ccgIntroducedPtr(m.config, param, t[0]) and descKind == dkParam:
-      params.add(getTypeDescWeak(m, param.typ, check, descKind))
-      params.add("*")
+      typ = (getTypeDescWeak(m, param.typ, check, descKind))
+      typ.add("*")
       incl(param.loc.flags, lfIndirect)
       param.loc.storage = OnUnknown
     elif weakDep:
-      params.add(getTypeDescWeak(m, param.typ, check, descKind))
+      typ = (getTypeDescWeak(m, param.typ, check, descKind))
     else:
-      params.add(getTypeDescAux(m, param.typ, check, descKind))
-    params.add(" ")
+      typ = (getTypeDescAux(m, param.typ, check, descKind))
+    typ.add(" ")
     if sfNoalias in param.flags:
-      params.add("NIM_NOALIAS ")
-    params.add(param.loc.r)
+      typ.add("NIM_NOALIAS ")
+    if sfCodegenDecl notin param.flags:
+      params.add(typ)
+      params.add(param.loc.r)
+    else:
+      params.add runtimeFormat(param.cgDeclFrmt, [typ, param.loc.r])
     # declare the len field for open arrays:
     var arr = param.typ.skipTypes({tyGenericInst})
     if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon
@@ -721,9 +732,6 @@ proc fillObjectFields*(m: BModule; typ: PType) =
   discard getRecordFields(m, typ, check)
 
 proc mangleDynLibProc(sym: PSym): Rope
-
-template cgDeclFrmt*(s: PSym): string =
-  s.constraint.strVal
   
 proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
                    check: var IntSet, hasField:var bool): Rope =                 
@@ -770,7 +778,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
   var baseType: string 
   if typ[0] != nil: 
     baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField)
-  if typ.sym == nil or typ.sym.constraint == nil:
+  if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
     result = structOrUnion & " " & name
     result.add(getRecordDescAux(m, typ, name, baseType, check, hasField))
     let desc = getRecordFields(m, typ, check)
@@ -1198,7 +1206,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false)
     name.add("_actual")
   # careful here! don't access ``prc.ast`` as that could reload large parts of
   # the object graph!
-  if prc.constraint.isNil:
+  if sfCodegenDecl notin prc.flags:
     if lfExportLib in prc.loc.flags:
       if isHeaderFile in m.flags:
         result.add "N_LIB_IMPORT "
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ed149ed0e..0242ae2f7 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -590,7 +590,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
   genCLineDir(result, p, n.info, p.config)
 
   result.add getTypeDesc(p.module, s.typ, dkVar)
-  if s.constraint.isNil:
+  if sfCodegenDecl notin s.flags:
     if sfRegister in s.flags: result.add(" register")
     #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
     #  decl.add(" GC_GUARD")
@@ -621,7 +621,7 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
 
 proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
   let s = n.sym
-  if s.constraint.isNil:
+  if sfCodegenDecl notin s.flags:
     if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
       decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
     if p.hcrOn: decl.add("static ")
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 0d95f596c..258836ca3 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -84,7 +84,7 @@ const
     wGensym, wInject,
     wIntDefine, wStrDefine, wBoolDefine, wDefine,
     wCompilerProc, wCore}
-  paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy}
+  paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl}
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
                       wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe,
@@ -253,6 +253,7 @@ proc processVirtual(c: PContext, n: PNode, s: PSym) =
 
 proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
   sym.constraint = getStrLitNode(c, n)
+  sym.flags.incl sfCodegenDecl
 
 proc processMagic(c: PContext, n: PNode, s: PSym) =
   #if sfSystemModule notin c.module.flags:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index aa5f0a79b..60550de57 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1356,7 +1356,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       let finalType = if lifted != nil: lifted else: typ.skipIntLit(c.idgen)
       arg.typ = finalType
       arg.position = counter
-      arg.constraint = constraint
+      if constraint != nil: 
+        #only replace the constraint when it has been set as arg could contain codegenDecl
+        arg.constraint = constraint
       inc(counter)
       if def != nil and def.kind != nkEmpty:
         arg.ast = copyTree(def)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index e90f1524b..4aa51977a 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -2432,7 +2432,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
     return
 
   template checkConstraint(n: untyped) {.dirty.} =
-    if not formal.constraint.isNil:
+    if not formal.constraint.isNil and sfCodegenDecl notin formal.flags:
       if matchNodeKinds(formal.constraint, n):
         # better match over other routines with no such restriction:
         inc(m.genericMatches, 100)
diff --git a/tests/cpp/tcodegendecl.nim b/tests/cpp/tcodegendecl.nim
new file mode 100644
index 000000000..e128c5eb7
--- /dev/null
+++ b/tests/cpp/tcodegendecl.nim
@@ -0,0 +1,17 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: "3"
+"""
+
+{.emit:"""/*TYPESECTION*/
+  int operate(int x, int y, int (*func)(const int&, const int&)){
+    return func(x, y);
+  };
+""".}
+
+proc operate(x, y: int32, fn: proc(x, y: int32 ): int32 {.cdecl.}): int32 {.importcpp:"$1(@)".}
+
+proc add(a {.codegenDecl:"const $#& $#".}, b {.codegenDecl:"const $# $#", byref.}: int32): int32  {.cdecl.} = a + b
+
+echo operate(1, 2, add)
\ No newline at end of file