瀏覽代碼

Remove overflow flag

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 年之前
父節點
當前提交
1ba694bc16

+ 1 - 2
docs/language/expressions.rst

@@ -34,8 +34,7 @@ x :superscript:`y`. This can only be done for unsigned types.
   uint64 thousand = 1000;
   uint64 billion = thousand ** 3;
 
-Overflow checking is limited to types of 64 bits and smaller, if the `--math-overflow` command
-line argument is specified. No overflow checking is generated in `unchecked` blocks, like so:
+No overflow checking is generated in `unchecked` blocks, like so:
 
 .. include:: ../examples/expression_unchecked.sol
   :code: solidity

+ 2 - 2
integration/solana/package.json

@@ -4,7 +4,7 @@
   "description": "Integration tests with Solang and Solana",
   "scripts": {
     "test": "tsc; ts-node setup.ts; mocha --parallel *.spec.ts",
-    "build": "solang compile *.sol --target solana -v --log-runtime-errors --math-overflow"
+    "build": "solang compile *.sol --target solana -v --log-runtime-errors"
   },
   "author": "Sean Young <sean@mess.org>",
   "license": "MIT",
@@ -26,4 +26,4 @@
     "web3-eth-abi": "^1.3.0",
     "web3-utils": "^1.3.0"
   }
-}
+}

+ 2 - 2
integration/substrate/build.sh

@@ -1,11 +1,11 @@
 #!/bin/bash
-set -e 
+set -e
 
 dup_contracts=$(grep -r '^contract .* {' | awk '{ print $2 }' | sort | uniq -d)
 if [[ $dup_contracts ]]; then
 	echo "Found contract with duplicate names: ${dup_contracts}"
 	/bin/false
 else
