From f10dda264c2cb3fc7e2574b25eeb64c1a8aca6ab Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 13 Feb 2026 14:29:01 +0200 Subject: [PATCH] Importc codegen fix (#25511) This fixes two issues with impotc'ed types. 1. Passing an importc'ed inherited object to where superclass is expected emitted `v.Sup` previously. Now it emits `v`, similar to cpp codegen. 2. Casting between different nim types that resolve to the same C type previously was done like `*(T*)&v`, now it is just `v`. (cherry picked from commit 937e647f4f843566dc8a31c3852dbf7dcb13698b) --- compiler/ccgexprs.nim | 8 ++++++-- tests/ccgbugs2/tcodegen.nim | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 274477fc8b..b3d95b67f3 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2853,7 +2853,11 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = raiseInstr(p, p.s(cpsStmts)) linefmt p, cpsStmts, "}$n", [] - if n[0].typ.kind != tyObject: + # skip cast when types map to the same C type + # this avoids invalid C code like `*(T*)&x` for types that can't have their address taken (e.g., WASM __externref_t) + if getTypeDesc(p.module, n.typ) == getTypeDesc(p.module, n[0].typ): + expr(p, n[0], d) + elif n[0].typ.kind != tyObject: if n.isLValue: putIntoDest(p, d, n, "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) @@ -2881,7 +2885,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc = initLocExpr(p, arg) putIntoDest(p, d, n, "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) - elif p.module.compileToCpp: + elif p.module.compileToCpp or isImportedType(src): # C++ implicitly downcasts for us expr(p, arg, d) else: diff --git a/tests/ccgbugs2/tcodegen.nim b/tests/ccgbugs2/tcodegen.nim index 37579e0bf4..bca361e813 100644 --- a/tests/ccgbugs2/tcodegen.nim +++ b/tests/ccgbugs2/tcodegen.nim @@ -56,3 +56,22 @@ proc main = # bug #24677 for NDEBUG in 0..2: doAssert NDEBUG == NDEBUG main() + +block: # importc type inheritance + type + A {.inheritable, pure, bycopy, importc: "int".} = object + B {.importc: "int", bycopy.} = object of A + + {.emit: """ + int foo(int a) { + return 123; + } + """.} + + proc foo(a: A): B {.importc, nodecl.} + + var a: A + var b = foo(a) + doAssert(cast[cint](b) == 123) + var c = foo(b) + doAssert(cast[cint](c) == 123)