From b3b87f0f8a8091c88461953d686f9772dfb3c4bc Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sun, 17 Dec 2023 22:29:46 +1100 Subject: [PATCH] Mark `macros.error` as `.noreturn.` (#23081) Closes #14329 Marks `macros.error` as `.noreturn` so that it can be used in expressions. This also fixes the issue that occurred in #19659 where a stmt that could be an expression (Due to having `discardable` procs at the end of other branches) would believe a `noreturn` proc is returning the same type e.g. ```nim proc bar(): int {.discardable.} = discard if true: bar() else: quit(0) # Says that quit is of type `int` and needs to be used/discarded except it actually has no return type ``` --- compiler/condsyms.nim | 1 + compiler/semstmts.nim | 5 +++++ lib/core/macros.nim | 7 ++++++- tests/casestmt/tcasestmt.nim | 14 ++++++++++++++ tests/macros/t14329.nim | 4 ++++ 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/macros/t14329.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 5865e5310e..085576c6b2 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -157,6 +157,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimAllowNonVarDestructor") defineSymbol("nimHasQuirky") defineSymbol("nimHasEnsureMove") + defineSymbol("nimHasNoReturnError") defineSymbol("nimUseStrictDefs") defineSymbol("nimHasNolineTooLong") diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index eacda7f9b7..a0eda36d1e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -169,6 +169,11 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) = while n.kind in skipForDiscardable: if n.kind == nkTryStmt: n = n[0] else: n = n.lastSon + + # Ignore noreturn procs since they don't have a type + if n.endsInNoReturn: + return + var s = "expression '" & $n & "' is of type '" & result.typ.typeToString & "' and has to be used (or discarded)" if result.info.line != n.info.line or diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 01a654b6c6..fe911ffbf6 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -427,7 +427,12 @@ proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} = let x = 12 echo x -proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.} +when defined(nimHasNoReturnError): + {.pragma: errorNoReturn, noreturn.} +else: + {.pragma: errorNoReturn.} + +proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign, errorNoReturn.} ## Writes an error message at compile time. The optional `n: NimNode` ## parameter is used as the source for file and line number information in ## the compilation error message. diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index 3a4907494a..aea0c96a42 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -298,3 +298,17 @@ proc main(a: uint64) = static: main(10) main(10) + +block: + # Just needs to compile + proc bar(): int {.discardable.} = discard + + proc foo() {.noreturn.} = discard + + case "*" + of "*": + bar() + else: + # Make sure this noreturn doesn't + # cause the discardable to not discard + foo() diff --git a/tests/macros/t14329.nim b/tests/macros/t14329.nim new file mode 100644 index 0000000000..b5606424ae --- /dev/null +++ b/tests/macros/t14329.nim @@ -0,0 +1,4 @@ +import macros + +macro myMacro(n) = + let x = if true: newLit"test" else: error "error", n