From 24fbacc63fe8c7a36c77a35bede98462607e950e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 3 Mar 2024 15:40:08 +0100 Subject: [PATCH 01/25] =?UTF-8?q?fixes=20an=20issue=20with=20string=20to?= =?UTF-8?q?=20'var=20openArray'=20at=20compile-time;=20[backp=E2=80=A6=20(?= =?UTF-8?q?#23363)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ort] --- compiler/ccgutils.nim | 40 ++++++++++++++++++++-------------------- compiler/vm.nim | 7 ++++++- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 7c305a195ffed..4ba1c19d94f82 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -13,7 +13,7 @@ import ast, types, msgs, wordrecg, platform, trees, options, cgendata -import std/[hashes, strutils, formatFloat] +import std/[hashes, strutils, formatfloat] when defined(nimPreviewSlimSystem): import std/assertions @@ -126,10 +126,10 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = var pt = skipTypes(s.typ, typedescInst) assert skResult != s.kind - + #note precedence: params override types if optByRef in s.options: return true - elif sfByCopy in s.flags: return false + elif sfByCopy in s.flags: return false elif tfByRef in pt.flags: return true elif tfByCopy in pt.flags: return false case pt.kind @@ -153,62 +153,62 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or pt.kind == tySet and mapSetType(conf, pt) == ctArray) -proc encodeName*(name: string): string = +proc encodeName*(name: string): string = result = mangle(name) result = $result.len & result -proc makeUnique(m: BModule; s: PSym, name: string = ""): string = +proc makeUnique(m: BModule; s: PSym, name: string = ""): string = result = if name == "": s.name.s else: name result.add "__" result.add m.g.graph.ifaces[s.itemId.module].uniqueName result.add "_u" result.add $s.itemId.item -proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string = +proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string = #Module::Type - var name = s.name.s + var name = s.name.s if makeUnique: name = makeUnique(m, s, name) "N" & encodeName(s.owner.name.s) & encodeName(name) & "E" -proc encodeType*(m: BModule; t: PType): string = +proc encodeType*(m: BModule; t: PType): string = result = "" var kindName = ($t.kind)[2..^1] kindName[0] = toLower($kindName[0])[0] case t.kind - of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam: + of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam: result = encodeSym(m, t.sym) of tyGenericInst, tyUserTypeClassInst, tyGenericBody: result = encodeName(t[0].sym.name.s) result.add "I" - for i in 1.. Date: Sun, 3 Mar 2024 15:40:53 +0100 Subject: [PATCH 02/25] strformat: detect format string errors at compile-time (#23356) This also prevents unwanted `raises: [ValueError]` effects from bubbling up from correct format strings which makes `fmt` broadly unusable with `raises`. The old runtime-based `formatValue` overloads are kept for backwards-compatibility, should anyone be using runtime format strings. --------- Co-authored-by: Andreas Rumpf --- lib/pure/strformat.nim | 136 +++++++++++++++++++++++++----------- tests/stdlib/tstrformat.nim | 15 +++- 2 files changed, 111 insertions(+), 40 deletions(-) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 41b35da834383..7d093ebb3761d 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -481,50 +481,48 @@ proc parseStandardFormatSpecifier*(s: string; start = 0; raise newException(ValueError, "invalid format string, cannot parse: " & s[i..^1]) +proc toRadix(typ: char): int = + case typ + of 'x', 'X': 16 + of 'd', '\0': 10 + of 'o': 8 + of 'b': 2 + else: + raise newException(ValueError, + "invalid type in format string for number, expected one " & + " of 'x', 'X', 'b', 'd', 'o' but got: " & typ) + proc formatValue*[T: SomeInteger](result: var string; value: T; - specifier: string) = + specifier: static string) = ## Standard format implementation for `SomeInteger`. It makes little ## sense to call this directly, but it is required to exist ## by the `&` macro. - if specifier.len == 0: + when specifier.len == 0: result.add $value - return - let spec = parseStandardFormatSpecifier(specifier) - var radix = 10 - case spec.typ - of 'x', 'X': radix = 16 - of 'd', '\0': discard - of 'b': radix = 2 - of 'o': radix = 8 else: - raise newException(ValueError, - "invalid type in format string for number, expected one " & - " of 'x', 'X', 'b', 'd', 'o' but got: " & spec.typ) - result.add formatInt(value, radix, spec) + const + spec = parseStandardFormatSpecifier(specifier) + radix = toRadix(spec.typ) -proc formatValue*(result: var string; value: SomeFloat; specifier: string) = - ## Standard format implementation for `SomeFloat`. It makes little + result.add formatInt(value, radix, spec) + +proc formatValue*[T: SomeInteger](result: var string; value: T; + specifier: string) = + ## Standard format implementation for `SomeInteger`. It makes little ## sense to call this directly, but it is required to exist ## by the `&` macro. if specifier.len == 0: result.add $value - return - let spec = parseStandardFormatSpecifier(specifier) - - var fmode = ffDefault - case spec.typ - of 'e', 'E': - fmode = ffScientific - of 'f', 'F': - fmode = ffDecimal - of 'g', 'G': - fmode = ffDefault - of '\0': discard else: - raise newException(ValueError, - "invalid type in format string for number, expected one " & - " of 'e', 'E', 'f', 'F', 'g', 'G' but got: " & spec.typ) + let + spec = parseStandardFormatSpecifier(specifier) + radix = toRadix(spec.typ) + + result.add formatInt(value, radix, spec) +proc formatFloat( + result: var string, value: SomeFloat, fmode: FloatFormatMode, + spec: StandardFormatSpecifier) = var f = formatBiggestFloat(value, fmode, spec.precision) var sign = false if value >= 0.0: @@ -559,23 +557,83 @@ proc formatValue*(result: var string; value: SomeFloat; specifier: string) = else: result.add res +proc toFloatFormatMode(typ: char): FloatFormatMode = + case typ + of 'e', 'E': ffScientific + of 'f', 'F': ffDecimal + of 'g', 'G': ffDefault + of '\0': ffDefault + else: + raise newException(ValueError, + "invalid type in format string for number, expected one " & + " of 'e', 'E', 'f', 'F', 'g', 'G' but got: " & typ) + +proc formatValue*(result: var string; value: SomeFloat; specifier: static string) = + ## Standard format implementation for `SomeFloat`. It makes little + ## sense to call this directly, but it is required to exist + ## by the `&` macro. + when specifier.len == 0: + result.add $value + else: + const + spec = parseStandardFormatSpecifier(specifier) + fmode = toFloatFormatMode(spec.typ) + + formatFloat(result, value, fmode, spec) + +proc formatValue*(result: var string; value: SomeFloat; specifier: string) = + ## Standard format implementation for `SomeFloat`. It makes little + ## sense to call this directly, but it is required to exist + ## by the `&` macro. + if specifier.len == 0: + result.add $value + else: + let + spec = parseStandardFormatSpecifier(specifier) + fmode = toFloatFormatMode(spec.typ) + + formatFloat(result, value, fmode, spec) + +proc formatValue*(result: var string; value: string; specifier: static string) = + ## Standard format implementation for `string`. It makes little + ## sense to call this directly, but it is required to exist + ## by the `&` macro. + const spec = parseStandardFormatSpecifier(specifier) + var value = + when spec.typ in {'s', '\0'}: value + else: static: + raise newException(ValueError, + "invalid type in format string for string, expected 's', but got " & + spec.typ) + when spec.precision != -1: + if spec.precision < runeLen(value): + const precision = cast[Natural](spec.precision) + setLen(value, Natural(runeOffset(value, precision))) + + result.add alignString(value, spec.minimumWidth, spec.align, spec.fill) + proc formatValue*(result: var string; value: string; specifier: string) = ## Standard format implementation for `string`. It makes little ## sense to call this directly, but it is required to exist ## by the `&` macro. let spec = parseStandardFormatSpecifier(specifier) - var value = value - case spec.typ - of 's', '\0': discard - else: - raise newException(ValueError, - "invalid type in format string for string, expected 's', but got " & - spec.typ) + var value = + if spec.typ in {'s', '\0'}: value + else: + raise newException(ValueError, + "invalid type in format string for string, expected 's', but got " & + spec.typ) if spec.precision != -1: if spec.precision < runeLen(value): - setLen(value, runeOffset(value, spec.precision)) + let precision = cast[Natural](spec.precision) + setLen(value, Natural(runeOffset(value, precision))) + result.add alignString(value, spec.minimumWidth, spec.align, spec.fill) +proc formatValue[T: not SomeInteger](result: var string; value: T; specifier: static string) = + mixin `$` + formatValue(result, $value, specifier) + proc formatValue[T: not SomeInteger](result: var string; value: T; specifier: string) = mixin `$` formatValue(result, $value, specifier) diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 3c0d55c1dbccf..ff406f8980177 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -562,7 +562,7 @@ proc main() = doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')" doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')" - + block: # issue #20381 var ss: seq[string] template myTemplate(s: string) = @@ -573,5 +573,18 @@ proc main() = foo() doAssert ss == @["hello", "hello"] + block: + proc noraises() {.raises: [].} = + const + flt = 0.0 + str = "str" + + doAssert fmt"{flt} {str}" == "0.0 str" + + noraises() + + block: + doAssert not compiles(fmt"{formatting errors detected at compile time") + static: main() main() From f4fe3af42a54d70154aa5e6bc811bb9eee304214 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Sun, 3 Mar 2024 15:53:23 +0100 Subject: [PATCH 03/25] make use of C++11's auto type deduction for temporary variables (#23327) This is just one of those tiny steps towards the goal of an "optimized" C and C++ codegen I raised elsewhere before - what does me babbling "optimized" mainly entail? (not mutually-exclusive ascertainment proposals following:) - less and simplified resulting code: easier to pick up/grasp for the C/C++ compiler for to do its own optimization heuristics, less parsing effort for us mere humans trying to debug, especially in the case of interop - build time reduction: less code emission I/O, runtime string formatting for output... - easier access for fresh contributors and better maintainability - interop improvements - further runtime optimizations I am eagerly looking forward to the results of the LLVM-based undertakings, but I also think we can do a bit better (as outlined above) with our current C/C++ backends till those come to fruition. **Long story short**: this PR here focuses on the C++ backend, augmenting the current codegen method of establishing "temporary" variables by using C++11's auto type deduction. The reasons for adopting an "Almost Always Auto" style have been collected [here ](https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/) for the C++ world. For those hopping between C++'s and Nim's realms, this change also results in a bit less code and less work for the codegen part (no redundant `getTypeDesc`s): no need to tell the C++ compiler the type it already knows of (in most cases). --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3c309db989de4..abdf9ef050d91 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -574,7 +574,7 @@ proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc = inc(p.labels) result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t, storage: OnStack, flags: {}) - linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value]) + linefmt(p, cpsStmts, "auto $1 = $2;$n", [result.r, value]) proc getIntTemp(p: BProc): TLoc = inc(p.labels) From 31d755452485eccffa396e0e8432050a63b04c35 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 3 Mar 2024 22:56:06 +0800 Subject: [PATCH 04/25] fixes #13481; fixes #22708; disable using union objects in VM (#23362) fixes #13481; fixes #22708 Otherwise it gives implicit results or bad codegen --- compiler/vmgen.nim | 2 ++ tests/vm/tvmmisc.nim | 8 -------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index b7dd193be63f2..79d037e420270 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2050,6 +2050,8 @@ proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) = c.freeTemp(a) proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) = + if tfUnion in n.typ.flags: # bug #22708 # bug #13481 + globalError(c.config, n.info, "object with '{.union.}' pragmas is not supported by VM") if dest < 0: dest = c.getTemp(n.typ) let t = n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc}) if t.kind == tyRef: diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index f277c20d8b8c6..d28f765740e2c 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -301,14 +301,6 @@ block: # bug #10815 const a = P() doAssert $a == "" -when defined osx: # xxx bug #13481 - block: - type CharSet {.union.} = object - cs: set[char] - vs: array[4, uint64] - const a = Charset(cs: {'a'..'z'}) - doAssert a.repr.len > 0 - import tables block: # bug #8007 From 572b0b67ff15373748dfdde4f470bd45641de990 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:03:53 +0800 Subject: [PATCH 05/25] fixes sink regression for ORC; ref #23354 (#23359) ref #23354 The new move analyzer requires types that have the tfAsgn flag (otherwise `lastRead` will return true); tfAsgn is included when the destructor is not trival. But it should consider the assignement for objects in this case because objects might have a trival destructors but it's the assignement that matters when it is passed to sink parameters. --- compiler/injectdestructors.nim | 3 ++- compiler/liftdestructors.nim | 2 +- tests/destructor/tsink.nim | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/destructor/tsink.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index ce84bc0dcb188..3e1f6afc71349 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -163,7 +163,8 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool = result = false proc isLastRead(n: PNode; c: var Con; s: var Scope): bool = - if not hasDestructor(c, n.typ): return true + # bug #23354; an object type could have a non-trival assignements when it is passed to a sink parameter + if not hasDestructor(c, n.typ) and (n.typ.kind != tyObject or isTrival(getAttachedOp(c.graph, n.typ, attachedAsgn))): return true let m = skipConvDfa(n) result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index aba1aa38c7020..350b4cc255520 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -1252,7 +1252,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I else: localError(g.config, info, "unresolved generic parameter") -proc isTrival(s: PSym): bool {.inline.} = +proc isTrival*(s: PSym): bool {.inline.} = s == nil or (s.ast != nil and s.ast[bodyPos].len == 0) proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo; diff --git a/tests/destructor/tsink.nim b/tests/destructor/tsink.nim new file mode 100644 index 0000000000000..82cbdfbe5da86 --- /dev/null +++ b/tests/destructor/tsink.nim @@ -0,0 +1,16 @@ +discard """ + matrix: "--mm:arc" +""" + +type AnObject = object of RootObj + value*: int + +proc mutate(shit: sink AnObject) = + shit.value = 1 + +proc foo = # bug #23359 + var bar = AnObject(value: 42) + mutate(bar) + doAssert bar.value == 42 + +foo() From aa30233ea7f904c466020b8eb1b369e9b49ab79f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:04:24 +0800 Subject: [PATCH 06/25] fixes #23273; forbids methods having importc pragmas (#23324) fixes #23273 --- compiler/cgmeth.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 6c3db7ad68f07..b132c60493a33 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -163,6 +163,10 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = g.config.isDefined("nimInternalNonVtablesTesting"): localError(g.config, s.info, errGenerated, "method `" & s.name.s & "` can be defined only in the same module with its type (" & s.typ.firstParamType.typeToString() & ")") + if sfImportc in s.flags: + localError(g.config, s.info, errGenerated, "method `" & s.name.s & + "` is not allowed to have 'importc' pragmas") + for i in 0.. Date: Sun, 3 Mar 2024 16:05:11 +0100 Subject: [PATCH 07/25] Fix nimsuggest highlight for import statements (#23263) Currently, I don't have syntax highlighting (+ no/wrong jump-to-definition) for some import statement forms, namely: - `import module/name/with/(slashes)` - `import (mod) as alias` - `import basemod/[ (sub1), (sub2) ]` With this patch, highlight/def will work for the regions indicated by parentheses. --- compiler/importer.nim | 10 +++++++++- nimsuggest/tests/timport_highlight.nim | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 nimsuggest/tests/timport_highlight.nim diff --git a/compiler/importer.nim b/compiler/importer.nim index 57cbbb8475830..6d3cd6f93405f 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -307,7 +307,15 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = if belongsToStdlib(c.graph, result) and not startsWith(moduleName, stdPrefix) and not startsWith(moduleName, "system/") and not startsWith(moduleName, "packages/"): message(c.config, n.info, warnStdPrefix, realModule.name.s) - suggestSym(c.graph, n.info, result, c.graph.usageSym, false) + + proc suggestMod(n: PNode; s: PSym) = + if n.kind == nkImportAs: + suggestMod(n[0], realModule) + elif n.kind == nkInfix: + suggestMod(n[2], s) + else: + suggestSym(c.graph, n.info, s, c.graph.usageSym, false) + suggestMod(n, result) importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) else: diff --git a/nimsuggest/tests/timport_highlight.nim b/nimsuggest/tests/timport_highlight.nim new file mode 100644 index 0000000000000..043f87d98fb6b --- /dev/null +++ b/nimsuggest/tests/timport_highlight.nim @@ -0,0 +1,12 @@ +import std/paths +import json as J +import std/[os,streams]#[!]# + +discard """ +$nimsuggest --tester $file +>highlight $1 +highlight;;skModule;;1;;11;;5 +highlight;;skModule;;2;;7;;4 +highlight;;skModule;;3;;12;;2 +highlight;;skModule;;3;;15;;7 +""" From 79bd6fe0845a90b15673ed887eda2cdc16ce2a09 Mon Sep 17 00:00:00 2001 From: litlighilit Date: Mon, 4 Mar 2024 00:27:27 +0800 Subject: [PATCH 08/25] Update browsers.nim, deprecate unimplemented `openDefaultBrowser()` (#23332) For this [proc](https://github.com/nim-lang/Nim/blob/773c066634d831a968bb464eab35b25a00026525/lib/pure/browsers.nim#L83) `proc openDefaultBrowser*() {.since: (1, 1).}`: though it's documented to open default browser with `about:blank` page, it behaves differently: - On Windows, it failed and open no window - On Linux(Debian with Kde), it opens not default browser but `Konqueror` I have paid much effort to implement this variant, but even the implementation on Windows is considerably complex. In short, it's not only hard but unworthy to fix this. Just as Araq [said](https://github.com/nim-lang/Nim/issues/22250#issuecomment-1631360617), we shall remove the `proc openDefaultBrowser*() {.since: (1, 1).}` variant --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/pure/browsers.nim | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 5708582e14601..59e2078dfc33f 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -12,7 +12,7 @@ ## ## Unstable API. -import std/private/since +import std/private/since # used by the deprecated `openDefaultBrowser()` import std/strutils @@ -40,7 +40,7 @@ proc prepare(s: string): string = else: result = "file://" & absolutePath(s) -proc openDefaultBrowserImplPrep(url: string) = +proc openDefaultBrowserRaw(url: string) = ## note the url argument should be alreadly prepared, i.e. the url is passed "AS IS" when defined(windows): @@ -60,9 +60,6 @@ proc openDefaultBrowserImplPrep(url: string) = except OSError: discard -proc openDefaultBrowserImpl(url: string) = - openDefaultBrowserImplPrep(prepare url) - proc openDefaultBrowser*(url: string) = ## Opens `url` with the user's default browser. This does not block. ## The URL must not be empty string, to open on a blank page see `openDefaultBrowser()`. @@ -78,16 +75,30 @@ proc openDefaultBrowser*(url: string) = ## block: openDefaultBrowser("https://nim-lang.org") ## ``` doAssert url.len > 0, "URL must not be empty string" - openDefaultBrowserImpl(url) + openDefaultBrowserRaw(url) -proc openDefaultBrowser*() {.since: (1, 1).} = - ## Opens the user's default browser without any `url` (blank page). This does not block. - ## Implements IETF RFC-6694 Section 3, "about:blank" must be reserved for a blank page. +proc openDefaultBrowser*() {.since: (1, 1), deprecated: + "not implemented, please open with a specific url instead".} = + ## Intends to open the user's default browser without any `url` (blank page). + ## This does not block. + ## Intends to implement IETF RFC-6694 Section 3, + ## ("about:blank" is reserved for a blank page). ## - ## Under Windows, `ShellExecute` is used. Under Mac OS X the `open` - ## command is used. Under Unix, it is checked if `xdg-open` exists and - ## used if it does. Otherwise the environment variable `BROWSER` is - ## used to determine the default browser to use. + ## Beware that this intended behavior is **not** implemented and + ## considered not worthy to implement here. + ## + ## The following describes the behavior of current implementation: + ## + ## - Under Windows, this will only cause a pop-up dialog \ + ## asking the assocated application with `about` \ + ## (as Windows simply treats `about:` as a protocol like `http`). + ## - Under Mac OS X the `open "about:blank"` command is used. + ## - Under Unix, it is checked if `xdg-open` exists and used \ + ## if it does and open the application assocated with `text/html` mime \ + ## (not `x-scheme-handler/http`, so maybe html-viewer \ + ## other than your default browser is opened). \ + ## Otherwise the environment variable `BROWSER` is used \ + ## to determine the default browser to use. ## ## This proc doesn't raise an exception on error, beware. ## @@ -98,4 +109,4 @@ proc openDefaultBrowser*() {.since: (1, 1).} = ## **See also:** ## ## * https://tools.ietf.org/html/rfc6694#section-3 - openDefaultBrowserImplPrep("about:blank") # See IETF RFC-6694 Section 3. + openDefaultBrowserRaw("about:blank") # See IETF RFC-6694 Section 3. From 90fe1b340f93622f5f101ee93306b386a30eb206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sun, 3 Mar 2024 16:37:29 +0000 Subject: [PATCH 09/25] Dont mangle when targeting cpp (#23335) Unfortunately we cant trick the debugger when targeting C++ so this one also needs to wait for our own debugger adapter. --- compiler/ccgtypes.nim | 2 +- tests/codegen/titaniummangle.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e8054b9e48fc8..83c226c984100 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -71,7 +71,7 @@ proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string = proc fillBackendName(m: BModule; s: PSym) = if s.loc.r == "": var result: Rope - if s.kind in routineKinds and optCDebug in m.g.config.globalOptions and + if not m.compileToCpp and s.kind in routineKinds and optCDebug in m.g.config.globalOptions and m.g.config.symbolFiles == disabledSf: result = mangleProc(m, s, false).rope else: diff --git a/tests/codegen/titaniummangle.nim b/tests/codegen/titaniummangle.nim index b20ffee3b827d..5ab4e34101246 100644 --- a/tests/codegen/titaniummangle.nim +++ b/tests/codegen/titaniummangle.nim @@ -1,5 +1,5 @@ discard """ - targets: "c cpp" + targets: "c" matrix: "--debugger:native" ccodecheck: "'_ZN14titaniummangle8testFuncE'" ccodecheck: "'_ZN14titaniummangle8testFuncE6stringN14titaniummangle3FooE'" From 248850a0ce869c15fea16a35e248850d2df47c8d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 4 Mar 2024 00:52:56 +0800 Subject: [PATCH 10/25] ref #23333; fixes AF_INET6 value on Linux (#23334) ref #23333 --- lib/pure/nativesockets.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 6d6b3097a3a64..20ea9d77a11e5 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -67,7 +67,7 @@ type ## some procedures, such as getaddrinfo) AF_UNIX = 1, ## for local socket (using a file). Unsupported on Windows. AF_INET = 2, ## for network protocol IPv4 or - AF_INET6 = when defined(macosx): 30 else: 23 ## for network protocol IPv6. + AF_INET6 = when defined(macosx): 30 elif defined(windows): 23 else: 10 ## for network protocol IPv6. SockType* = enum ## second argument to `socket` proc SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets From a61943490479daf9716f310e94130b016a99abe0 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 4 Mar 2024 16:57:40 +0800 Subject: [PATCH 11/25] remove obselete doc with nimrtl (#23358) since nimrtl.dll is created with `--threads:on` --- doc/nimc.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/nimc.md b/doc/nimc.md index 1136bef092bb8..25acf31e835db 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -503,9 +503,6 @@ To link against ``nimrtl.dll`` use the command: nim c -d:useNimRtl myprog.nim ``` -**Note**: Currently the creation of ``nimrtl.dll`` with thread support has -never been tested and is unlikely to work! - Additional compilation switches =============================== From 2081da3207b004e21537cf079c8e7f583bc66d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 4 Mar 2024 08:58:06 +0000 Subject: [PATCH 12/25] makes nimsuggest listen on localhost by default (#23351) --- nimsuggest/nimsuggest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index e69731b27ac39..e1bb0d5aa3e35 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -92,7 +92,7 @@ type var gPort = 6000.Port - gAddress = "" + gAddress = "127.0.0.1" gMode: Mode gEmitEof: bool # whether we write '!EOF!' dummy lines gLogging = defined(logging) From 6e875cd7c2b4659f46199593cacf5fced653b660 Mon Sep 17 00:00:00 2001 From: litlighilit Date: Mon, 4 Mar 2024 16:58:33 +0800 Subject: [PATCH 13/25] fix `isAbsolute` broken when `nodejs` on Windows (#23365) When target is nodejs, `isAbsolute` used to only check in the POSIX flavor, i.e. for js backend on Windows, ```nim isAbsolute(r"C:\Windows") == false ``` This fixes it. --- lib/std/private/ospaths2.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 5dd09d7e696d1..a5c0edd9fe547 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -254,10 +254,10 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raise result = path[0] != ':' elif defined(RISCOS): result = path[0] == '$' - elif defined(posix) or defined(js): - # `or defined(js)` wouldn't be needed pending https://github.com/nim-lang/Nim/issues/13469 - # This works around the problem for posix, but Windows is still broken with nim js -d:nodejs + elif defined(posix): result = path[0] == '/' + elif defined(nodejs): + {.emit: [result," = require(\"path\").isAbsolute(",path.cstring,");"].} else: raiseAssert "unreachable" # if ever hits here, adapt as needed From e217bb24a1e5b92d448bf7afa2488bec89b94cfb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 4 Mar 2024 17:14:25 +0800 Subject: [PATCH 14/25] fixes #20945; fixes #18262; provides C API `NimDestroyGlobals` for static/dynlib libraries (#23357) fixes #20945 fixes #18262 todo - [ ] perhaps export with lib prefix when the option is enabled --- compiler/cgen.nim | 23 +++++++++++++++++++++++ doc/backends.md | 2 ++ 2 files changed, 25 insertions(+) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index abdf9ef050d91..ca735166a33b4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2194,6 +2194,22 @@ proc updateCachedModule(m: BModule) = cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) +proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: PNode; isDynlib: bool): PSym = + let procname = getIdent(graph.cache, "NimDestroyGlobals") + result = newSym(skProc, procname, m.idgen, m.module.owner, m.module.info) + result.typ = newProcType(m.module.info, m.idgen, m.module.owner) + result.typ.callConv = ccCDecl + incl result.flags, sfExportc + result.loc.r = "NimDestroyGlobals" + if isDynlib: + incl(result.loc.flags, lfExportLib) + + let theProc = newNodeI(nkProcDef, m.module.info, bodyPos+1) + for i in 0.. Date: Tue, 5 Mar 2024 16:39:20 +0800 Subject: [PATCH 15/25] closes #10219; adds a test case (#23370) closes #10219 --- tests/cpp/torc.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim index 64c6c0e5fde6b..67eb52deac463 100644 --- a/tests/cpp/torc.nim +++ b/tests/cpp/torc.nim @@ -39,3 +39,23 @@ proc asVector*[T](t: T): EnumVector[T] = # N_NIMCALL(std::vector<> , asvector_106028_3197418230)(SomeEnum t0) discard asVector(SomeEnum.A) + + +block: # bug #10219 + type + Vector[T] {.importcpp: "std::vector", header: "vector".} = object + + proc initVector[T](n: csize_t): Vector[T] + {.importcpp: "std::vector<'*0>(@)", header: "vector".} + + proc unsafeIndex[T](this: var Vector[T], i: csize_t): var T + {.importcpp: "#[#]", header: "vector".} + + proc `[]`[T](this: var Vector[T], i: Natural): var T {.inline, noinit.} = + when compileOption("boundChecks"): + # this.checkIndex i + discard + result = this.unsafeIndex(csize_t(i)) + + var v1 = initVector[int](10) + doAssert v1[0] == 0 From 7cd3d606838848261b7be6aa4675a761c7946129 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 6 Mar 2024 01:06:58 +0800 Subject: [PATCH 16/25] fixes #12703; nim cpp rejects valid code would lose const qualifier for cstring to string via cstrToNimstr (#23371) fixes #12703 ref #19588 --- compiler/ccgexprs.nim | 19 +++++++++++++++---- tests/cpp/torc.nim | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 704ca82e2a20e..c81153744f415 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2250,9 +2250,15 @@ proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc = initLocExpr(p, n[0]) - putIntoDest(p, d, n, - ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), - a.storage) + if p.module.compileToCpp: + # fixes for const qualifier; bug #12703; bug #19588 + putIntoDest(p, d, n, + ropecg(p.module, "#cstrToNimstr((NCSTRING) $1)", [rdLoc(a)]), + a.storage) + else: + putIntoDest(p, d, n, + ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), + a.storage) gcUsage(p.config, n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = @@ -2470,7 +2476,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = genDollar(p, e, d, "#nimFloat32ToStr($1)") else: genDollar(p, e, d, "#nimFloatToStr($1)") - of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") + of mCStrToStr: + if p.module.compileToCpp: + # fixes for const qualifier; bug #12703; bug #19588 + genDollar(p, e, d, "#cstrToNimstr((NCSTRING) $1)") + else: + genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e[1], d) of generatedMagics: genCall(p, e, d) of mEnumToStr: diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim index 67eb52deac463..9f1a41a21b722 100644 --- a/tests/cpp/torc.nim +++ b/tests/cpp/torc.nim @@ -59,3 +59,17 @@ block: # bug #10219 var v1 = initVector[int](10) doAssert v1[0] == 0 + +block: # bug #12703 bug #19588 + type + cstringConstImpl {.importc:"const char*".} = cstring + constChar = distinct cstringConstImpl + + {.emit: """ + const char* foo() { + return "hello"; + } + """.} + proc foo(): constChar {.importcpp.} # change to importcpp for C++ backend + doAssert $(foo().cstring) == "hello" + From a2584c779b0debb54cdd0111f9ad845fbfe33e97 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:25:20 +0800 Subject: [PATCH 17/25] closes #15751; adds a test case (#23372) closes #15751 --- tests/macros/t15751.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/macros/t15751.nim diff --git a/tests/macros/t15751.nim b/tests/macros/t15751.nim new file mode 100644 index 0000000000000..fcabb2f9ef583 --- /dev/null +++ b/tests/macros/t15751.nim @@ -0,0 +1,11 @@ +discard """ + cmd: "nim c --hints:off $file" + nimout: "out" +""" + +# bug #15751 +macro print(n: untyped): untyped = + echo n.repr + +print: + out From c2d2b6344d5fbbb802d59f3066b6b71ad09fa68a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 7 Mar 2024 04:24:55 +0800 Subject: [PATCH 18/25] remove mention of `GC_ref` and `GC_unref` for strings (#23373) --- doc/backends.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/doc/backends.md b/doc/backends.md index 996ffd2f9d9c4..9f0c548354ac5 100644 --- a/doc/backends.md +++ b/doc/backends.md @@ -373,11 +373,7 @@ The manual mentions that [Nim strings are implicitly convertible to cstrings](manual.html#types-cstring-type) which makes interaction usually painless. Most C functions accepting a Nim string converted to a `cstring` will likely not need to keep this string around and by the time -they return the string won't be needed anymore. However, for the rare cases -where a Nim string has to be preserved and made available to the C backend -as a `cstring`, you will need to manually prevent the string data -from being freed with [GC_ref](system.html#GC_ref,string) and [GC_unref]( -system.html#GC_unref,string). +they return the string won't be needed anymore. A similar thing happens with C code invoking Nim code which returns a `cstring`. Consider the following proc: From 6ebad30e7a96c67cc7a55aa3248849313c9f4e52 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:06:04 +0800 Subject: [PATCH 19/25] closes #22846; adds a test case (#23374) closes #22846 --- tests/template/tparams_gensymed.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index b68d7e253cb6c..b559c2d9e166d 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -16,6 +16,7 @@ wth (total: 6) S1 5 +abc ''' """ # bug #1915 @@ -394,3 +395,11 @@ proc chunkedReadLoop2 = test2 test1(); test2() + +block: # bug #22846 + template foo2(x: proc (y: string)) = + let f = x + f("abc") + + foo2(proc (y: string) = echo y) + From f80a5a30b4a73efb3a7da162f57a259dd69e02c2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 9 Mar 2024 18:41:39 +0800 Subject: [PATCH 20/25] fixes #23378; fixes js abs negative int64 (#23379) fixes #23378 --- compiler/jsgen.nim | 8 +++++++- tests/int/tints.nim | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 471d51c0f9873..ffc11789f9128 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -788,7 +788,13 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mEqProc: applyFormat("($1 == $2)", "($1 == $2)") of mUnaryMinusI: applyFormat("negInt($1)", "-($1)") of mUnaryMinusI64: applyFormat("negInt64($1)", "-($1)") - of mAbsI: applyFormat("absInt($1)", "Math.abs($1)") + of mAbsI: + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + useMagic(p, "absInt64") + applyFormat("absInt64($1)", "absInt64($1)") + else: + applyFormat("absInt($1)", "Math.abs($1)") of mNot: applyFormat("!($1)", "!($1)") of mUnaryPlusI: applyFormat("+($1)", "+($1)") of mBitnotI: diff --git a/tests/int/tints.nim b/tests/int/tints.nim index a7d27d7369762..5c071c21dd2d2 100644 --- a/tests/int/tints.nim +++ b/tests/int/tints.nim @@ -1,5 +1,6 @@ discard """ matrix: "; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + targets: "c js" output: ''' 0 0 0 0 @@ -7,6 +8,8 @@ Success''' """ # Test the different integer operations +# TODO: fixme --backend:js cannot change targets!!! + import std/private/jsutils var testNumber = 0 @@ -141,4 +144,9 @@ block: # shl when not defined(js) or (defined(js) and compileOption("jsbigint64")): doAssert u64 shl 1 == u64 - 1 +block: # bug #23378 + var neg = -1 # prevent compile-time evaluation + let n = abs BiggestInt neg + doAssert n == 1 + echo("Success") #OUT Success From 320311182c904cf4672457b8b02a60303856cb38 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 9 Mar 2024 18:42:15 +0800 Subject: [PATCH 21/25] fixes #22284; fixes #22282; don't override original parameters of inferred lambdas (#23368) fixes #22284 fixes #22282 ``` Error: j(uRef, proc (config: F; sources: auto) {.raises: [].} = discard ) can raise an unlisted exception: Exception ``` The problem is that `n.typ.n` contains the effectList which shouldn't appear in the parameter of a function defintion. We could not simply use `n.typ.n` as `n[paramsPos]`. The effect lists should be stripped away anyway. --- compiler/semstmts.nim | 1 - tests/errmsgs/t22284.nim | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/errmsgs/t22284.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index ff29f21d09040..677edbec60446 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1849,7 +1849,6 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = n[genericParamsPos] = c.graph.emptyNode # for LL we need to avoid wrong aliasing let params = copyTree n.typ.n - n[paramsPos] = params s.typ = n.typ for i in 1.. Date: Sat, 9 Mar 2024 18:43:00 +0800 Subject: [PATCH 22/25] fixes #22166; adds sideeffects for `close` and `setFilePos` (#23380) fixes #22166 --- lib/std/syncio.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index 38c151bb7ba5b..44244297f4b30 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -320,7 +320,7 @@ elif defined(windows): const BufSize = 4000 -proc close*(f: File) {.tags: [], gcsafe.} = +proc close*(f: File) {.tags: [], gcsafe, sideEffect.} = ## Closes the file. if not f.isNil: discard c_fclose(f) @@ -763,7 +763,7 @@ proc open*(filename: string, if not open(result, filename, mode, bufSize): raise newException(IOError, "cannot open: " & filename) -proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} = +proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign, sideEffect.} = ## Sets the position of the file pointer that is used for read/write ## operations. The file's first byte has the index zero. if c_fseek(f, pos, cint(relativeTo)) != 0: From 94c599687796f4ee3872c8aa866827b9ed33f52b Mon Sep 17 00:00:00 2001 From: lit <2636353816@qq.com> Date: Sat, 9 Mar 2024 18:43:27 +0800 Subject: [PATCH 23/25] Update tests/js/tos.nim, make isAbsolute tested on nodejs under Windows. (#23377) Windows's nodejs `isAbsolute` issue has been resolved by [this PR](https://github.com/nim-lang/Nim/pull/23365). So we can improve the coverage for Windows. --- tests/js/tos.nim | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/js/tos.nim b/tests/js/tos.nim index bfe3cd9b4f869..40fb52bcf74b7 100644 --- a/tests/js/tos.nim +++ b/tests/js/tos.nim @@ -13,11 +13,9 @@ block: doAssert not "foo".isAbsolute doAssert relativePath("", "bar") == "" doAssert normalizedPath(".///foo//./") == "foo" - let cwd = getCurrentDir() - let isWindows = '\\' in cwd - # defined(windows) doesn't work with -d:nodejs but should - # these actually break because of that (see https://github.com/nim-lang/Nim/issues/13469) - if not isWindows: + when nimvm: discard + else: + let cwd = getCurrentDir() doAssert cwd.isAbsolute - doAssert relativePath(getCurrentDir() / "foo", "bar") == "../foo" + doAssert relativePath(getCurrentDir() / "foo", "bar") == ".." / "foo" From 93399776c4640875c22c24e95bf8070dfd02d227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 11 Mar 2024 11:10:43 +0000 Subject: [PATCH 24/25] [C++] Allow `member` to define static funcs (#23387) --- compiler/ccgtypes.nim | 13 +++++++++---- tests/cpp/tmember.nim | 13 ++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 83c226c984100..baee02d20cd20 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1193,12 +1193,15 @@ proc isReloadable(m: BModule; prc: PSym): bool = proc isNonReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable in prc.flags -proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool, isFunctor=false) = +proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual, isStatic: var bool; isCtor: bool, isFunctor=false) = var afterParams: string = "" if scanf(val, "$*($*)$s$*", name, params, afterParams): if name.strip() == "operator" and params == "": #isFunctor? - parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isCtor, true) + parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isStatic, isCtor, true) return + if name.find("static ") > -1: + isStatic = true + name = name.replace("static ", "") isFnConst = afterParams.find("const") > -1 isOverride = afterParams.find("override") > -1 isMemberVirtual = name.find("virtual ") > -1 @@ -1231,8 +1234,8 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = var typDesc = getTypeDescWeak(m, typ, check, dkParam) let asPtrStr = rope(if asPtr: "_PTR" else: "") var name, params, rettype, superCall: string = "" - var isFnConst, isOverride, isMemberVirtual: bool = false - parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor) + var isFnConst, isOverride, isMemberVirtual, isStatic: bool = false + parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isStatic, isCtor) genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false) let isVirtual = sfVirtual in prc.flags or isMemberVirtual var fnConst, override: string = "" @@ -1241,6 +1244,8 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = if isFnConst: fnConst = " const" if isFwdDecl: + if isStatic: + result.add "static " if isVirtual: rettype = "virtual " & rettype if isOverride: diff --git a/tests/cpp/tmember.nim b/tests/cpp/tmember.nim index 07bd5e0ee3159..1a5b6fd9754b2 100644 --- a/tests/cpp/tmember.nim +++ b/tests/cpp/tmember.nim @@ -8,6 +8,8 @@ hello foo hello boo hello boo FunctorSupport! +static +static destructing destructing ''' @@ -34,7 +36,7 @@ echo doo == Doo(test: 1) #virtual proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} type - Foo = object of RootObj + Foo {.exportc.} = object of RootObj FooPtr = ptr Foo Boo = object of Foo BooPtr = ptr Boo @@ -62,3 +64,12 @@ proc invoke(f: NimFunctor, n:int) {.member:"operator ()('2 #2)" .} = {.experimental: "callOperator".} proc `()`(f: NimFunctor, n:int) {.importcpp:"#(@)" .} NimFunctor()(1) + +#static +proc staticProc(self: FooPtr) {.member: "static $1()".} = + echo "static" + +proc importedStaticProc() {.importcpp:"Foo::staticProc()".} + +foo.staticProc() +importedStaticProc() From 78c834dd76f273d8813247647531005a1f7db1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 11 Mar 2024 12:57:55 +0000 Subject: [PATCH 25/25] Fixes an issue where exported types werent being cgen with the `exportc` pragma (#23369) --- compiler/ccgtypes.nim | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index baee02d20cd20..ae9349b43f39f 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1992,8 +1992,11 @@ proc genTypeSection(m: BModule, n: PNode) = if len(n[i]) == 0: continue if n[i][0].kind != nkPragmaExpr: continue for p in 0..