From a9fe618756304a765006a54b3f8f8b1cdae0ffb9 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 4 May 2015 23:59:53 +0200 Subject: [PATCH 1/4] Pass noReturn pragma to C code. With GCC and Clang this generates __attribute__((noreturn)) in the function declaration. (both tested) With VCC __declspec(noreturn) is used. --- compiler/cgen.nim | 5 +++++ compiler/extccomp.nim | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index da9c6f6539..4743e4576c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -676,6 +676,9 @@ proc genProcAux(m: BModule, prc: PSym) = closureSetup(p, prc) genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. var generatedProc: Rope + if sfNoReturn in prc.flags: + if hasNoreturnDeclspec in extccomp.CC[extccomp.cCompiler].props: + header = "__declspec(noreturn) " & header if sfPure in prc.flags: if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props: header = "__declspec(naked) " & header @@ -722,6 +725,8 @@ proc genProcPrototype(m: BModule, sym: PSym) = header = "extern \"C\" " & header if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: header.add(" __attribute__((naked))") + if sfNoReturn in sym.flags and hasNoreturnAttribute in CC[cCompiler].props: + header.add(" __attribute__((noreturn))") add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) proc genProcNoForward(m: BModule, prc: PSym) = diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 26f0318ee2..1bf4eb7574 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -27,7 +27,9 @@ type hasGcGuard, # CC supports GC_GUARD to keep stack roots hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax hasNakedDeclspec, # CC has __declspec(naked) - hasNakedAttribute # CC has __attribute__((naked)) + hasNakedAttribute, # CC has __attribute__((naked)) + hasNoreturnAttribute, # CC has __attribute__((noreturn)) + hasNoreturnDeclspec # CC has __declspec(noreturn) TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -85,7 +87,7 @@ compiler gcc: structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name packedPragma: "__attribute__((__packed__))", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasNakedAttribute}) + hasNakedAttribute, hasNoreturnAttribute}) # LLVM Frontend for GCC/G++ compiler llvmGcc: @@ -127,7 +129,7 @@ compiler vcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", packedPragma: "#pragma pack(1)", - props: {hasCpp, hasAssume, hasNakedDeclspec}) + props: {hasCpp, hasAssume, hasNakedDeclspec, hasNoreturnDeclspec}) # Intel C/C++ Compiler compiler icl: From c5db4fc3a27b17cc20fc13de0a325c126e612c16 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 5 May 2015 20:24:54 +0200 Subject: [PATCH 2/4] Move the noreturn pragma to sysFatal Now you can choose to implement sysFatal with --os:standalone so that it returns. --- lib/system.nim | 19 ++++++++++--------- lib/system/arithm.nim | 8 ++++---- lib/system/chcks.nim | 6 +++--- tests/manyloc/standalone/panicoverride.nim | 6 +++--- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index ca4c814110..1e6f76f3df 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1110,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int ## prematurely using ``quit``, this value is ignored. proc quit*(errorcode: int = QuitSuccess) {. - magic: "Exit", importc: "exit", header: "", noReturn.} + magic: "Exit", importc: "exit", header: "", noreturn.} ## Stops the program immediately with an exit code. ## ## Before stopping the program the "quit procedures" are called in the @@ -2270,20 +2270,21 @@ when hostOS == "standalone": include panicoverride when not declared(sysFatal): - template sysFatal(exceptn: typedesc, message: string) = - when hostOS == "standalone": + when hostOS == "standalone": + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = panic(message) - else: + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + rawoutput(message) + panic(arg) + else: + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message raise e - template sysFatal(exceptn: typedesc, message, arg: string) = - when hostOS == "standalone": - rawoutput(message) - panic(arg) - else: + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message & arg diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index f68e2dcd9f..ef153417c0 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -10,11 +10,11 @@ # simple integer arithmetic with overflow checking -proc raiseOverflow {.compilerproc, noinline, noreturn.} = +proc raiseOverflow {.compilerproc, noinline.} = # a single proc to reduce code size to a minimum sysFatal(OverflowError, "over- or underflow") -proc raiseDivByZero {.compilerproc, noinline, noreturn.} = +proc raiseDivByZero {.compilerproc, noinline.} = sysFatal(DivByZeroError, "division by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = @@ -327,13 +327,13 @@ when not declared(mulInt): # We avoid setting the FPU control word here for compatibility with libraries # written in other languages. -proc raiseFloatInvalidOp {.noinline, noreturn.} = +proc raiseFloatInvalidOp {.noinline.} = sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") proc nanCheck(x: float64) {.compilerProc, inline.} = if x != x: raiseFloatInvalidOp() -proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} = +proc raiseFloatOverflow(x: float64) {.noinline.} = if x > 0.0: sysFatal(FloatOverflowError, "FPU operation caused an overflow") else: diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 2f6d25a129..6caf99d27b 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -9,16 +9,16 @@ # Implementation of some runtime checks. -proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} = +proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": sysFatal(RangeError, "value out of range") else: sysFatal(RangeError, "value out of range: ", $val) -proc raiseIndexError() {.compilerproc, noreturn, noinline.} = +proc raiseIndexError() {.compilerproc, noinline.} = sysFatal(IndexError, "index out of bounds") -proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = +proc raiseFieldError(f: string) {.compilerproc, noinline.} = sysFatal(FieldError, f, " is not accessible") proc chckIndx(i, a, b: int): int = diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index efd2b21f95..d9b3f43886 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "", cdecl.} proc rawoutput(s: string) = printf("%s\n", s) -proc panic(s: string) = +proc panic(s: string) {.noreturn.} = rawoutput(s) exit(1) # Alternatively we also could implement these 2 here: # -# template sysFatal(exceptn: typeDesc, message: string) -# template sysFatal(exceptn: typeDesc, message, arg: string) +# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.} +# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.} {.pop.} From 78c26cbf18cf1c39964ce32a4991ea4f997a980e Mon Sep 17 00:00:00 2001 From: def Date: Tue, 5 May 2015 20:35:43 +0200 Subject: [PATCH 3/4] Distinguish only between __declspec and __attribute__ --- compiler/cgen.nim | 8 ++++---- compiler/extccomp.nim | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 4743e4576c..8e532739b3 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -677,10 +677,10 @@ proc genProcAux(m: BModule, prc: PSym) = genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. var generatedProc: Rope if sfNoReturn in prc.flags: - if hasNoreturnDeclspec in extccomp.CC[extccomp.cCompiler].props: + if {hasNoreturn, hasDeclspec} <= extccomp.CC[extccomp.cCompiler].props: header = "__declspec(noreturn) " & header if sfPure in prc.flags: - if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props: + if {hasNaked, hasDeclspec} <= extccomp.CC[extccomp.cCompiler].props: header = "__declspec(naked) " & header generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N", header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) @@ -723,9 +723,9 @@ proc genProcPrototype(m: BModule, sym: PSym) = var header = genProcHeader(m, sym) if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): header = "extern \"C\" " & header - if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: + if sfPure in sym.flags and {hasNaked, hasAttribute} <= CC[cCompiler].props: header.add(" __attribute__((naked))") - if sfNoReturn in sym.flags and hasNoreturnAttribute in CC[cCompiler].props: + if sfNoReturn in sym.flags and {hasNoreturn, hasAttribute} <= CC[cCompiler].props: header.add(" __attribute__((noreturn))") add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 1bf4eb7574..3d4d1a3a52 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -26,10 +26,10 @@ type hasAssume, # CC has __assume (Visual C extension) hasGcGuard, # CC supports GC_GUARD to keep stack roots hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax - hasNakedDeclspec, # CC has __declspec(naked) - hasNakedAttribute, # CC has __attribute__((naked)) - hasNoreturnAttribute, # CC has __attribute__((noreturn)) - hasNoreturnDeclspec # CC has __declspec(noreturn) + hasDeclspec, # CC has __declspec(X) + hasAttribute, # CC has __attribute__((X)) + hasNaked, # CC has naked declspec/attribute + hasNoreturn # CC has noreturn declspec/attribute TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -87,7 +87,7 @@ compiler gcc: structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name packedPragma: "__attribute__((__packed__))", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasNakedAttribute, hasNoreturnAttribute}) + hasAttribute, hasNaked, hasNoreturn}) # LLVM Frontend for GCC/G++ compiler llvmGcc: @@ -129,7 +129,7 @@ compiler vcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", packedPragma: "#pragma pack(1)", - props: {hasCpp, hasAssume, hasNakedDeclspec, hasNoreturnDeclspec}) + props: {hasCpp, hasAssume, hasDeclspec, hasNaked, hasNoreturn}) # Intel C/C++ Compiler compiler icl: From 4a2a0894aee91fac027f9d0cce401bf5c9dc353b Mon Sep 17 00:00:00 2001 From: def Date: Thu, 7 May 2015 22:31:45 +0200 Subject: [PATCH 4/4] Implicitly assume compilers to know naked and noreturn attributes --- compiler/cgen.nim | 8 ++++---- compiler/extccomp.nim | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 8e532739b3..4b0bac28ad 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -677,10 +677,10 @@ proc genProcAux(m: BModule, prc: PSym) = genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. var generatedProc: Rope if sfNoReturn in prc.flags: - if {hasNoreturn, hasDeclspec} <= extccomp.CC[extccomp.cCompiler].props: + if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: header = "__declspec(noreturn) " & header if sfPure in prc.flags: - if {hasNaked, hasDeclspec} <= extccomp.CC[extccomp.cCompiler].props: + if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: header = "__declspec(naked) " & header generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N", header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) @@ -723,9 +723,9 @@ proc genProcPrototype(m: BModule, sym: PSym) = var header = genProcHeader(m, sym) if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): header = "extern \"C\" " & header - if sfPure in sym.flags and {hasNaked, hasAttribute} <= CC[cCompiler].props: + if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((naked))") - if sfNoReturn in sym.flags and {hasNoreturn, hasAttribute} <= CC[cCompiler].props: + if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((noreturn))") add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 3d4d1a3a52..31b03f418c 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -28,8 +28,6 @@ type hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax hasDeclspec, # CC has __declspec(X) hasAttribute, # CC has __attribute__((X)) - hasNaked, # CC has naked declspec/attribute - hasNoreturn # CC has noreturn declspec/attribute TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -87,7 +85,7 @@ compiler gcc: structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name packedPragma: "__attribute__((__packed__))", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasAttribute, hasNaked, hasNoreturn}) + hasAttribute}) # LLVM Frontend for GCC/G++ compiler llvmGcc: @@ -129,7 +127,7 @@ compiler vcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", packedPragma: "#pragma pack(1)", - props: {hasCpp, hasAssume, hasDeclspec, hasNaked, hasNoreturn}) + props: {hasCpp, hasAssume, hasDeclspec}) # Intel C/C++ Compiler compiler icl: