diff --git a/changelog.md b/changelog.md index af62173247a2d..d54ed4c8cc25b 100644 --- a/changelog.md +++ b/changelog.md @@ -122,11 +122,11 @@ deallocShared(x.val) x.val = nil ``` - - getImpl() on enum type symbols now returns field syms instead of idents. This helps with writing typed macros. Old behavior for backwards compatiblity can be restored with command line switch `--useVersion:1.0`. - +- ``let`` statements can now be used without a value if declared with + ``importc``/``importcpp``/``importjs``/``importobjc``. - The keyword `from` is now usable as an operator. - Exceptions inheriting from `system.Defect` are no longer tracked with the `.raises: []` exception tracking mechanism. This is more consistent with the @@ -152,7 +152,6 @@ proc mydiv(a, b): int {.raises: [].} = The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. - ## Compiler changes - Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0e018dd0b3138..3faa328080aea 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -531,8 +531,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = # special type inference rule: 'var it = ownedPointer' is turned # into an unowned pointer. typ = typ.lastSon - else: - if symkind == skLet: localError(c.config, a.info, errLetNeedsInit) # this can only happen for errornous var statements: if typ == nil: continue @@ -620,6 +618,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = defaultConstructionError(c, v.typ, v.info) else: checkNilable(c, v) + # allow let to not be initialised if imported from C: + if v.kind == skLet and sfImportc notin v.flags: + localError(c.config, a.info, errLetNeedsInit) if sfCompileTime in v.flags: var x = newNodeI(result.kind, v.info) x.add result[i] diff --git a/doc/manual.rst b/doc/manual.rst index 82678f40ee0b0..8d4439644a9e2 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2679,6 +2679,11 @@ nor can their address be taken. They cannot be assigned new values. For let variables the same pragmas are available as for ordinary variables. +As ``let`` statements are immutable after creation they need to define a value +when they are declared. The only exception to this is if the ``{.importc.}`` +pragma (or any of the other ``importX`` pragmas) is applied, in this case the +value is expected to come from native code, typically a C/C++ ``const``. + Tuple unpacking --------------- @@ -7090,6 +7095,16 @@ spelled*: .. code-block:: proc printf(formatstr: cstring) {.header: "", importc: "printf", varargs.} +When ``importc`` is applied to a ``let`` statement it can omit its value which +will then be expected to come from C. This can be used to import a C ``const``: + +.. code-block:: + {.emit: "const int cconst = 42;".} + + let cconst {.importc, nodecl.}: cint + + assert cconst == 42 + Note that this pragma has been abused in the past to also work in the js backend for js objects and functions. : Other backends do provide the same feature under the same name. Also, when the target language diff --git a/tests/let/timportc.nim b/tests/let/timportc.nim new file mode 100644 index 0000000000000..85244da9fba34 --- /dev/null +++ b/tests/let/timportc.nim @@ -0,0 +1,24 @@ +discard """ +targets: "c cpp js" +""" + +when defined(c) or defined(cpp): + {.emit:""" + const int TEST1 = 123; + #define TEST2 321 + """.} + +when defined(js): + {.emit:""" + const TEST1 = 123; + const TEST2 = 321; // JS doesn't have macros, so we just duplicate + """.} + +let + TEST0 = 1 + TEST1 {.importc, nodecl.}: cint + TEST2 {.importc, nodecl.}: cint + +doAssert TEST0 == 1 +doAssert TEST1 == 123 +doAssert TEST2 == 321 diff --git a/tests/let/timportc2.nim b/tests/let/timportc2.nim new file mode 100644 index 0000000000000..9643059238712 --- /dev/null +++ b/tests/let/timportc2.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "'let' symbol requires an initialization" + line: "7" +""" + +# Test that this still works when not annotated with importc +let test: cint +echo test