diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 91f87b5992..cd2e325dee 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -2283,3 +2283,21 @@ proc genTypeSection(m: BModule, n: PNode) = discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.kind)) if m.g.generatedHeader != nil: discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.kind)) + +# Unlike genCppInitializer which returns just the braced value list (e.g. "{a, b}"), +# genCppConstructorExpr returns a full type-prefixed expression (e.g. "Foo(a, b)"). +# This is used when a standalone construction expression is needed — e.g. on the +# right-hand side of an assignment — whereas genCppInitializer is used in variable +# declarations where the type is already written separately before the initializer. +proc genCppConstructorExpr(m: BModule, prc: BProc; typ: PType; didGenTemp: var bool): Snippet = + var params = "" + if typ.itemId in m.g.graph.initializersPerType: + let call = m.g.graph.initializersPerType[typ.itemId] + if call != nil: + var p = prc + if p == nil: + p = BProc(module: m) + params = genCppParamsForCtor(p, call, didGenTemp) + if prc == nil: + assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks" + result = getTypeDesc(m, typ, dkVar) & "(" & params & ")" diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b54160edf8..b1f6f862c7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -613,7 +613,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = if isImportedCppType(typ): var didGenTemp = false let rl = rdLoc(loc) - let init = genCppInitializer(p.module, p, typ, didGenTemp) + let init = genCppConstructorExpr(p.module, p, typ, didGenTemp) p.s(cpsStmts).addAssignment(rl, init) return if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}: diff --git a/compiler/sem.nim b/compiler/sem.nim index a9f87cd006..7f777a7add 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -89,6 +89,18 @@ proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode = changeType(c, x, formal, check=true) result = arg result = skipHiddenSubConv(result, c.graph, c.idgen) + # Walk through nested statement-list/block expressions to find the innermost + # value node. Empty containers (e.g. `@[]`) inside `nkStmtListExpr` wrappers + # need their type resolved to match the formal type, otherwise the C codegen + # cannot map `tyEmpty` to a concrete type (fixes #25945). + var tail = result + while tail.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkPragmaBlock} and tail.len > 0: + tail = tail.lastSon + + if tail.typ != nil and tail.typ.isEmptyContainer and + formal.kind notin {tyUntyped, tyBuiltInTypeClass, tyAnything}: + changeType(c, tail, formal, check=true) + # mark inserted converter as used: var a = result if a.kind == nkHiddenDeref: a = a[0] diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 008f2317ba..73e3b4072a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -93,6 +93,7 @@ type graph: ModuleGraph c: PContext escapingParams: IntSet + inNimvmBranch: int PEffects = var TEffects const @@ -1127,7 +1128,7 @@ proc trackCall(tracked: PEffects; n: PNode) = # sfCompileTime` path in `semProcAux`. if a.kind == nkSym and a.sym.magic in {mNLen..mNError, mSlurp..mQuoteAst} and tracked.owner != nil and tracked.owner.kind in routineKinds and - tracked.config.cmd != cmdNimscript: + tracked.config.cmd != cmdNimscript and tracked.inNimvmBranch == 0: # ...but NOT under `nim e`: nimscript has no codegen backend to protect, and # marking a routine `sfCompileTime` makes `semExpr` eagerly fold calls to it # at sem time (emConst), where module-level globals it reads have no VM slot @@ -1483,7 +1484,9 @@ proc track(tracked: PEffects, n: PNode) = of nkCaseStmt: trackCase(tracked, n) of nkWhen: # This should be a "when nimvm" node. let oldState = tracked.init.len + inc tracked.inNimvmBranch track(tracked, n[0][1]) + dec tracked.inNimvmBranch tracked.init.setLen(oldState) track(tracked, n[1][0]) of nkIfStmt, nkIfExpr: trackIf(tracked, n) diff --git a/config/nim.cfg b/config/nim.cfg index 6a259321fb..26948ba928 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -134,11 +134,11 @@ nimblepath="$home/.nimble/pkgs/" # BSD got posix_spawn only recently, so we deactivate it for osproc: define:useFork @elif haiku: - gcc.options.linker = "-Wl,--as-needed -lnetwork" - gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork" - clang.options.linker = "-Wl,--as-needed -lnetwork" - clang.cpp.options.linker = "-Wl,--as-needed -lnetwork" - tcc.options.linker = "-Wl,--as-needed -lnetwork" + gcc.options.linker = "-Wl,--as-needed -lnetwork -lbsd" + gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork -lbsd" + clang.options.linker = "-Wl,--as-needed -lnetwork -lbsd" + clang.cpp.options.linker = "-Wl,--as-needed -lnetwork -lbsd" + tcc.options.linker = "-Wl,--as-needed -lnetwork -lbsd" @elif not genode: # -fopenmp gcc.options.linker = "-ldl" diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim index 2450cdb424..f5edcaf2e0 100644 --- a/lib/posix/kqueue.nim +++ b/lib/posix/kqueue.nim @@ -28,6 +28,15 @@ elif defined(netbsd): EVFILT_PROC* = 4 ## attached to struct proc EVFILT_SIGNAL* = 5 ## attached to struct proc EVFILT_TIMER* = 6 ## timers (in ms) +elif defined(haiku): + const + EVFILT_READ* = -1 + EVFILT_WRITE* = -2 + EVFILT_AIO* = -3 ## attached to aio requests + EVFILT_VNODE* = -4 ## attached to vnodes + EVFILT_PROC* = -5 ## attached to struct proc + EVFILT_SIGNAL* = -6 ## attached to struct proc + EVFILT_TIMER* = -7 ## timers when defined(macosx): const EVFILT_MACHPORT* = -8 ## Mach portsets diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 4177b47b1f..db7f4c1482 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -89,7 +89,7 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): var mmapDescrPos = cast[int](result) -% sizeof(EmscriptenMMapBlock) - var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) + var mmapDescr = cast[PEmscriptenMMapBlock](mmapDescrPos) mmapDescr.realSize = realSize mmapDescr.realPointer = realPointer @@ -99,7 +99,7 @@ elif defined(emscripten) and not defined(StandaloneHeapSize): proc osDeallocPages(p: pointer, size: int) {.inline.} = var mmapDescrPos = cast[int](p) -% sizeof(EmscriptenMMapBlock) - var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) + var mmapDescr = cast[PEmscriptenMMapBlock](mmapDescrPos) munmap(mmapDescr.realPointer, mmapDescr.realSize) elif defined(genode) and not defined(StandaloneHeapSize): diff --git a/tests/ccgbugs2/tcodegen.nim b/tests/ccgbugs2/tcodegen.nim index bca361e813..da5ab045cc 100644 --- a/tests/ccgbugs2/tcodegen.nim +++ b/tests/ccgbugs2/tcodegen.nim @@ -75,3 +75,15 @@ block: # importc type inheritance doAssert(cast[cint](b) == 123) var c = foo(b) doAssert(cast[cint](c) == 123) + +block: # bug #25945 + var stateRefund = 0 + let authCode = + if true: + if false: + stateRefund += 0 + @[] + else: + @([1.byte]) + +discard (if true: (discard; @[]) else: @[0]) diff --git a/tests/cpp/tcpp_default_ctor_assignment.h b/tests/cpp/tcpp_default_ctor_assignment.h new file mode 100644 index 0000000000..356cbb9381 --- /dev/null +++ b/tests/cpp/tcpp_default_ctor_assignment.h @@ -0,0 +1,30 @@ +#ifndef TCPP_DEFAULT_CTOR_ASSIGNMENT_H +#define TCPP_DEFAULT_CTOR_ASSIGNMENT_H + +struct AmbiguousAssign { + int x; + const char* y; + + AmbiguousAssign(): x(0), y(nullptr) {} + AmbiguousAssign(int x, const char* y): x(x), y(y) {} + + AmbiguousAssign& operator=(int v) { + x = v; + y = nullptr; + return *this; + } + + AmbiguousAssign& operator=(const char* s) { + x = 0; + y = s; + return *this; + } + + AmbiguousAssign& operator=(const AmbiguousAssign& other) { + x = other.x; + y = other.y; + return *this; + } +}; + +#endif \ No newline at end of file diff --git a/tests/cpp/tcpp_default_ctor_assignment.nim b/tests/cpp/tcpp_default_ctor_assignment.nim new file mode 100644 index 0000000000..88d9671ae6 --- /dev/null +++ b/tests/cpp/tcpp_default_ctor_assignment.nim @@ -0,0 +1,14 @@ +discard """ + cmd: "nim cpp $file" +""" + +type + AmbiguousAssign {.importcpp, header: "tcpp_default_ctor_assignment.h".} = object + x: cint + y: cstring + +proc main = + var xs = newSeq[AmbiguousAssign](3) + doAssert xs.len == 3 + +main() \ No newline at end of file diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 906ced7b83..c8ed29f7ce 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -855,3 +855,17 @@ block: var r = Obj(x: 10) r.value = 42 doAssert r.x == 42 + +block: # bug #25949 + template loadFile(filename: string): auto = + when nimvm: + staticRead(filename) + else: + "something" + + proc roundTrip(): bool = + let content = loadFile("tests/tomls/case.toml") + content == "something" + + doAssert roundTrip() +