diff options
author | Juan M Gómez <info@jmgomez.me> | 2023-10-08 22:51:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-08 23:51:44 +0200 |
commit | 8ac466980f7658c37b05c6ec099537ea0e459cb9 (patch) | |
tree | 9d1aaa8382b3f635bec29dc668ec43b4cae13972 | |
parent | c3774c8821cc25187252491b4514235b9a8f1aac (diff) | |
download | Nim-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.md | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 3 | ||||
-rw-r--r-- | compiler/pragmas.nim | 4 | ||||
-rw-r--r-- | doc/manual_experimental.md | 50 | ||||
-rw-r--r-- | tests/cpp/tnoinitfield.nim | 30 |
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 |