diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 897e83290..46ae3381c 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -50,7 +50,7 @@ using namespace solidity::frontend; pair IRGenerator::run( ContractDefinition const& _contract, - map const& _otherYulSources + map const& _otherYulSources ) { string const ir = yul::reindent(generate(_contract, _otherYulSources)); @@ -78,7 +78,7 @@ pair IRGenerator::run( string IRGenerator::generate( ContractDefinition const& _contract, - map const& _otherYulSources + map const& _otherYulSources ) { auto subObjectSources = [&_otherYulSources](std::set const& subObjects) -> string diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 94433912d..cdb431e83 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -53,13 +53,13 @@ public: /// (or just pretty-printed, depending on the optimizer settings). std::pair run( ContractDefinition const& _contract, - std::map const& _otherYulSources + std::map const& _otherYulSources ); private: std::string generate( ContractDefinition const& _contract, - std::map const& _otherYulSources + std::map const& _otherYulSources ); std::string generate(Block const& _block); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index dbe57764a..119ea42b8 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -525,6 +525,7 @@ bool CompilerStack::compile(State _stopAfter) // Only compile contracts individually which have been requested. map> otherCompilers; + for (Source const* source: m_sourceOrder) for (ASTPointer const& node: source->ast->nodes()) if (auto contract = dynamic_cast(node.get())) @@ -1231,21 +1232,20 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) if (m_hasError) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateIR with errors.")); - if (!_contract.canBeDeployed()) - return; - - map otherYulSources; - Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); if (!compiledContract.yulIR.empty()) return; string dependenciesSource; for (auto const* dependency: _contract.annotation().contractDependencies) - { generateIR(*dependency); - otherYulSources.emplace(dependency, m_contracts.at(dependency->fullyQualifiedName()).yulIR); - } + + if (!_contract.canBeDeployed()) + return; + + map otherYulSources; + for (auto const& pair: m_contracts) + otherYulSources.emplace(pair.second.contract, pair.second.yulIR); IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources); diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index de43bf9fa..37539d712 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1521,7 +1521,7 @@ BOOST_AUTO_TEST_CASE(dependency_tracking_of_abstract_contract) "settings": { "outputSelection": { "BlockRewardAuRaCoins.sol": { - "BlockRewardAuRaCoins": ["evm.bytecode.sourceMap"] + "BlockRewardAuRaCoins": ["ir", "evm.bytecode.sourceMap"] } } } @@ -1540,11 +1540,61 @@ BOOST_AUTO_TEST_CASE(dependency_tracking_of_abstract_contract) 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"]["ir"].isString()); BOOST_REQUIRE(result["contracts"]["BlockRewardAuRaCoins.sol"]["BlockRewardAuRaCoins"]["evm"]["bytecode"].isObject()); BOOST_REQUIRE(result["sources"].isObject()); BOOST_REQUIRE(result["sources"].size() == 2); } +BOOST_AUTO_TEST_CASE(dependency_tracking_of_abstract_contract_yul) +{ + char const* input = R"( + { + "language": "Solidity", + "sources": { + "A.sol": { + "content": "contract A {} contract B {} contract C { constructor() { new B(); } } contract D {}" + } + }, + "settings": { + "outputSelection": { + "A.sol": { + "C": ["ir"] + } + } + } + } + )"; + + 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"]["A.sol"].isObject()); + BOOST_REQUIRE(result["contracts"]["A.sol"].size() == 1); + BOOST_REQUIRE(result["contracts"]["A.sol"]["C"].isObject()); + BOOST_REQUIRE(result["contracts"]["A.sol"]["C"]["ir"].isString()); + + const string& irCode = result["contracts"]["A.sol"]["C"]["ir"].asString(); + + // Make sure C and B contracts are deployed + BOOST_REQUIRE(irCode.find("object \"C") != string::npos); + BOOST_REQUIRE(irCode.find("object \"B") != string::npos); + + // Make sure A and D are NOT deployed as they were not requested and are not + // in any dependency + BOOST_REQUIRE(irCode.find("object \"A") == string::npos); + BOOST_REQUIRE(irCode.find("object \"D") == string::npos); + + + BOOST_REQUIRE(result["sources"].isObject()); + BOOST_REQUIRE(result["sources"].size() == 1); +} + BOOST_AUTO_TEST_SUITE_END() } // end namespaces diff --git a/test/libsolidity/semanticTests/freeFunctions/free_runtimecode.sol b/test/libsolidity/semanticTests/freeFunctions/free_runtimecode.sol index 7a05ff5d0..a79d68a3c 100644 --- a/test/libsolidity/semanticTests/freeFunctions/free_runtimecode.sol +++ b/test/libsolidity/semanticTests/freeFunctions/free_runtimecode.sol @@ -11,5 +11,7 @@ contract D { return test(); } } +// ==== +// compileViaYul: true // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/freeFunctions/new_operator.sol b/test/libsolidity/semanticTests/freeFunctions/new_operator.sol index e35f1c9ea..7a7e53759 100644 --- a/test/libsolidity/semanticTests/freeFunctions/new_operator.sol +++ b/test/libsolidity/semanticTests/freeFunctions/new_operator.sol @@ -11,5 +11,7 @@ contract D { return test(); } } +// ==== +// compileViaYul: true // ---- // f() -> 2