-	parallel solang compile -v -g --target substrate --log-runtime-errors --math-overflow --log-api-return-codes ::: *.sol test/*.sol
+	parallel solang compile -v -g --target substrate --log-runtime-errors --log-api-return-codes ::: *.sol test/*.sol
 fi
 

+ 0 - 10
src/bin/solang.rs

@@ -179,13 +179,6 @@ fn main() {
                             .action(ArgAction::SetFalse)
                             .display_order(5),
                     )
-                    .arg(
-                        Arg::new("MATHOVERFLOW")
-                            .help("Enable math overflow checking")
-                            .long("math-overflow")
-                            .action(ArgAction::SetTrue)
-                            .display_order(6),
-                    )
                     .arg(
                         Arg::new("LOGAPIRETURNS")
                             .help("Log the return codes of runtime API calls in the environment")
@@ -403,8 +396,6 @@ fn compile(matches: &ArgMatches) {
         eprintln!("info: Solang version {}", env!("SOLANG_VERSION"));
     }
 
-    let math_overflow_check = *matches.get_one("MATHOVERFLOW").unwrap();
-
     let generate_debug_info = *matches.get_one("GENERATEDEBUGINFORMATION").unwrap();
 
     let log_api_return_codes = *matches.get_one("LOGAPIRETURNS").unwrap();
@@ -426,7 +417,6 @@ fn compile(matches: &ArgMatches) {
         constant_folding: *matches.get_one("CONSTANTFOLDING").unwrap(),
         strength_reduce: *matches.get_one("STRENGTHREDUCE").unwrap(),
         vector_to_slice: *matches.get_one("VECTORTOSLICE").unwrap(),
-        math_overflow_check,
         generate_debug_information: generate_debug_info,
         common_subexpression_elimination: *matches
             .get_one("COMMONSUBEXPRESSIONELIMINATION")

+ 2 - 1
src/codegen/encoding/borsh_encoding.rs

@@ -35,10 +35,11 @@ impl AbiEncoding for BorshEncoding {
         expr: &Expression,
         buffer: &Expression,
         offset: &Expression,
+        ns: &Namespace,
         vartab: &mut Vartable,
         cfg: &mut ControlFlowGraph,
     ) -> Expression {
-        self.encode_int(expr, buffer, offset, vartab, cfg, 32)
+        self.encode_int(expr, buffer, offset, ns, vartab, cfg, 32)
     }
 
     fn encode_external_function(

+ 10 - 6
src/codegen/encoding/mod.rs

@@ -173,7 +173,7 @@ pub(super) trait AbiEncoding {
             }
             Type::Bool => self.encode_directly(expr, buffer, offset, vartab, cfg, 1.into()),
             Type::Uint(width) | Type::Int(width) => {
-                self.encode_int(expr, buffer, offset, vartab, cfg, *width)
+                self.encode_int(expr, buffer, offset, ns, vartab, cfg, *width)
             }
             Type::Value => {
                 let size = ns.value_length.into();
@@ -183,7 +183,7 @@ pub(super) trait AbiEncoding {
                 self.encode_directly(expr, buffer, offset, vartab, cfg, (*length).into())
             }
             Type::String | Type::DynamicBytes => {
-                self.encode_bytes(expr, buffer, offset, vartab, cfg)
+                self.encode_bytes(expr, buffer, offset, ns, vartab, cfg)
             }
             Type::Enum(_) => self.encode_directly(expr, buffer, offset, vartab, cfg, 1.into()),
             Type::Struct(ty) => {
@@ -263,13 +263,14 @@ pub(super) trait AbiEncoding {
         expr: &Expression,
         buffer: &Expression,
         offset: &Expression,
+        ns: &Namespace,
         vartab: &mut Vartable,
         cfg: &mut ControlFlowGraph,
         width: u16,
     ) -> Expression {
         let encoding_size = width.next_power_of_two();
         let expr = if encoding_size != width {
-            if expr.ty().is_signed_int() {
+            if expr.ty().is_signed_int(ns) {
                 Expression::SignExt(Codegen, Type::Int(encoding_size), expr.clone().into())
             } else {
                 Expression::ZeroExt(Codegen, Type::Uint(encoding_size), expr.clone().into())
@@ -296,6 +297,7 @@ pub(super) trait AbiEncoding {
         expr: &Expression,
         buffer: &Expression,
         offset: &Expression,
+        ns: &Namespace,
         vartab: &mut Vartable,
         cfg: &mut ControlFlowGraph,
     ) -> Expression;
@@ -306,6 +308,7 @@ pub(super) trait AbiEncoding {
         expr: &Expression,
         buffer: &Expression,
         offset: &Expression,
+        ns: &Namespace,
         vartab: &mut Vartable,
         cfg: &mut ControlFlowGraph,
     ) -> Expression {
@@ -313,7 +316,7 @@ pub(super) trait AbiEncoding {
         let (data_offset, size) = if self.is_packed() {
             (offset.clone(), None)
         } else {
-            let size = self.encode_size(&len, buffer, offset, vartab, cfg);
+            let size = self.encode_size(&len, buffer, offset, ns, vartab, cfg);
             (offset.clone().add_u32(size.clone()), Some(size))
         };
         // ptr + offset + size_of_integer
@@ -432,7 +435,8 @@ pub(super) trait AbiEncoding {
                     let (new_offset, size_length) = if self.is_packed() {
                         (offset.clone(), None)
                     } else {
-                        let encoded_size = self.encode_size(&value, buffer, offset, vartab, cfg);
+                        let encoded_size =
+                            self.encode_size(&value, buffer, offset, ns, vartab, cfg);
                         (
                             offset.clone().add_u32(encoded_size.clone()),
                             Some(encoded_size),
@@ -541,7 +545,7 @@ pub(super) trait AbiEncoding {
             );
 
             let offset_expr = Expression::Variable(Codegen, Uint(32), offset_var);
-            let encoded_size = self.encode_size(&size, buffer, &offset_expr, vartab, cfg);
+            let encoded_size = self.encode_size(&size, buffer, &offset_expr, ns, vartab, cfg);
             cfg.add(
                 vartab,
                 Instr::Set {

+ 1 - 0
src/codegen/encoding/scale_encoding.rs

@@ -363,6 +363,7 @@ impl AbiEncoding for ScaleEncoding {
         expr: &Expression,
         buffer: &Expression,
         offset: &Expression,
+        _ns: &Namespace,
         vartab: &mut Vartable,
         cfg: &mut ControlFlowGraph,
     ) -> Expression {

+ 7 - 6
src/codegen/expression.rs

@@ -123,7 +123,7 @@ pub fn expression(
         } => {
             let l = expression(left, cfg, contract_no, func, ns, vartab, opt);
             let r = expression(right, cfg, contract_no, func, ns, vartab, opt);
-            if ty.is_signed_int() {
+            if ty.is_signed_int(ns) {
                 Expression::SignedDivide(*loc, ty.clone(), Box::new(l), Box::new(r))
             } else {
                 Expression::UnsignedDivide(*loc, ty.clone(), Box::new(l), Box::new(r))
@@ -137,7 +137,7 @@ pub fn expression(
         } => {
             let l = expression(left, cfg, contract_no, func, ns, vartab, opt);
             let r = expression(right, cfg, contract_no, func, ns, vartab, opt);
-            if ty.is_signed_int() {
+            if ty.is_signed_int(ns) {
                 Expression::SignedModulo(*loc, ty.clone(), Box::new(l), Box::new(r))
             } else {
                 Expression::UnsignedModulo(*loc, ty.clone(), Box::new(l), Box::new(r))
@@ -226,16 +226,17 @@ pub fn expression(
         ast::Expression::More { loc, left, right } => {
             let l = expression(left, cfg, contract_no, func, ns, vartab, opt);
             let r = expression(right, cfg, contract_no, func, ns, vartab, opt);
+
             Expression::More {
                 loc: *loc,
-                signed: l.ty().is_signed_int(),
+                signed: l.ty().is_signed_int(ns),
                 left: Box::new(l),
                 right: Box::new(r),
             }
         }
         ast::Expression::MoreEqual { loc, left, right } => Expression::MoreEqual {
             loc: *loc,
-            signed: left.ty().is_signed_int(),
+            signed: left.ty().is_signed_int(ns),
             left: Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
             right: Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
         },
@@ -244,14 +245,14 @@ pub fn expression(
             let r = expression(right, cfg, contract_no, func, ns, vartab, opt);
             Expression::Less {
                 loc: *loc,
-                signed: l.ty().is_signed_int(),
+                signed: l.ty().is_signed_int(ns),
                 left: Box::new(l),
                 right: Box::new(r),
             }
         }
         ast::Expression::LessEqual { loc, left, right } => Expression::LessEqual {
             loc: *loc,
-            signed: left.ty().is_signed_int(),
+            signed: left.ty().is_signed_int(ns),
             left: Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)),
             right: Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)),
         },

+ 4 - 6
src/codegen/mod.rs

@@ -86,7 +86,6 @@ pub struct Options {
     pub constant_folding: bool,
     pub strength_reduce: bool,
     pub vector_to_slice: bool,
-    pub math_overflow_check: bool,
     pub common_subexpression_elimination: bool,
     pub generate_debug_information: bool,
     pub opt_level: OptimizationLevel,
@@ -101,7 +100,6 @@ impl Default for Options {
             constant_folding: true,
             strength_reduce: true,
             vector_to_slice: true,
-            math_overflow_check: false,
             common_subexpression_elimination: true,
             generate_debug_information: false,
             opt_level: OptimizationLevel::Default,
@@ -804,7 +802,7 @@ impl Expression {
             },
 
             (Type::Uint(from_len), Type::Address(_)) | (Type::Int(from_len), Type::Address(_)) => {
-                let address_to_int = if from.is_signed_int() {
+                let address_to_int = if from.is_signed_int(ns) {
                     Type::Int(address_bits)
                 } else {
                     Type::Uint(address_bits)
@@ -814,7 +812,7 @@ impl Expression {
                     Ordering::Greater => {
                         Expression::Trunc(self.loc(), address_to_int, Box::new(self.clone()))
                     }
-                    Ordering::Less if from.is_signed_int() => {
+                    Ordering::Less if from.is_signed_int(ns) => {
                         Expression::ZeroExt(self.loc(), to.clone(), Box::new(self.clone()))
                     }
                     Ordering::Less => {
@@ -826,7 +824,7 @@ impl Expression {
                 Expression::Cast(self.loc(), to.clone(), Box::new(expr))
             }
             (Type::Address(_), Type::Uint(to_len)) | (Type::Address(_), Type::Int(to_len)) => {
-                let address_to_int = if to.is_signed_int() {
+                let address_to_int = if to.is_signed_int(ns) {
                     Type::Int(address_bits)
                 } else {
                     Type::Uint(address_bits)
@@ -837,7 +835,7 @@ impl Expression {
                 // now resize int to request size with sign extension etc
                 match to_len.cmp(&address_bits) {
                     Ordering::Less => Expression::Trunc(self.loc(), to.clone(), Box::new(expr)),
-                    Ordering::Greater if to.is_signed_int() => {
+                    Ordering::Greater if to.is_signed_int(ns) => {
                         Expression::ZeroExt(self.loc(), to.clone(), Box::new(expr))
                     }
                     Ordering::Greater => {

+ 3 - 3
src/codegen/strength_reduce/expression_values.rs

@@ -377,7 +377,7 @@ fn multiply_values(
         .map(|(l, r)| {
             let mut known_bits = BitArray::new([0u8; 32]);
 
-            if ty.is_signed_int() {
+            if ty.is_signed_int(ns) {
                 match (l.sign(), r.sign()) {
                     ((true, left_sign), (true, right_sign)) => {
                         let left = if left_sign {
@@ -706,7 +706,7 @@ fn equal_values(
             let mut known_bits = BitArray::new([0u8; 32]);
             let mut value = BitArray::new([0u8; 32]);
 
-            let could_be_equal = if left_expr.ty().is_signed_int() {
+            let could_be_equal = if left_expr.ty().is_signed_int(ns) {
                 BigInt::from_signed_bytes_le(&l.get_signed_min_value().into_inner())
                     >= BigInt::from_signed_bytes_le(&r.get_signed_max_value().into_inner())
                     && BigInt::from_signed_bytes_le(&l.get_signed_min_value().into_inner())
@@ -747,7 +747,7 @@ fn not_equal_values(
             let mut known_bits = BitArray::new([0u8; 32]);
             let mut value = BitArray::new([0u8; 32]);
 
-            let could_be_equal = if left_expr.ty().is_signed_int() {
+            let could_be_equal = if left_expr.ty().is_signed_int(ns) {
                 BigInt::from_signed_bytes_le(&l.get_signed_min_value().into_inner())
                     >= BigInt::from_signed_bytes_le(&r.get_signed_max_value().into_inner())
                     && BigInt::from_signed_bytes_le(&l.get_signed_min_value().into_inner())

+ 4 - 4
src/codegen/strength_reduce/mod.rs

@@ -255,7 +255,7 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                         }
                     }
 
-                    if ty.is_signed_int() {
+                    if ty.is_signed_int(ns) {
                         if let (Some(left_max), Some(right_max)) =
                             (set_max_signed(&left_values), set_max_signed(&right_values))
                         {
@@ -343,7 +343,7 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                                     ty.clone(),
                                     left.clone(),
                                     Box::new(Expression::NumberLiteral(*loc, ty.clone(), shift)),
-                                    ty.is_signed_int(),
+                                    ty.is_signed_int(ns),
                                 );
                             }
 
@@ -352,7 +352,7 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                         }
                     }
 
-                    if ty.is_signed_int() {
+                    if ty.is_signed_int(ns) {
                         if let (Some(left_max), Some(right_max)) =
                             (set_max_signed(&left_values), set_max_signed(&right_values))
                         {
@@ -441,7 +441,7 @@ fn expression_reduce(expr: &Expression, vars: &Variables, ns: &mut Namespace) ->
                         }
                     }
 
-                    if ty.is_signed_int() {
+                    if ty.is_signed_int(ns) {
                         if let (Some(left_max), Some(right_max)) =
                             (set_max_signed(&left_values), set_max_signed(&right_values))
                         {

+ 7 - 7
src/emit/expression.rs

@@ -121,8 +121,8 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             let left = expression(target, bin, l, vartab, function, ns).into_int_value();
             let right = expression(target, bin, r, vartab, function, ns).into_int_value();
 
-            if bin.options.math_overflow_check && !*unchecked {
-                let signed = l.ty().is_signed_int();
+            if !unchecked {
+                let signed = l.ty().is_signed_int(ns);
                 build_binary_op_with_overflow_check(
                     target,
                     bin,
@@ -143,8 +143,8 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             let left = expression(target, bin, l, vartab, function, ns).into_int_value();
             let right = expression(target, bin, r, vartab, function, ns).into_int_value();
 
-            if bin.options.math_overflow_check && !*unchecked {
-                let signed = l.ty().is_signed_int();
+            if !unchecked {
+                let signed = l.ty().is_signed_int(ns);
                 build_binary_op_with_overflow_check(
                     target,
                     bin,
@@ -172,7 +172,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 *unchecked,
                 left,
                 right,
-                res_ty.is_signed_int(),
+                res_ty.is_signed_int(ns),
                 ns,
                 *loc,
             )
@@ -653,7 +653,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
                 bin,
                 *unchecked,
                 bits,
-                res_ty.is_signed_int(),
+                res_ty.is_signed_int(ns),
                 o,
                 ns,
                 *loc,
@@ -670,7 +670,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
             // Load the result pointer
             let res = bin.builder.build_load(left.get_type(), o, "");
 
-            if !bin.options.math_overflow_check || *unchecked || ns.target != Target::Solana {
+            if *unchecked || ns.target.is_substrate() {
                 // In Substrate, overflow case will hit an unreachable expression, so no additional checks are needed.
                 res
             } else {

+ 2 - 2
src/emit/math.rs

@@ -283,7 +283,7 @@ pub(super) fn multiply<'a, T: TargetRuntime<'a> + ?Sized>(
                 .build_store(r, bin.builder.build_int_z_extend(right, mul_ty, ""));
         }
 
-        if bin.options.math_overflow_check && !unchecked {
+        if !unchecked {
             if signed {
                 return signed_ovf_detect(
                     target, bin, mul_ty, mul_bits, left, right, bits, function, ns, loc,
@@ -375,7 +375,7 @@ pub(super) fn multiply<'a, T: TargetRuntime<'a> + ?Sized>(
         } else {
             return call_mul32_without_ovf(bin, l, r, o, mul_bits, mul_ty, left.get_type());
         }
-    } else if bin.options.math_overflow_check && !unchecked {
+    } else if !unchecked {
         build_binary_op_with_overflow_check(
             target,
             bin,

+ 1 - 1
src/emit/substrate/mod.rs

@@ -899,7 +899,7 @@ impl SubstrateTarget {
 
                 let arg = if len == power_of_two_len {
                     arg.into_int_value()
-                } else if ty.is_signed_int() {
+                } else if ty.is_signed_int(ns) {
                     binary.builder.build_int_s_extend(
                         arg.into_int_value(),
                         binary

+ 0 - 2
src/lib.rs

@@ -122,13 +122,11 @@ pub fn compile(
     resolver: &mut FileResolver,
     opt_level: inkwell::OptimizationLevel,
     target: Target,
-    math_overflow_check: bool,
     log_api_return_codes: bool,
     log_runtime_errors: bool,
 ) -> (Vec<(Vec<u8>, String)>, sema::ast::Namespace) {
     let mut ns = parse_and_resolve(filename, resolver, target);
     let opts = codegen::Options {
-        math_overflow_check,
         log_api_return_codes,
         opt_level: opt_level.into(),
         log_runtime_errors,

+ 7 - 7
src/sema/expression/arithmetic.rs

@@ -262,7 +262,7 @@ pub(super) fn shift_right(
         ty: left_type.clone(),
         left: Box::new(left.cast(loc, &left_type, true, ns, diagnostics)?),
         right: Box::new(cast_shift_arg(loc, right, right_length, &left_type, ns)),
-        sign: left_type.is_signed_int(),
+        sign: left_type.is_signed_int(ns),
     })
 }
 
@@ -324,7 +324,7 @@ pub(super) fn multiply(
     if resolve_to == ResolveTo::Unknown {
         let bits = std::cmp::min(256, ty.bits(ns) * 2);
 
-        if ty.is_signed_int() {
+        if ty.is_signed_int(ns) {
             multiply(
                 loc,
                 l,
@@ -461,7 +461,7 @@ pub(super) fn power(
     // If we don't know what type the result is going to be, assume
     // the result is 256 bits
     if resolve_to == ResolveTo::Unknown {
-        if base.ty().is_signed_int() {
+        if base.ty().is_signed_int(ns) {
             base = expression(
                 b,
                 context,
@@ -490,7 +490,7 @@ pub(super) fn power(
     let exp_type = exp.ty();
 
     // solc-0.5.13 does not allow either base or exp to be signed
-    if base_type.is_signed_int() || exp_type.is_signed_int() {
+    if base_type.is_signed_int(ns) || exp_type.is_signed_int(ns) {
         diagnostics.push(Diagnostic::error(
             *loc,
             "exponation (**) is not allowed with signed types".to_string(),
@@ -740,7 +740,7 @@ pub(super) fn addition(
     // If we don't know what type the result is going to be
     if resolve_to == ResolveTo::Unknown {
         let bits = std::cmp::min(256, ty.bits(ns) * 2);
-        let resolve_to = if ty.is_signed_int() {
+        let resolve_to = if ty.is_signed_int(ns) {
             Type::Int(bits)
         } else {
             Type::Uint(bits)
@@ -924,13 +924,13 @@ pub fn cast_shift_arg(
 
     if from_width == to_width {
         expr
-    } else if from_width < to_width && ty.is_signed_int() {
+    } else if from_width < to_width && ty.is_signed_int(ns) {
         Expression::SignExt {
             loc: *loc,
             to: ty.clone(),
             expr: Box::new(expr),
         }
-    } else if from_width < to_width && !ty.is_signed_int() {
+    } else if from_width < to_width && !ty.is_signed_int(ns) {
         Expression::ZeroExt {
             loc: *loc,
             to: ty.clone(),

+ 3 - 3
src/sema/expression/assign.rs

@@ -204,13 +204,13 @@ pub(super) fn assign_expr(
                 // TODO: does shifting by negative value need compiletime/runtime check?
                 if left_length == right_length {
                     set
-                } else if right_length < left_length && set_type.is_signed_int() {
+                } else if right_length < left_length && set_type.is_signed_int(ns) {
                     Expression::SignExt {
                         loc: *loc,
                         to: ty.clone(),
                         expr: Box::new(set),
                     }
-                } else if right_length < left_length && !set_type.is_signed_int() {
+                } else if right_length < left_length && !set_type.is_signed_int(ns) {
                     Expression::ZeroExt {
                         loc: *loc,
                         to: ty.clone(),
@@ -278,7 +278,7 @@ pub(super) fn assign_expr(
                 ty: ty.clone(),
                 left: Box::new(assign),
                 right: Box::new(set),
-                sign: ty.is_signed_int(),
+                sign: ty.is_signed_int(ns),
             },
             pt::Expression::AssignDivide(..) => Expression::Divide {
                 loc: *loc,

+ 1 - 1
src/sema/expression/integers.rs

@@ -185,7 +185,7 @@ pub fn bigint_to_expression(
 
     if let ResolveTo::Type(resolve_to) = resolve_to {
         if *resolve_to != Type::Unresolved {
-            if !resolve_to.is_integer() {
+            if !resolve_to.is_integer(ns) {
                 diagnostics.push(Diagnostic::cast_error(
                     *loc,
                     format!("expected '{}', found integer", resolve_to.to_string(ns)),

+ 4 - 4
src/sema/expression/mod.rs

@@ -731,7 +731,7 @@ impl Expression {
                     Err(())
                 } else {
                     // cast integer it to integer of the same size of address with sign ext etc
-                    let address_to_int = if from.is_signed_int() {
+                    let address_to_int = if from.is_signed_int(ns) {
                         Type::Int(address_bits)
                     } else {
                         Type::Uint(address_bits)
@@ -743,7 +743,7 @@ impl Expression {
                             to: address_to_int,
                             expr: Box::new(self.clone()),
                         },
-                        Ordering::Less if from.is_signed_int() => Expression::ZeroExt {
+                        Ordering::Less if from.is_signed_int(ns) => Expression::ZeroExt {
                             loc: *loc,
                             to: address_to_int,
                             expr: Box::new(self.clone()),
@@ -779,7 +779,7 @@ impl Expression {
                     Err(())
                 } else {
                     // first convert address to int/uint
-                    let address_to_int = if to.is_signed_int() {
+                    let address_to_int = if to.is_signed_int(ns) {
                         Type::Int(address_bits)
                     } else {
                         Type::Uint(address_bits)
@@ -797,7 +797,7 @@ impl Expression {
                             to: to.clone(),
                             expr: Box::new(expr),
                         }),
-                        Ordering::Greater if to.is_signed_int() => Ok(Expression::ZeroExt {
+                        Ordering::Greater if to.is_signed_int(ns) => Ok(Expression::ZeroExt {
                             loc: *loc,
                             to: to.clone(),
                             expr: Box::new(expr),

+ 8 - 6
src/sema/types.rs

@@ -1421,23 +1421,25 @@ impl Type {
         }
     }
 
-    pub fn is_signed_int(&self) -> bool {
+    pub fn is_signed_int(&self, ns: &Namespace) -> bool {
         match self {
             Type::Int(_) => true,
-            Type::Ref(r) => r.is_signed_int(),
-            Type::StorageRef(_, r) => r.is_signed_int(),
+            Type::Ref(r) => r.is_signed_int(ns),
+            Type::StorageRef(_, r) => r.is_signed_int(ns),
+            Type::UserType(user) => ns.user_types[*user].ty.is_signed_int(ns),
             _ => false,
         }
     }
 
-    pub fn is_integer(&self) -> bool {
+    pub fn is_integer(&self, ns: &Namespace) -> bool {
         match self {
             Type::Int(_) => true,
             Type::Uint(_) => true,
             Type::Value => true,
             Type::Bytes(1) => true,
-            Type::Ref(r) => r.is_integer(),
-            Type::StorageRef(_, r) => r.is_integer(),
+            Type::Ref(r) => r.is_integer(ns),
+            Type::StorageRef(_, r) => r.is_integer(ns),
+            Type::UserType(user) => ns.user_types[*user].ty.is_integer(ns),
             _ => false,
         }
     }

+ 1 - 1
tests/codegen_testcases/solidity/array_of_struct.sol

@@ -12,7 +12,7 @@ contract c {
         uint64[4] f2;
     }
 
-// BEGIN-CHECK: @"c::c::function::foo__c.S"(ptr %17, ptr %0)
+// BEGIN-CHECK: @"c::c::function::foo__c.S"(ptr %14, ptr %0)
     function foo(S s) public pure {
     }
 }

+ 0 - 1
tests/contract.rs

@@ -67,7 +67,6 @@ fn parse_file(path: PathBuf, target: Target) -> io::Result<()> {
         codegen::codegen(
             &mut ns,
             &codegen::Options {
-                math_overflow_check: false,
                 opt_level: codegen::OptimizationLevel::Default,
                 ..Default::default()
             },

+ 0 - 1
tests/doc_examples.rs

@@ -71,7 +71,6 @@ fn try_compile(path: &str, target: Target) -> Result<(), Diagnostics> {
             constant_folding: true,
             strength_reduce: true,
             vector_to_slice: true,
-            math_overflow_check: true,
             common_subexpression_elimination: true,
             opt_level: OptimizationLevel::Default,
             ..Default::default()

+ 1 - 10
tests/solana.rs

@@ -134,14 +134,6 @@ struct Assign {
 }
 
 fn build_solidity(src: &str) -> VirtualMachine {
-    build_solidity_with_options(src, false, false)
-}
-
-fn build_solidity_with_options(
-    src: &str,
-    math_overflow_flag: bool,
-    log_runtime_errors: bool,
-) -> VirtualMachine {
     let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
@@ -151,9 +143,8 @@ fn build_solidity_with_options(
         &mut cache,
         inkwell::OptimizationLevel::Default,
         Target::Solana,
-        math_overflow_flag,
         false,
-        log_runtime_errors,
+        true,
     );
 
     ns.print_diagnostics_in_plain(&cache, false);

+ 29 - 16
tests/solana_tests/primitives.rs

@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: Apache-2.0
 
-use crate::build_solidity_with_options;
 use crate::{build_solidity, BorshToken};
 use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
 use num_traits::{One, ToPrimitive, Zero};
@@ -359,30 +358,38 @@ fn uint() {
             }
 
             function add(uintN a, uintN b) public returns (uintN) {
-                return a + b;
+                unchecked {
+                    return a + b;
+                }
             }
 
             function sub(uintN a, uintN b) public returns (uintN) {
-                return a - b;
+                unchecked {
+                    return a - b;
+                }
             }
 
             function mul(uintN a, uintN b) public returns (uintN) {
                 unchecked {
-                return a * b;
+                    return a * b;
                 }
             }
 
             function div(uintN a, uintN b) public returns (uintN) {
-                return a / b;
+                unchecked {
+                    return a / b;
+                }
             }
 
             function mod(uintN a, uintN b) public returns (uintN) {
-                return a % b;
+                unchecked {
+                    return a % b;
+                }
             }
 
             function pow(uintN a, uintN b) public returns (uintN) {
                 unchecked {
-                return a ** b;
+                    return a ** b;
                 }
             }
 
@@ -770,7 +777,7 @@ fn test_power_overflow_boundaries() {
         }"#
         .replace("intN", &format!("int{width}"));
 
-        let mut contract = build_solidity_with_options(&src, true, false);
+        let mut contract = build_solidity(&src);
         contract.constructor(&[]);
 
         let return_value = contract
@@ -827,7 +834,7 @@ fn test_overflow_boundaries() {
             }
         }"#
         .replace("intN", &format!("int{width}"));
-        let mut contract = build_solidity_with_options(&src, true, false);
+        let mut contract = build_solidity(&src);
 
         // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1]. We generate these boundaries:
         let mut upper_boundary: BigInt = BigInt::from(2_u32).pow((width - 1) as u32);
@@ -1043,7 +1050,7 @@ fn test_mul_within_range() {
         }"#
         .replace("intN", &format!("int{width}"));
 
-        let mut contract = build_solidity_with_options(&src, true, false);
+        let mut contract = build_solidity(&src);
         contract.constructor(&[]);
         for _ in 0..10 {
             // Max number to fit unsigned N bits is (2^N)-1
@@ -1095,7 +1102,7 @@ fn test_overflow_detect_signed() {
             }
         }"#
         .replace("intN", &format!("int{width}"));
-        let mut contract = build_solidity_with_options(&src, true, false);
+        let mut contract = build_solidity(&src);
 
         contract.constructor(&[]);
 
@@ -1164,7 +1171,7 @@ fn test_overflow_detect_unsigned() {
             }
         }"#
         .replace("intN", &format!("int{width}"));
-        let mut contract = build_solidity_with_options(&src, true, false);
+        let mut contract = build_solidity(&src);
 
         contract.constructor(&[]);
 
@@ -1206,21 +1213,27 @@ fn int() {
         let src = r#"
         contract test {
             function add(intN a, intN b) public returns (intN) {
-                return a + b;
+                unchecked {
+                    return a + b;
+                }
             }
 
             function sub(intN a, intN b) public returns (intN) {
-                return a - b;
+                unchecked {
+                    return a - b;
+                }
             }
 
             function mul(intN a, intN b) public returns (intN) {
                 unchecked {
-                return a * b;
+                    return a * b;
                 }
             }
 
             function div(intN a, intN b) public returns (intN) {
-                 return a / b;
+                unchecked {
+                    return a / b;
+                }
             }
 
             function mod(intN a, intN b) public returns (intN) {

+ 3 - 5
tests/solana_tests/runtime_errors.rs

@@ -1,11 +1,11 @@
 // SPDX-License-Identifier: Apache-2.0
 
-use crate::{build_solidity_with_options, BorshToken};
+use crate::{build_solidity, BorshToken};
 use num_bigint::BigInt;
 
 #[test]
 fn runtime_errors() {
-    let mut vm = build_solidity_with_options(
+    let mut vm = build_solidity(
         r#"
 contract RuntimeErrors {
     bytes b = hex"0000_00fa";
@@ -71,7 +71,7 @@ contract RuntimeErrors {
         uint128 x = address(this).balance;
         //print("sesa");
         print("x = {}".format(x));
-        
+
     }
 
     function i_will_revert() public {
@@ -140,8 +140,6 @@ contract calle_contract {
 }
 
  "#,
-        true,
-        true,
     );
 
     vm.set_program(0);

+ 15 - 13
tests/solana_tests/simple.rs

@@ -381,19 +381,21 @@ contract test3 {
 	}
 
 	function bar(uint32 b, bool x) public returns (uint32) {
-		uint32 i = 1;
-		if (x) {
-			do {
-				i += 10;
-			}
-			while (b-- > 0);
-		} else {
-			uint32 j;
-			for (j=2; j<10; j++) {
-				i *= 3;
-			}
-		}
-		return i;
+        unchecked {
+            uint32 i = 1;
+            if (x) {
+                do {
+                    i += 10;
+                }
+                while (b-- > 0);
+            } else {
+                uint32 j;
+                for (j=2; j<10; j++) {
+                    i *= 3;
+                }
+            }
+            return i;
+        }
 	}
 
 	function baz(uint32 x) public returns (uint32) {

+ 1 - 3
tests/substrate.rs

@@ -1180,12 +1180,11 @@ impl MockSubstrate {
 }
 
 pub fn build_solidity(src: &str) -> MockSubstrate {
-    build_solidity_with_options(src, false, false, false)
+    build_solidity_with_options(src, false, true)
 }
 
 pub fn build_solidity_with_options(
     src: &str,
-    math_overflow_flag: bool,
     log_api_return_codes: bool,
     log_runtime_errors: bool,
 ) -> MockSubstrate {
@@ -1198,7 +1197,6 @@ pub fn build_solidity_with_options(
         &mut cache,
         inkwell::OptimizationLevel::Default,
         Target::default_substrate(),
-        math_overflow_flag,
         log_api_return_codes,
         log_runtime_errors,
     );

+ 2 - 3
tests/substrate_tests/calls.rs

@@ -769,11 +769,11 @@ fn log_api_call_return_values_works() {
         r##"
         contract Test {
             constructor () payable {}
-        
+
             function test() public {
                 try new Other() returns (Other o) {
                     o.foo();
-                } 
+                }
                 catch {}
             }
         }
@@ -783,7 +783,6 @@ fn log_api_call_return_values_works() {
             }
         }
         "##,
-        false,
         true,
         false,
     );

+ 2 - 3
tests/substrate_tests/debug_buffer_format.rs

@@ -10,15 +10,14 @@ fn debug_buffer_format() {
                 print("Hello!");
                 print("I call seal_debug_message under the hood!");
             }
-        
+
             function multiple_prints_then_revert() public {
                 print("Hello!");
                 print("I call seal_debug_message under the hood!");
                 revert("sesa!!!");
             }
-        }        
+        }
     "#,
-        false,
         true,
         true,
     );

+ 28 - 30
tests/substrate_tests/errors.rs

@@ -12,61 +12,61 @@ fn errors() {
         child public c;
         child public c2;
         callee public cal;
-    
+
         constructor() public payable {}
-    
+
         function print_test(int8 num) public returns (int8) {
             print("Hello world!");
             return num;
         }
-    
+
         function math_overflow(int8 num) public returns (int8) {
             int8 ovf = num + 120;
             return ovf;
         }
-    
+
         function require_test(int8 num) public returns (int8) {
             require(num > 10, "sesa");
             return 0;
         }
-    
+
         // assert failure
         function assert_test(int8 num) public returns (int8) {
             assert(num > 10);
             return 0;
         }
-    
+
         // storage index out of bounds
         function set_storage_bytes() public returns (bytes) {
             bytes sesa = new bytes(1);
             b[5] = sesa[0];
             return sesa;
         }
-    
+
         // storage array index out of bounds
         function get_storage_bytes() public returns (bytes) {
             bytes sesa = new bytes(1);
             sesa[0] = b[5];
             return sesa;
         }
-    
+
         // value transfer failure
         function transfer_abort() public {
             address a = address(0);
             payable(a).transfer(10);
         }
-    
+
         //  pop from empty storage array
         function pop_empty_storage() public {
             arr.pop();
         }
-    
+
         // external call failed
         function call_ext() public {
             //cal = new callee();
             cal.callee_func{gas: 1e15}();
         }
-    
+
         // contract creation failed (contract was deplyed with no value)
         function create_child() public {
             c = new child{value: 900e15, salt:2}();
@@ -74,85 +74,83 @@ fn errors() {
             uint128 x = address(this).balance;
             //print("sesa");
             print("x = {}".format(x));
-            
+
         }
-    
+
         // non payable function dont_pay_me received value
         function dont_pay_me() public {}
-    
+
         function pay_me() public payable {
             print("PAYED");
             uint128 x = address(this).balance;
             //print("sesa");
             print("x = {}".format(x));
-            
+
         }
-    
+
         function i_will_revert() public {
             revert();
         }
-    
+
         function write_integer_failure(uint8 buf_size) public {
             bytes smol_buf = new bytes(buf_size);
             smol_buf.writeUint32LE(350, 20);
         }
-    
+
         function write_bytes_failure(uint8 buf_size) public {
             bytes data = new bytes(10);
             bytes smol_buf = new bytes(buf_size);
             smol_buf.writeBytes(data, 0);
         }
-    
+
         function read_integer_failure(uint32 offset) public {
             bytes smol_buf = new bytes(1);
             smol_buf.readUint16LE(offset);
         }
-    
+
         // truncated type overflows
         function trunc_failure(uint128 input) public returns (uint256) {
             uint256[] a = new uint256[](input);
             return a[0];
         }
-    
+
         function out_of_bounds(uint8 input) public returns (uint256) {
             uint256[] a = new uint256[](input);
             return a[20];
         }
-    
+
         function invalid_instruction() public {
             assembly {
                 invalid()
             }
         }
-    
+
         function byte_cast_failure(uint8 num) public returns (bytes) {
             bytes smol_buf = new bytes(num);
-    
+
             //bytes32 b32 = new bytes(num);
             bytes32 b32 = bytes32(smol_buf);
             return b32;
         }
     }
-    
+
     contract callee {
         constructor() {}
-    
+
         function callee_func() public {
             revert();
         }
     }
-    
+
     contract child {
         constructor() {}
-    
+
         function say_my_name() public pure returns (string memory) {
             print("say_my_name");
             return "child";
         }
     }
-    
     "#,
-        true,
         false,
         true,
     );

+ 8 - 12
tests/substrate_tests/expressions.rs

@@ -143,8 +143,10 @@ fn expressions() {
             int constant large_value = 14474011154664524427946373126085988481658748083205070504932198000989141204992;
 
             function add_100(uint16 a) pure public returns (uint16) {
-                a -= 200;
-                a += 300;
+                unchecked {
+                    a -= 200;
+                    a += 300;
+                }
                 return a;
             }
 
@@ -956,7 +958,7 @@ fn test_power_overflow_boundaries() {
         }"#
         .replace("intN", &format!("int{width}"));
 
-        let mut contract = build_solidity_with_options(&src, true, false, false);
+        let mut contract = build_solidity_with_options(&src, false, false);
 
         let base = BigUint::from(2_u32);
         let mut base_data = base.to_bytes_le();
@@ -1156,7 +1158,7 @@ fn test_overflow_boundaries() {
             }
         }"#
         .replace("intN", &format!("int{width}"));
-        let mut contract = build_solidity_with_options(&src, true, false, false);
+        let mut contract = build_solidity_with_options(&src, false, false);
 
         // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1]. We generate these boundaries:
         let upper_boundary = BigInt::from(2_u32).pow(width - 1).sub(1_u32);
@@ -1287,7 +1289,7 @@ fn test_overflow_detect_signed() {
             }
         }"#
         .replace("intN", &format!("int{width}"));
-        let mut contract = build_solidity_with_options(&src, true, false, false);
+        let mut contract = build_solidity_with_options(&src, false, false);
 
         // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1] .Generate a value that will overflow this range:
         let limit = BigInt::from(2_u32).pow(width - 1).sub(1_u32);
@@ -1349,7 +1351,7 @@ fn test_overflow_detect_unsigned() {
             }
         }"#
         .replace("intN", &format!("int{width}"));
-        let mut contract = build_solidity_with_options(&src, true, false, false);
+        let mut contract = build_solidity_with_options(&src, false, false);
 
         // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1].
         let limit = BigUint::from(2_u32).pow(width).sub(1_u32);
@@ -1707,7 +1709,6 @@ fn addition_overflow() {
             }
         }
         "#,
-        true,
         false,
         false,
     );
@@ -1732,7 +1733,6 @@ fn unchecked_addition_overflow() {
             }
         }
         "#,
-        true,
         false,
         false,
     );
@@ -1756,7 +1756,6 @@ fn subtraction_underflow() {
             }
         }
         "#,
-        true,
         false,
         false,
     );
@@ -1781,7 +1780,6 @@ fn unchecked_subtraction_underflow() {
             }
         }
         "#,
-        true,
         false,
         false,
     );
@@ -1805,7 +1803,6 @@ fn multiplication_overflow() {
             }
         }
         "#,
-        true,
         false,
         false,
     );
@@ -1830,7 +1827,6 @@ fn unchecked_multiplication_overflow() {
             }
         }
         "#,
-        true,
         false,
         false,
     );

+ 0 - 2
tests/substrate_tests/inheritance.rs

@@ -37,7 +37,6 @@ fn test_abstract() {
         Target::default_substrate(),
         false,
         false,
-        false,
     );
 
     assert!(!ns.diagnostics.any_errors());
@@ -77,7 +76,6 @@ fn test_abstract() {
         Target::default_substrate(),
         false,
         false,
-        false,
     );
 
     assert!(!ns.diagnostics.any_errors());

+ 0 - 1
tests/undefined_variable_detection.rs

@@ -18,7 +18,6 @@ fn parse_and_codegen(src: &'static str) -> Namespace {
         vector_to_slice: false,
         common_subexpression_elimination: false,
         opt_level: OptimizationLevel::Default,
-        math_overflow_check: false,
         generate_debug_information: false,
         log_api_return_codes: false,
         log_runtime_errors: false,