Forráskód Böngészése

Allow returns values to be ignored in try catch (#1369)

A try catch statement does not need to decode the return values if it is not interested.

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 éve
szülő
commit
8906a77c6b

+ 1 - 1
src/codegen/statements.rs

@@ -1177,7 +1177,7 @@ fn try_catch(
 
                 cfg.set_basic_block(success_block);
 
-                if func_returns != vec![Type::Void] {
+                if !try_stmt.returns.is_empty() {
                     let mut res = Vec::new();
 
                     for ret in &try_stmt.returns {

+ 1 - 1
src/sema/statements.rs

@@ -2272,7 +2272,7 @@ fn try_catch(
                 func_returns = vec![];
             }
 
-            if returns.len() != func_returns.len() {
+            if !returns.is_empty() && returns.len() != func_returns.len() {
                 diagnostics.push(Diagnostic::error(
                     expr.loc(),
                     format!(

+ 17 - 0
tests/codegen_testcases/solidity/try_catch.sol

@@ -0,0 +1,17 @@
+// RUN: --target substrate --emit cfg
+interface I {
+	function bar() external returns (int32, bool);
+}
+
+contract C {
+// BEGIN-CHECK: C::C::function::foo
+	function foo(I i) public returns (int32 x) {
+        try i.bar() {
+            // ensure no abi decoding is done because the return values of bar() are not used
+            x = 1;
+        } catch (bytes) {
+            x = 2;
+        }
+// NOT-CHECK: builtin ReadFromBuffer ((external call return data)
+	}
+}

+ 1 - 1
tests/evm.rs

@@ -248,7 +248,7 @@ fn ethereum_solidity_tests() {
         })
         .sum();
 
-    assert_eq!(errors, 1038);
+    assert_eq!(errors, 1032);
 }
 
 fn set_file_contents(source: &str, path: &Path) -> (FileResolver, Vec<String>) {

+ 61 - 0
tests/substrate_tests/calls.rs

@@ -333,6 +333,65 @@ fn try_catch_external_calls() {
     runtime.function_expect_failure("test", Vec::new());
 }
 
+#[test]
+fn try_catch_external_calls_dont_decode_returns() {
+    // try not using the return values of test() - revert case
+    // note the absense of "try o.test() returns (int32 y, bool) {"
+    let mut runtime = build_solidity(
+        r##"
+        contract c {
+            function test() public returns (int32 x) {
+                other o = new other();
+                try o.test() {
+                    x = 1;
+                } catch (bytes c) {
+                    x = 2;
+                }
+            }
+        }
+
+        contract other {
+            function test() public returns (int32, bool) {
+                revert("foo");
+            }
+        }
+        "##,
+    );
+
+    runtime.constructor(0, Vec::new());
+    runtime.function("test", Vec::new());
+
+    assert_eq!(runtime.output(), 2i32.encode());
+
+    // try not using the return values of test() - normal case
+    // note the absense of "try o.test() returns (int32 y, bool) {"
+    let mut runtime = build_solidity(
+        r##"
+        contract c {
+            function test() public returns (int32 x) {
+                other o = new other();
+                try o.test({meh: false}) {
+                    x = 1;
+                } catch (bytes c) {
+                    x = 2;
+                }
+            }
+        }
+
+        contract other {
+            function test(bool meh) public returns (int32, bool) {
+                return (5, meh);
+            }
+        }
+        "##,
+    );
+
+    runtime.constructor(0, Vec::new());
+    runtime.function("test", Vec::new());
+
+    assert_eq!(runtime.output(), 1i32.encode());
+}
+
 #[test]
 fn try_catch_constructor() {
     let mut runtime = build_solidity(
@@ -397,6 +456,7 @@ fn try_catch_constructor() {
                 try new other(true) {
                     x = 1;
                 } catch (bytes c) {
+                    print("returns:{}".format(c));
                     assert(c == hex"a079c3080c666f6f");
                     x = 2;
                 }
@@ -418,6 +478,7 @@ fn try_catch_constructor() {
     // TODO / REGRESSION
     // This traps with InstructionTrap(MemoryOutOfBounds). Which does not seem right
     // runtime.function_expect_failure("test", Vec::new());
+    // There is a problem with reading return data, see output pf: print("returns:{}".format(c));
 }
 
 #[test]