diff --git a/Changelog.md b/Changelog.md index 4dd1b7c82..a3c5df97a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Compiler Features: Bugfixes: + * Code generator: Fix missing dependency tracking for abstract contracts. * Code generator: Fix internal error on returning structs containing mappings from library function. * Code generator: Fix internal compiler error when referencing members via module name but not using the reference. * Code generator: Fix ``ABIEncoderV2`` pragma from the current module affecting inherited functions and applied modifiers. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 0c1b6b49d..6ff3e91f6 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1151,11 +1151,15 @@ void CompilerStack::compileContract( if (m_hasError) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors.")); - if (_otherCompilers.count(&_contract) || !_contract.canBeDeployed()) + if (_otherCompilers.count(&_contract)) return; + for (auto const* dependency: _contract.annotation().contractDependencies) compileContract(*dependency, _otherCompilers); + if (!_contract.canBeDeployed()) + return; + Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); shared_ptr compiler = make_shared(m_evmVersion, m_revertStrings, m_optimiserSettings); diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 8ff8a85aa..de43bf9fa 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1505,6 +1505,46 @@ BOOST_AUTO_TEST_CASE(stopAfter_ast_output) BOOST_CHECK(result["sources"]["a.sol"]["ast"].isObject()); } +BOOST_AUTO_TEST_CASE(dependency_tracking_of_abstract_contract) +{ + char const* input = R"( + { + "language": "Solidity", + "sources": { + "BlockRewardAuRaBase.sol": { + "content": " contract Sacrifice { constructor() payable {} } abstract contract BlockRewardAuRaBase { function _transferNativeReward() internal { new Sacrifice(); } function _distributeTokenRewards() internal virtual; } " + }, + "BlockRewardAuRaCoins.sol": { + "content": " import \"./BlockRewardAuRaBase.sol\"; contract BlockRewardAuRaCoins is BlockRewardAuRaBase { function transferReward() public { _transferNativeReward(); } function _distributeTokenRewards() internal override {} } " + } + }, + "settings": { + "outputSelection": { + "BlockRewardAuRaCoins.sol": { + "BlockRewardAuRaCoins": ["evm.bytecode.sourceMap"] + } + } + } + } + )"; + + Json::Value parsedInput; + BOOST_REQUIRE(util::jsonParseStrict(input, parsedInput)); + + solidity::frontend::StandardCompiler compiler; + Json::Value result = compiler.compile(parsedInput); + + BOOST_REQUIRE(result["contracts"].isObject()); + BOOST_REQUIRE(result["contracts"].size() == 1); + BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"].isObject()); + BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"].size() == 1); + BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"].isObject()); + BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"]["evm"].isObject()); + BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"]["evm"]["bytecode"].isObject()); + BOOST_REQUIRE(result["sources"].isObject()); + BOOST_REQUIRE(result["sources"].size() == 2); +} + BOOST_AUTO_TEST_SUITE_END() } // end namespaces