marking a field with noInit allows to skip constructor initialiser (#22802)

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
Juan M Gómez
2023-10-08 22:51:44 +01:00
committed by GitHub
parent c3774c8821
commit 8ac466980f
5 changed files with 85 additions and 4 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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,

View File

@@ -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
=============

View File

@@ -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()