From 558bbb7426b21156b6ad5f8834a62cdf067a2ac3 Mon Sep 17 00:00:00 2001 From: HexSegfaultCat <167362716+HexSegfaultCat@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:57:06 +0200 Subject: [PATCH] Fix duplicated member declarations in structs for C++ backend (#23512) When forward declaration is used with pragmas `virtual` or `member`, the declaration in struct is added twice. It happens because of missing check for `sfWasForwarded` pragma. Current compiler generates the following C++ code: ```cpp struct tyObject_Foo__fFO9b6HU7kRnKB9aJA1RApKw { N_LIB_PRIVATE N_NOCONV(void, abc)(NI x_p1); N_LIB_PRIVATE N_NOCONV(virtual void, def)(NI y_p1); N_LIB_PRIVATE N_NOCONV(void, abc)(NI x_p1); N_LIB_PRIVATE N_NOCONV(virtual void, def)(NI y_p1); }; ``` --- compiler/semstmts.nim | 2 +- tests/cpp/tmember_forward_declaration.nim | 27 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/cpp/tmember_forward_declaration.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f71fc9fa0d..7ccc29d7e5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2402,7 +2402,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfBorrow in s.flags and c.config.cmd notin cmdDocLike: result[bodyPos] = c.graph.emptyNode - if sfCppMember * s.flags != {}: + if sfCppMember * s.flags != {} and sfWasForwarded notin s.flags: semCppMember(c, s, n) if n[bodyPos].kind != nkEmpty and sfError notin s.flags: diff --git a/tests/cpp/tmember_forward_declaration.nim b/tests/cpp/tmember_forward_declaration.nim new file mode 100644 index 0000000000..2f4a79daa3 --- /dev/null +++ b/tests/cpp/tmember_forward_declaration.nim @@ -0,0 +1,27 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +abc called +def called +abc called +''' +""" + +type Foo = object + +proc abc(this: Foo, x: int): void {.member: "$1('2 #2)".} +proc def(this: Foo, y: int): void {.virtual: "$1('2 #2)".} + +proc abc(this: Foo, x: int): void = + echo "abc called" + if x > 0: + this.def(x - 1) + +proc def(this: Foo, y: int): void = + echo "def called" + this.abc(y) + +var x = Foo() +x.abc(1) +