summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJuan M Gómez <info@jmgomez.me>2023-10-08 22:51:44 +0100
committerGitHub <noreply@github.com>2023-10-08 23:51:44 +0200
commit8ac466980f7658c37b05c6ec099537ea0e459cb9 (patch)
tree9d1aaa8382b3f635bec29dc668ec43b4cae13972
parentc3774c8821cc25187252491b4514235b9a8f1aac (diff)
downloadNim-8ac466980f7658c37b05c6ec099537ea0e459cb9.tar.gz
marking a field with noInit allows to skip constructor initialiser (#22802)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
-rw-r--r--changelog.md2
-rw-r--r--compiler/ccgtypes.nim3
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--doc/manual_experimental.md50
-rw-r--r--tests/cpp/tnoinitfield.nim30
5 files changed, 85 insertions, 4 deletions
diff --git a/changelog.md b/changelog.md
index 5656a86c3..72d0a2a2d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -28,7 +28,7 @@ slots when enlarging a sequence.
 
 ## Language changes
 
-
+- `noInit` can be used in types and fields to disable member initializers in the C++ backend. 
 
 ## Compiler changes
 
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 1aed8442b..a5555048f 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -735,7 +735,8 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
       else:
         # don't use fieldType here because we need the
         # tyGenericInst for C++ template support
-        if fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ):
+        let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
+        if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
           var initializer = genCppInitializer(m, nil, fieldType)
           result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
         else:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 5fb74406b..e6867aa5d 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -72,9 +72,9 @@ const
     wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
     wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage, wCodegenDecl,
-    wSendable}
+    wSendable, wNoInit}
   fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
-    wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these?
+    wRequiresInit, wNoalias, wAlign, wNoInit} - {wExportNims, wNodecl} # why exclude these?
   varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
     wMagic, wHeader, wCompilerProc, wCore, wDynlib,
     wNoInit, wCompileTime, wGlobal,
diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md
index 41d463ff8..249f9367b 100644
--- a/doc/manual_experimental.md
+++ b/doc/manual_experimental.md
@@ -2408,6 +2408,56 @@ proc makeCppStruct(a: cint = 5, b:cstring = "hello"): CppStruct {.importcpp: "Cp
 # If one removes a default value from the constructor and passes it to the call explicitly, the C++ compiler will complain.
 
 ```
+Skip initializers in fields members
+===================================
+
+By using `noInit` in a type or field declaration, the compiler will skip the initializer. By doing so one can explicitly initialize those values in the constructor of the type owner.
+
+For example:
+
+```nim
+
+{.emit: """/*TYPESECTION*/
+  struct Foo {
+    Foo(int a){};
+  };
+  struct Boo {
+    Boo(int a){};
+  };
+
+  """.}
+
+type 
+  Foo {.importcpp.} = object
+  Boo {.importcpp, noInit.} = object
+  Test {.exportc.} = object
+    foo {.noInit.}: Foo
+    boo: Boo
+
+proc makeTest(): Test {.constructor: "Test() : foo(10), boo(1)".} = 
+  discard
+
+proc main() = 
+  var t = makeTest()
+
+main()
+
+```
+
+Will produce: 
+
+```c++
+
+struct Test {
+	Foo foo; 
+	Boo boo;
+  N_LIB_PRIVATE N_NOCONV(, Test)(void);
+};
+
+```
+
+Notice that without `noInit` it would produce `Foo foo {}` and `Boo boo {}`
+
 
 Member pragma
 =============
diff --git a/tests/cpp/tnoinitfield.nim b/tests/cpp/tnoinitfield.nim
new file mode 100644
index 000000000..4deffece8
--- /dev/null
+++ b/tests/cpp/tnoinitfield.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: '''
+'''
+"""
+{.emit: """/*TYPESECTION*/
+  struct Foo {
+    Foo(int a){};
+  };
+  struct Boo {
+    Boo(int a){};
+  };
+
+  """.}
+
+type 
+  Foo {.importcpp.} = object
+  Boo {.importcpp, noInit.} = object
+  Test {.exportc.} = object
+    foo {.noInit.}: Foo
+    boo: Boo
+
+proc makeTest(): Test {.constructor: "Test() : foo(10), boo(1)".} = 
+  discard
+
+proc main() = 
+  var t = makeTest()
+
+main()
\ No newline at end of file