nitc: add `add_raw_throw` so raw_abortions are caught
[nit.git] / src / compiler / abstract_compiler.nit
index 8bdfdee..9ec830a 100644 (file)
@@ -349,14 +349,21 @@ class MakefileToolchain
                end
                var debug = toolcontext.opt_debug.value
 
-               makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g{ if not debug then " -O2 " else " "}-Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
+               makefile.write """
+CC ?= ccache cc
+CXX ?= ccache c++
+CFLAGS ?= -g {{{if not debug then "-O2" else ""}}} -Wno-unused-value -Wno-switch -Wno-attributes -Wno-trigraphs
+CINCL =
+LDFLAGS ?=
+LDLIBS  ?= -lm {{{linker_options.join(" ")}}}
+\n"""
 
                makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
                if platform.supports_libunwind then
                        if toolcontext.opt_no_stacktrace.value then
-                               makefile.write "NO_STACKTRACE=True"
+                               makefile.write "NO_STACKTRACE ?= True"
                        else
-                               makefile.write "NO_STACKTRACE= # Set to `True` to enable"
+                               makefile.write "NO_STACKTRACE ?= # Set to `True` to enable"
                        end
                end
 
@@ -404,12 +411,15 @@ ifeq ($(uname_S),Darwin)
 endif
 
 # Special configuration for Windows under mingw64
-ifeq ($(uname_S),MINGW64_NT-10.0)
+ifneq ($(findstring MINGW64,$(uname_S)),)
        # Use the pcreposix regex library
        LDLIBS += -lpcreposix
 
        # Remove POSIX flag -lrt
        LDLIBS := $(filter-out -lrt,$(LDLIBS))
