aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/SolidityEndToEndTest.cpp84
-rw-r--r--libsolidity/SolidityOptimizer.cpp61
2 files changed, 138 insertions, 7 deletions
diff --git a/libsolidity/SolidityEndToEndTest.cpp b/libsolidity/SolidityEndToEndTest.cpp
index f168ad45..f32439a2 100644
--- a/libsolidity/SolidityEndToEndTest.cpp
+++ b/libsolidity/SolidityEndToEndTest.cpp
@@ -3910,6 +3910,90 @@ BOOST_AUTO_TEST_CASE(external_types_in_calls)
BOOST_CHECK(callContractFunction("nonexisting") == encodeArgs(u256(9)));
}
+BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes)
+{
+ // bug #1798
+ char const* sourceCode = R"(
+ contract init {
+ function isOk() returns (bool) { return false; }
+ bool public ok = false;
+ }
+ contract fix {
+ function isOk() returns (bool) { return true; }
+ bool public ok = true;
+ }
+
+ contract init_fix is init, fix {
+ function checkOk() returns (bool) { return ok; }
+ }
+ contract fix_init is fix, init {
+ function checkOk() returns (bool) { return ok; }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "init_fix");
+ BOOST_CHECK(callContractFunction("isOk()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("ok()") == encodeArgs(true));
+
+ compileAndRun(sourceCode, 0, "fix_init");
+ BOOST_CHECK(callContractFunction("isOk()") == encodeArgs(false));
+ BOOST_CHECK(callContractFunction("ok()") == encodeArgs(false));
+}
+
+BOOST_AUTO_TEST_CASE(proper_overwriting_accessor_by_function)
+{
+ // bug #1798
+ char const* sourceCode = R"(
+ contract attribute {
+ bool ok = false;
+ }
+ contract func {
+ function ok() returns (bool) { return true; }
+ }
+
+ contract attr_func is attribute, func {
+ function checkOk() returns (bool) { return ok(); }
+ }
+ contract func_attr is func, attribute {
+ function checkOk() returns (bool) { return ok; }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "attr_func");
+ BOOST_CHECK(callContractFunction("ok()") == encodeArgs(true));
+ compileAndRun(sourceCode, 0, "func_attr");
+ BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(false));
+}
+
+
+BOOST_AUTO_TEST_CASE(overwriting_inheritance)
+{
+ // bug #1798
+ char const* sourceCode = R"(
+ contract A {
+ function ok() returns (uint) { return 1; }
+ }
+ contract B {
+ function ok() returns (uint) { return 2; }
+ }
+ contract C {
+ uint ok = 6;
+ }
+ contract AB is A, B {
+ function ok() returns (uint) { return 4; }
+ }
+ contract reversedE is C, AB {
+ function checkOk() returns (uint) { return ok(); }
+ }
+ contract E is AB, C {
+ function checkOk() returns (uint) { return ok; }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "reversedE");
+ BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(4));
+ compileAndRun(sourceCode, 0, "E");
+ BOOST_CHECK(callContractFunction("checkOk()") == encodeArgs(6));
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/libsolidity/SolidityOptimizer.cpp b/libsolidity/SolidityOptimizer.cpp
index 9cdaa588..3cb6a536 100644
--- a/libsolidity/SolidityOptimizer.cpp
+++ b/libsolidity/SolidityOptimizer.cpp
@@ -83,14 +83,28 @@ public:
"\nOptimized: " + toHex(optimizedOutput));
}
- AssemblyItems getCSE(AssemblyItems const& _input)
+ AssemblyItems addDummyLocations(AssemblyItems const& _input)
{
// add dummy locations to each item so that we can check that they are not deleted
AssemblyItems input = _input;
for (AssemblyItem& item: input)
item.setLocation(SourceLocation(1, 3, make_shared<string>("")));
+ return input;
+ }
+
+ eth::KnownState createInitialState(AssemblyItems const& _input)
+ {
+ eth::KnownState state;
+ for (auto const& item: addDummyLocations(_input))
+ state.feedItem(item);
+ return state;
+ }
+
+ AssemblyItems getCSE(AssemblyItems const& _input, eth::KnownState const& _state = eth::KnownState())
+ {
+ AssemblyItems input = addDummyLocations(_input);
- eth::CommonSubexpressionEliminator cse;
+ eth::CommonSubexpressionEliminator cse(_state);
BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end());
AssemblyItems output = cse.getOptimizedItems();
@@ -101,9 +115,13 @@ public:
return output;
}
- void checkCSE(AssemblyItems const& _input, AssemblyItems const& _expectation)
+ void checkCSE(
+ AssemblyItems const& _input,
+ AssemblyItems const& _expectation,
+ KnownState const& _state = eth::KnownState()
+ )
{
- AssemblyItems output = getCSE(_input);
+ AssemblyItems output = getCSE(_input, _state);
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
}
@@ -113,8 +131,12 @@ public:
// Running it four times should be enough for these tests.
for (unsigned i = 0; i < 4; ++i)
{
- eth::ControlFlowGraph cfg(output);
- output = cfg.optimisedItems();
+ ControlFlowGraph cfg(output);
+ AssemblyItems optItems;
+ for (BasicBlock const& block: cfg.optimisedBlocks())
+ copy(output.begin() + block.begin, output.begin() + block.end,
+ back_inserter(optItems));
+ output = move(optItems);
}
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
}
@@ -231,7 +253,8 @@ BOOST_AUTO_TEST_CASE(function_calls)
BOOST_AUTO_TEST_CASE(cse_intermediate_swap)
{
- eth::CommonSubexpressionEliminator cse;
+ eth::KnownState state;
+ eth::CommonSubexpressionEliminator cse(state);
AssemblyItems input{
Instruction::SWAP1, Instruction::POP, Instruction::ADD, u256(0), Instruction::SWAP1,
Instruction::SLOAD, Instruction::SWAP1, u256(100), Instruction::EXP, Instruction::SWAP1,
@@ -754,6 +777,30 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between
BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3)));
}
+BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack)
+{
+ eth::KnownState state = createInitialState(AssemblyItems{
+ u256(0x12),
+ u256(0x20),
+ Instruction::ADD
+ });
+ AssemblyItems input{
+ u256(0x12 + 0x20)
+ };
+ checkCSE(input, AssemblyItems{Instruction::DUP1}, state);
+}
+
+BOOST_AUTO_TEST_CASE(cse_equality_on_initially_known_stack)
+{
+ eth::KnownState state = createInitialState(AssemblyItems{Instruction::DUP1});
+ AssemblyItems input{
+ Instruction::EQ
+ };
+ AssemblyItems output = getCSE(input, state);
+ // check that it directly pushes 1 (true)
+ BOOST_CHECK(find(output.begin(), output.end(), AssemblyItem(u256(1))) != output.end());
+}
+
BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused)
{
// remove parts of the code that are unused