+
+       # Silence warnings when storing Int, Char and Bool as pointer address
+       CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast
 endif
 
 """
@@ -1440,7 +1450,7 @@ abstract class AbstractCompilerVisitor
        # Checks
 
        # Can value be null? (according to current knowledge)
-       fun maybenull(value: RuntimeVariable): Bool
+       fun maybe_null(value: RuntimeVariable): Bool
        do
                return value.mcasttype isa MNullableType or value.mcasttype isa MNullType
        end
@@ -1450,7 +1460,7 @@ abstract class AbstractCompilerVisitor
        do
                if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
 
-               if maybenull(recv) then
+               if maybe_null(recv) then
                        self.add("if (unlikely({recv} == NULL)) \{")
                        self.add_abort("Receiver is null")
                        self.add("\}")
@@ -1621,7 +1631,7 @@ abstract class AbstractCompilerVisitor
        fun int8_instance(value: Int8): RuntimeVariable
        do
                var t = mmodule.int8_type
-               var res = new RuntimeVariable("((int8_t){value.to_s})", t, t)
+               var res = new RuntimeVariable("INT8_C({value.to_s})", t, t)
                return res
        end
 
@@ -1629,7 +1639,7 @@ abstract class AbstractCompilerVisitor
        fun int16_instance(value: Int16): RuntimeVariable
        do
                var t = mmodule.int16_type
-               var res = new RuntimeVariable("((int16_t){value.to_s})", t, t)
+               var res = new RuntimeVariable("INT16_C({value.to_s})", t, t)
                return res
        end
 
@@ -1637,7 +1647,7 @@ abstract class AbstractCompilerVisitor
        fun uint16_instance(value: UInt16): RuntimeVariable
        do
                var t = mmodule.uint16_type
-               var res = new RuntimeVariable("((uint16_t){value.to_s})", t, t)
+               var res = new RuntimeVariable("UINT16_C({value.to_s})", t, t)
                return res
        end
 
@@ -1645,7 +1655,7 @@ abstract class AbstractCompilerVisitor
        fun int32_instance(value: Int32): RuntimeVariable
        do
                var t = mmodule.int32_type
-               var res = new RuntimeVariable("((int32_t){value.to_s})", t, t)
+               var res = new RuntimeVariable("INT32_C({value.to_s})", t, t)
                return res
        end
 
@@ -1653,7 +1663,7 @@ abstract class AbstractCompilerVisitor
        fun uint32_instance(value: UInt32): RuntimeVariable
        do
                var t = mmodule.uint32_type
-               var res = new RuntimeVariable("((uint32_t){value.to_s})", t, t)
+               var res = new RuntimeVariable("UINT32_C({value.to_s})", t, t)
                return res
        end
 
@@ -1815,17 +1825,30 @@ abstract class AbstractCompilerVisitor
        # used by aborts, asserts, casts, etc.
        fun add_abort(message: String)
        do
+               add_raw_throw
+               self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
+               add_raw_abort
+       end
+
+       # Generate a long jump if there is a catch block.
+       #
+       # This method should be called before the error messages and before a `add_raw_abort`.
+       fun add_raw_throw
+       do
                self.add("if(catchStack.cursor >= 0)\{")
                self.add("longjmp(catchStack.envs[catchStack.cursor], 1);")
                self.add("\}")
-               self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
-               add_raw_abort
        end
 
+       # Generate abort without a message.
+       #
+       # Used when one need a more complex message.
+       # Do not forget to call `add_raw_abort` before the display of a custom user message.
        fun add_raw_abort
        do
-               if self.current_node != null and self.current_node.location.file != null and
-                               self.current_node.location.file.mmodule != null then
+               var current_node = self.current_node
+               if current_node != null and current_node.location.file != null and
+                               current_node.location.file.mmodule != null then
                        var f = "FILE_{self.current_node.location.file.mmodule.c_name}"
                        self.require_declaration(f)
                        self.add("PRINT_ERROR(\" (%s:%d)\\n\", {f}, {current_node.location.line_start});")
@@ -1840,6 +1863,7 @@ abstract class AbstractCompilerVisitor
        do
                var res = self.type_test(value, mtype, tag)
                self.add("if (unlikely(!{res})) \{")
+               self.add_raw_throw
                var cn = self.class_name_string(value)
                self.add("PRINT_ERROR(\"Runtime error: Cast failed. Expected `%s`, got `%s`\", \"{mtype.to_s.escape_to_c}\", {cn});")
                self.add_raw_abort
@@ -2169,6 +2193,7 @@ redef class MMethodDef
                var node = modelbuilder.mpropdef2node(self)
 
                if is_abstract then
+                       v.add_raw_throw
                        var cn = v.class_name_string(arguments.first)
                        v.current_node = node
                        v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mproperty.name.escape_to_c}\", {cn});")
@@ -2280,6 +2305,7 @@ redef class AMethPropdef
                end
 
                # We have a problem
+               v.add_raw_throw
                var cn = v.class_name_string(arguments.first)
                v.add("PRINT_ERROR(\"Runtime error: uncompiled method `%s` called on `%s`. NOT YET IMPLEMENTED\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
                v.add_raw_abort
@@ -2623,10 +2649,10 @@ redef class AMethPropdef
                                v.ret(v.new_expr("(char*){alloc}", ret.as(not null)))
                                return true
                        else if pname == "fetch_4_chars" then
-                               v.ret(v.new_expr("(long)*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null)))
+                               v.ret(v.new_expr("*((uint32_t*)({arguments[0]} + {arguments[1]}))", ret.as(not null)))
                                return true
                        else if pname == "fetch_4_hchars" then
-                               v.ret(v.new_expr("(long)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t)be32toh(*((uint32_t*)({arguments[0]} + {arguments[1]})))", ret.as(not null)))
                                return true
                        end
                else if cname == "NativeArray" then
@@ -3068,7 +3094,7 @@ redef class AMethPropdef
                        end
                end
                if pname == "exit" then
-                       v.add("exit({arguments[1]});")
+                       v.add("exit((int){arguments[1]});")
                        return true
                else if pname == "sys" then
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
@@ -3201,7 +3227,7 @@ redef class AAttrPropdef
                        assert arguments.length == 2
                        var recv = arguments.first
                        var arg = arguments[1]
-                       if is_optional and v.maybenull(arg) then
+                       if is_optional and v.maybe_null(arg) then
                                var value = v.new_var(self.mpropdef.static_mtype.as(not null))
                                v.add("if ({arg} == NULL) \{")
                                v.assign(value, evaluate_expr(v, recv))
@@ -3635,7 +3661,7 @@ redef class AOrElseExpr
                var res = v.new_var(self.mtype.as(not null))
                var i1 = v.expr(self.n_expr, null)
 
-               if not v.maybenull(i1) then return i1
+               if not v.maybe_null(i1) then return i1
 
                v.add("if ({i1}!=NULL) \{")
                v.assign(res, i1)
@@ -3888,7 +3914,7 @@ redef class AAsNotnullExpr
                var i = v.expr(self.n_expr, null)
                if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
 
-               if not v.maybenull(i) then return i
+               if not v.maybe_null(i) then return i
 
                v.add("if (unlikely({i} == NULL)) \{")
                v.add_abort("Cast failed")