Merge pull request #7760 from ethereum/merge_develop_060

Merge develop into develop_060
This commit is contained in:
chriseth 2019-11-20 15:50:21 +01:00 committed by GitHub
commit 1b9e861050
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
105 changed files with 634 additions and 666 deletions

View File

@ -52,8 +52,8 @@ then
rm -rf z3-4.8.6-x64-osx-10.14.6 rm -rf z3-4.8.6-x64-osx-10.14.6
# evmone # evmone
wget https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-darwin-x86_64.tar.gz wget https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-darwin-x86_64.tar.gz
tar xzpf evmone-0.1.0-darwin-x86_64.tar.gz -C /usr/local tar xzpf evmone-0.3.0-darwin-x86_64.tar.gz -C /usr/local
rm -f evmone-0.1.0-darwin-x86_64.tar.gz rm -f evmone-0.3.0-darwin-x86_64.tar.gz
fi fi

View File

@ -29,7 +29,7 @@ set -e
REPODIR="$(realpath $(dirname $0)/..)" REPODIR="$(realpath $(dirname $0)/..)"
for OPTIMIZE in 0 1; do for OPTIMIZE in 0 1; do
for EVM in homestead byzantium constantinople petersburg; do for EVM in homestead byzantium constantinople petersburg istanbul; do
EVM=$EVM OPTIMIZE=$OPTIMIZE ${REPODIR}/.circleci/soltest.sh EVM=$EVM OPTIMIZE=$OPTIMIZE ${REPODIR}/.circleci/soltest.sh
done done
done done

View File

@ -1,17 +0,0 @@
name: Mark stale pull requests
on:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: "A reminder that this pull request has had no activity for 14 days"
stale-pr-label: "no-pr-activity"
days-before-stale: 14

View File

@ -69,6 +69,7 @@ Bugfixes:
* SMTChecker: Fix internal error when implicitly converting string literals to fixed bytes. * SMTChecker: Fix internal error when implicitly converting string literals to fixed bytes.
* Type Checker: Disallow constructor of the same class to be used as modifier. * Type Checker: Disallow constructor of the same class to be used as modifier.
* Type Checker: Treat magic variables as unknown identifiers in inline assembly. * Type Checker: Treat magic variables as unknown identifiers in inline assembly.
* Code Generator: Fix internal error when trying to convert ``super`` to a different type
### 0.5.12 (2019-10-01) ### 0.5.12 (2019-10-01)

View File

@ -94,7 +94,7 @@ The test system will automatically try to discover the location of the ``evmone`
starting from the current directory. The required file is called ``libevmone.so`` on Linux systems, starting from the current directory. The required file is called ``libevmone.so`` on Linux systems,
``evmone.dll`` on Windows systems and ``libevmone.dylib`` on MacOS. If it is not found, the relevant tests ``evmone.dll`` on Windows systems and ``libevmone.dylib`` on MacOS. If it is not found, the relevant tests
are skipped. To run all tests, download the library from are skipped. To run all tests, download the library from
`Github <https://github.com/ethereum/evmone/releases/tag/v0.1.0>`_ `Github <https://github.com/ethereum/evmone/releases/tag/v0.3.0>`_
and either place it in the project root path or inside the ``deps`` folder. and either place it in the project root path or inside the ``deps`` folder.
If you do not have libz3 installed on your system, you should disable the SMT tests: If you do not have libz3 installed on your system, you should disable the SMT tests:

View File

@ -185,11 +185,17 @@ introduce new identifiers into these scopes.
Identifiers are visible in Identifiers are visible in
the block they are defined in (including all sub-nodes and sub-blocks). the block they are defined in (including all sub-nodes and sub-blocks).
As an exception, identifiers defined in the "init" part of the for-loop
As an exception, identifiers defined directly in the "init" part of the for-loop
(the first block) are visible in all other parts of the for-loop (the first block) are visible in all other parts of the for-loop
(but not outside of the loop). (but not outside of the loop).
Identifiers declared in the other parts of the for loop respect the regular Identifiers declared in the other parts of the for loop respect the regular
syntactical scoping rules. syntactical scoping rules.
This means a for-loop of the form ``for { I... } C { P... } { B... }`` is equivalent
to ``{ I... for {} C { P... } { B... } }``.
The parameters and return parameters of functions are visible in the The parameters and return parameters of functions are visible in the
function body and their names cannot overlap. function body and their names cannot overlap.

View File

@ -27,7 +27,7 @@ namespace dev
{ {
/// Generic visitor used as follows: /// Generic visitor used as follows:
/// boost::apply_visitor(GenericVisitor<Class1, Class2>( /// std::visit(GenericVisitor<Class1, Class2>(
/// [](Class1& _c) { _c.f(); }, /// [](Class1& _c) { _c.f(); },
/// [](Class2& _c) { _c.g(); } /// [](Class2& _c) { _c.g(); }
/// ), variant); /// ), variant);
@ -59,7 +59,7 @@ struct GenericVisitor<>: public boost::static_visitor<> {
}; };
/// Generic visitor with fallback: /// Generic visitor with fallback:
/// boost::apply_visitor(GenericFallbackVisitor<Class1, Class2>( /// std::visit(GenericFallbackVisitor<Class1, Class2>(
/// [](Class1& _c) { _c.f(); }, /// [](Class1& _c) { _c.f(); },
/// [](Class2& _c) { _c.g(); } /// [](Class2& _c) { _c.g(); }
/// ), variant); /// ), variant);
@ -92,7 +92,7 @@ struct GenericFallbackVisitor<>: public boost::static_visitor<> {
}; };
/// Generic visitor with fallback that can return a value: /// Generic visitor with fallback that can return a value:
/// boost::apply_visitor(GenericFallbackReturnsVisitor<ReturnType, Class1, Class2>( /// std::visit(GenericFallbackReturnsVisitor<ReturnType, Class1, Class2>(
/// [](Class1& _c) { return _c.f(); }, /// [](Class1& _c) { return _c.f(); },
/// [](Class2& _c) { return _c.g(); } /// [](Class2& _c) { return _c.g(); }
/// ), variant); /// ), variant);

View File

@ -96,7 +96,7 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const
{ {
assertThrow(_data.size() > 0, OptimizerException, "Empty bytecode generated."); assertThrow(_data.size() > 0, OptimizerException, "Empty bytecode generated.");
return bigint(GasMeter::dataGas(_data, m_params.isCreation)); return bigint(GasMeter::dataGas(_data, m_params.isCreation, m_params.evmVersion));
} }
size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items) size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
@ -131,7 +131,7 @@ bigint LiteralMethod::gasNeeded() const
return combineGas( return combineGas(
simpleRunGas({Instruction::PUSH1}), simpleRunGas({Instruction::PUSH1}),
// PUSHX plus data // PUSHX plus data
(m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)), (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)),
0 0
); );
} }
@ -142,7 +142,7 @@ bigint CodeCopyMethod::gasNeeded() const
// Run gas: we ignore memory increase costs // Run gas: we ignore memory increase costs
simpleRunGas(copyRoutine()) + GasCosts::copyGas, simpleRunGas(copyRoutine()) + GasCosts::copyGas,
// Data gas for copy routines: Some bytes are zero, but we ignore them. // Data gas for copy routines: Some bytes are zero, but we ignore them.
bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas), bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas),
// Data gas for data itself // Data gas for data itself
dataGas(toBigEndian(m_value)) dataGas(toBigEndian(m_value))
); );
@ -322,7 +322,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
return combineGas( return combineGas(
simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)), simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
// Data gas for routine: Some bytes are zero, but we ignore them. // Data gas for routine: Some bytes are zero, but we ignore them.
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas), bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas),
0 0
); );
} }

View File

@ -266,13 +266,13 @@ unsigned GasMeter::runGas(Instruction _instruction)
return 0; return 0;
} }
u256 GasMeter::dataGas(bytes const& _data, bool _inCreation) u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion)
{ {
bigint gas = 0; bigint gas = 0;
if (_inCreation) if (_inCreation)
{ {
for (auto b: _data) for (auto b: _data)
gas += (b != 0) ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas; gas += (b != 0) ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::txDataZeroGas;
} }
else else
gas = bigint(GasCosts::createDataGas) * _data.size(); gas = bigint(GasCosts::createDataGas) * _data.size();

View File

@ -53,7 +53,12 @@ namespace GasCosts
} }
inline unsigned balanceGas(langutil::EVMVersion _evmVersion) inline unsigned balanceGas(langutil::EVMVersion _evmVersion)
{ {
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 400 : 20; if (_evmVersion >= langutil::EVMVersion::istanbul())
return 700;
else if (_evmVersion >= langutil::EVMVersion::tangerineWhistle())
return 400;
else
return 20;
} }
static unsigned const expGas = 10; static unsigned const expGas = 10;
inline unsigned expByteGas(langutil::EVMVersion _evmVersion) inline unsigned expByteGas(langutil::EVMVersion _evmVersion)
@ -64,7 +69,12 @@ namespace GasCosts
static unsigned const keccak256WordGas = 6; static unsigned const keccak256WordGas = 6;
inline unsigned sloadGas(langutil::EVMVersion _evmVersion) inline unsigned sloadGas(langutil::EVMVersion _evmVersion)
{ {
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 200 : 50; if (_evmVersion >= langutil::EVMVersion::istanbul())
return 800;
else if (_evmVersion >= langutil::EVMVersion::tangerineWhistle())
return 200;
else
return 50;
} }
static unsigned const sstoreSetGas = 20000; static unsigned const sstoreSetGas = 20000;
static unsigned const sstoreResetGas = 5000; static unsigned const sstoreResetGas = 5000;
@ -92,7 +102,10 @@ namespace GasCosts
static unsigned const txGas = 21000; static unsigned const txGas = 21000;
static unsigned const txCreateGas = 53000; static unsigned const txCreateGas = 53000;
static unsigned const txDataZeroGas = 4; static unsigned const txDataZeroGas = 4;
static unsigned const txDataNonZeroGas = 68; inline unsigned txDataNonZeroGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= langutil::EVMVersion::istanbul() ? 16 : 68;
}
static unsigned const copyGas = 3; static unsigned const copyGas = 3;
} }
@ -139,7 +152,7 @@ public:
/// @returns the gas cost of the supplied data, depending whether it is in creation code, or not. /// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas /// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
/// otherwise code will be stored and have to pay "createDataGas" cost. /// otherwise code will be stored and have to pay "createDataGas" cost.
static u256 dataGas(bytes const& _data, bool _inCreation); static u256 dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion);
private: private:
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise. /// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.

View File

@ -21,7 +21,9 @@
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <libevmasm/SemanticInformation.h> #include <libevmasm/SemanticInformation.h>
#include <functional> #include <functional>
#include <variant>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -31,7 +33,7 @@ using namespace dev::solidity;
namespace namespace
{ {
class AssemblyViewPureChecker: public boost::static_visitor<void> class AssemblyViewPureChecker
{ {
public: public:
explicit AssemblyViewPureChecker( explicit AssemblyViewPureChecker(
@ -49,16 +51,16 @@ public:
void operator()(yul::Identifier const&) {} void operator()(yul::Identifier const&) {}
void operator()(yul::ExpressionStatement const& _expr) void operator()(yul::ExpressionStatement const& _expr)
{ {
boost::apply_visitor(*this, _expr.expression); std::visit(*this, _expr.expression);
} }
void operator()(yul::Assignment const& _assignment) void operator()(yul::Assignment const& _assignment)
{ {
boost::apply_visitor(*this, *_assignment.value); std::visit(*this, *_assignment.value);
} }
void operator()(yul::VariableDeclaration const& _varDecl) void operator()(yul::VariableDeclaration const& _varDecl)
{ {
if (_varDecl.value) if (_varDecl.value)
boost::apply_visitor(*this, *_varDecl.value); std::visit(*this, *_varDecl.value);
} }
void operator()(yul::FunctionDefinition const& _funDef) void operator()(yul::FunctionDefinition const& _funDef)
{ {
@ -72,16 +74,16 @@ public:
checkInstruction(_funCall.location, *fun->instruction); checkInstruction(_funCall.location, *fun->instruction);
for (auto const& arg: _funCall.arguments) for (auto const& arg: _funCall.arguments)
boost::apply_visitor(*this, arg); std::visit(*this, arg);
} }
void operator()(yul::If const& _if) void operator()(yul::If const& _if)
{ {
boost::apply_visitor(*this, *_if.condition); std::visit(*this, *_if.condition);
(*this)(_if.body); (*this)(_if.body);
} }
void operator()(yul::Switch const& _switch) void operator()(yul::Switch const& _switch)
{ {
boost::apply_visitor(*this, *_switch.expression); std::visit(*this, *_switch.expression);
for (auto const& _case: _switch.cases) for (auto const& _case: _switch.cases)
{ {
if (_case.value) if (_case.value)
@ -92,7 +94,7 @@ public:
void operator()(yul::ForLoop const& _for) void operator()(yul::ForLoop const& _for)
{ {
(*this)(_for.pre); (*this)(_for.pre);
boost::apply_visitor(*this, *_for.condition); std::visit(*this, *_for.condition);
(*this)(_for.body); (*this)(_for.body);
(*this)(_for.post); (*this)(_for.post);
} }
@ -108,7 +110,7 @@ public:
void operator()(yul::Block const& _block) void operator()(yul::Block const& _block)
{ {
for (auto const& s: _block.statements) for (auto const& s: _block.statements)
boost::apply_visitor(*this, s); std::visit(*this, s);
} }
private: private:

View File

@ -1438,6 +1438,9 @@ Type const* ContractType::encodingType() const
BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (m_super)
return false;
if (*this == _convertTo) if (*this == _convertTo)
return true; return true;
if (_convertTo.category() == Category::Contract) if (_convertTo.category() == Category::Contract)
@ -1455,8 +1458,12 @@ BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (m_super)
return false;
if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo)) if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo))
return isPayable() || (addressType->stateMutability() < StateMutability::Payable); return isPayable() || (addressType->stateMutability() < StateMutability::Payable);
return isImplicitlyConvertibleTo(_convertTo); return isImplicitlyConvertibleTo(_convertTo);
} }

View File

@ -731,6 +731,9 @@ void CompilerUtils::convertType(
Type::Category stackTypeCategory = _typeOnStack.category(); Type::Category stackTypeCategory = _typeOnStack.category();
Type::Category targetTypeCategory = _targetType.category(); Type::Category targetTypeCategory = _targetType.category();
if (auto contrType = dynamic_cast<ContractType const*>(&_typeOnStack))
solAssert(!contrType->isSuper(), "Cannot convert magic variable \"super\"");
bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum); bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum);
bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer; bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer;
if (chopSignBitsPending) if (chopSignBitsPending)

View File

@ -837,9 +837,9 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
yul::Statement modified = bodyCopier(_inlineAsm.operations()); yul::Statement modified = bodyCopier(_inlineAsm.operations());
solAssert(modified.type() == typeid(yul::Block), ""); solAssert(holds_alternative<yul::Block>(modified), "");
m_code << yul::AsmPrinter()(boost::get<yul::Block>(std::move(modified))) << "\n"; m_code << yul::AsmPrinter()(std::get<yul::Block>(std::move(modified))) << "\n";
return false; return false;
} }

View File

@ -1457,7 +1457,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
if (eth::AssemblyItems const* items = assemblyItems(_contractName)) if (eth::AssemblyItems const* items = assemblyItems(_contractName))
{ {
Gas executionGas = gasEstimator.functionalEstimation(*items); Gas executionGas = gasEstimator.functionalEstimation(*items);
Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false)}; Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false, m_evmVersion)};
Json::Value creation(Json::objectValue); Json::Value creation(Json::objectValue);
creation["codeDepositCost"] = gasToJson(codeDepositGas); creation["codeDepositCost"] = gasToJson(codeDepositGas);

View File

@ -182,7 +182,7 @@ bool AsmAnalyzer::operator()(Identifier const& _identifier)
bool AsmAnalyzer::operator()(ExpressionStatement const& _statement) bool AsmAnalyzer::operator()(ExpressionStatement const& _statement)
{ {
int initialStackHeight = m_stackHeight; int initialStackHeight = m_stackHeight;
bool success = boost::apply_visitor(*this, _statement.expression); bool success = std::visit(*this, _statement.expression);
if (success && m_stackHeight != initialStackHeight) if (success && m_stackHeight != initialStackHeight)
{ {
string msg = string msg =
@ -204,7 +204,7 @@ bool AsmAnalyzer::operator()(Assignment const& _assignment)
int const expectedItems = _assignment.variableNames.size(); int const expectedItems = _assignment.variableNames.size();
solAssert(expectedItems >= 1, ""); solAssert(expectedItems >= 1, "");
int const stackHeight = m_stackHeight; int const stackHeight = m_stackHeight;
bool success = boost::apply_visitor(*this, *_assignment.value); bool success = std::visit(*this, *_assignment.value);
if ((m_stackHeight - stackHeight) != expectedItems) if ((m_stackHeight - stackHeight) != expectedItems)
{ {
m_errorReporter.declarationError( m_errorReporter.declarationError(
@ -239,7 +239,7 @@ bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
if (_varDecl.value) if (_varDecl.value)
{ {
int const stackHeight = m_stackHeight; int const stackHeight = m_stackHeight;
success = boost::apply_visitor(*this, *_varDecl.value); success = std::visit(*this, *_varDecl.value);
int numValues = m_stackHeight - stackHeight; int numValues = m_stackHeight - stackHeight;
if (numValues != numVariables) if (numValues != numVariables)
{ {
@ -261,7 +261,7 @@ bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
for (auto const& variable: _varDecl.variables) for (auto const& variable: _varDecl.variables)
{ {
expectValidType(variable.type.str(), variable.location); expectValidType(variable.type.str(), variable.location);
m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name))); m_activeVariables.insert(&std::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
} }
m_info.stackHeightInfo[&_varDecl] = m_stackHeight; m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
return success; return success;
@ -276,7 +276,7 @@ bool AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
for (auto const& var: _funDef.parameters + _funDef.returnVariables) for (auto const& var: _funDef.parameters + _funDef.returnVariables)
{ {
expectValidType(var.type.str(), var.location); expectValidType(var.type.str(), var.location);
m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name))); m_activeVariables.insert(&std::get<Scope::Variable>(varScope.identifiers.at(var.name)));
} }
int const stackHeight = m_stackHeight; int const stackHeight = m_stackHeight;
@ -352,15 +352,15 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall)
success = false; success = false;
else if (needsLiteralArguments) else if (needsLiteralArguments)
{ {
if (arg.type() != typeid(Literal)) if (!holds_alternative<Literal>(arg))
m_errorReporter.typeError( m_errorReporter.typeError(
_funCall.functionName.location, _funCall.functionName.location,
"Function expects direct literals as arguments." "Function expects direct literals as arguments."
); );
else if (!m_dataNames.count(boost::get<Literal>(arg).value)) else if (!m_dataNames.count(std::get<Literal>(arg).value))
m_errorReporter.typeError( m_errorReporter.typeError(
_funCall.functionName.location, _funCall.functionName.location,
"Unknown data object \"" + boost::get<Literal>(arg).value.str() + "\"." "Unknown data object \"" + std::get<Literal>(arg).value.str() + "\"."
); );
} }
} }
@ -526,7 +526,7 @@ bool AsmAnalyzer::operator()(Block const& _block)
int const initialStackHeight = m_stackHeight; int const initialStackHeight = m_stackHeight;
for (auto const& s: _block.statements) for (auto const& s: _block.statements)
if (!boost::apply_visitor(*this, s)) if (!std::visit(*this, s))
success = false; success = false;
m_stackHeight -= scope(&_block).numberOfVariables(); m_stackHeight -= scope(&_block).numberOfVariables();
@ -555,7 +555,7 @@ bool AsmAnalyzer::expectExpression(Expression const& _expr)
{ {
bool success = true; bool success = true;
int const initialHeight = m_stackHeight; int const initialHeight = m_stackHeight;
if (!boost::apply_visitor(*this, _expr)) if (!std::visit(*this, _expr))
success = false; success = false;
if (success && !expectDeposit(1, initialHeight, locationOf(_expr))) if (success && !expectDeposit(1, initialHeight, locationOf(_expr)))
success = false; success = false;
@ -586,12 +586,12 @@ bool AsmAnalyzer::checkAssignment(Identifier const& _variable, size_t _valueSize
if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name)) if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
{ {
// Check that it is a variable // Check that it is a variable
if (var->type() != typeid(Scope::Variable)) if (!holds_alternative<Scope::Variable>(*var))
{ {
m_errorReporter.typeError(_variable.location, "Assignment requires variable."); m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
success = false; success = false;
} }
else if (!m_activeVariables.count(&boost::get<Scope::Variable>(*var))) else if (!m_activeVariables.count(&std::get<Scope::Variable>(*var)))
{ {
m_errorReporter.declarationError( m_errorReporter.declarationError(
_variable.location, _variable.location,

View File

@ -30,8 +30,6 @@
#include <libyul/backends/evm/AbstractAssembly.h> #include <libyul/backends/evm/AbstractAssembly.h>
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
#include <boost/variant.hpp>
#include <functional> #include <functional>
#include <list> #include <list>
#include <memory> #include <memory>
@ -53,7 +51,7 @@ struct AsmAnalysisInfo;
* references and performs other checks. * references and performs other checks.
* If all these checks pass, code generation should not throw errors. * If all these checks pass, code generation should not throw errors.
*/ */
class AsmAnalyzer: public boost::static_visitor<bool> class AsmAnalyzer
{ {
public: public:
explicit AsmAnalyzer( explicit AsmAnalyzer(

View File

@ -28,7 +28,6 @@
#include <libevmasm/Instruction.h> #include <libevmasm/Instruction.h>
#include <liblangutil/SourceLocation.h> #include <liblangutil/SourceLocation.h>
#include <boost/variant.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <map> #include <map>
@ -79,7 +78,7 @@ struct Continue { langutil::SourceLocation location; };
/// Leave statement (valid within function) /// Leave statement (valid within function)
struct Leave { langutil::SourceLocation location; }; struct Leave { langutil::SourceLocation location; };
struct LocationExtractor: boost::static_visitor<langutil::SourceLocation> struct LocationExtractor
{ {
template <class T> langutil::SourceLocation operator()(T const& _node) const template <class T> langutil::SourceLocation operator()(T const& _node) const
{ {
@ -90,7 +89,7 @@ struct LocationExtractor: boost::static_visitor<langutil::SourceLocation>
/// Extracts the source location from an inline assembly node. /// Extracts the source location from an inline assembly node.
template <class T> inline langutil::SourceLocation locationOf(T const& _node) template <class T> inline langutil::SourceLocation locationOf(T const& _node)
{ {
return boost::apply_visitor(LocationExtractor(), _node); return std::visit(LocationExtractor(), _node);
} }
} }

View File

@ -22,7 +22,7 @@
#pragma once #pragma once
#include <boost/variant.hpp> #include <variant>
namespace yul namespace yul
{ {
@ -46,7 +46,7 @@ struct Block;
struct TypedName; struct TypedName;
using Expression = boost::variant<FunctionCall, Identifier, Literal>; using Expression = std::variant<FunctionCall, Identifier, Literal>;
using Statement = boost::variant<ExpressionStatement, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Break, Continue, Leave, Block>; using Statement = std::variant<ExpressionStatement, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Break, Continue, Leave, Block>;
} }

View File

@ -83,7 +83,7 @@ Json::Value AsmJsonConverter::operator()(Assignment const& _node) const
Json::Value ret = createAstNode(_node.location, "YulAssignment"); Json::Value ret = createAstNode(_node.location, "YulAssignment");
for (auto const& var: _node.variableNames) for (auto const& var: _node.variableNames)
ret["variableNames"].append((*this)(var)); ret["variableNames"].append((*this)(var));
ret["value"] = _node.value ? boost::apply_visitor(*this, *_node.value) : Json::nullValue; ret["value"] = _node.value ? std::visit(*this, *_node.value) : Json::nullValue;
return ret; return ret;
} }
@ -98,7 +98,7 @@ Json::Value AsmJsonConverter::operator()(FunctionCall const& _node) const
Json::Value AsmJsonConverter::operator()(ExpressionStatement const& _node) const Json::Value AsmJsonConverter::operator()(ExpressionStatement const& _node) const
{ {
Json::Value ret = createAstNode(_node.location, "YulExpressionStatement"); Json::Value ret = createAstNode(_node.location, "YulExpressionStatement");
ret["expression"] = boost::apply_visitor(*this, _node.expression); ret["expression"] = std::visit(*this, _node.expression);
return ret; return ret;
} }
@ -108,7 +108,7 @@ Json::Value AsmJsonConverter::operator()(VariableDeclaration const& _node) const
for (auto const& var: _node.variables) for (auto const& var: _node.variables)
ret["variables"].append((*this)(var)); ret["variables"].append((*this)(var));
ret["value"] = _node.value ? boost::apply_visitor(*this, *_node.value) : Json::nullValue; ret["value"] = _node.value ? std::visit(*this, *_node.value) : Json::nullValue;
return ret; return ret;
} }
@ -130,7 +130,7 @@ Json::Value AsmJsonConverter::operator()(If const& _node) const
{ {
solAssert(_node.condition, "Invalid if condition."); solAssert(_node.condition, "Invalid if condition.");
Json::Value ret = createAstNode(_node.location, "YulIf"); Json::Value ret = createAstNode(_node.location, "YulIf");
ret["condition"] = boost::apply_visitor(*this, *_node.condition); ret["condition"] = std::visit(*this, *_node.condition);
ret["body"] = (*this)(_node.body); ret["body"] = (*this)(_node.body);
return ret; return ret;
} }
@ -139,7 +139,7 @@ Json::Value AsmJsonConverter::operator()(Switch const& _node) const
{ {
solAssert(_node.expression, "Invalid expression pointer."); solAssert(_node.expression, "Invalid expression pointer.");
Json::Value ret = createAstNode(_node.location, "YulSwitch"); Json::Value ret = createAstNode(_node.location, "YulSwitch");
ret["expression"] = boost::apply_visitor(*this, *_node.expression); ret["expression"] = std::visit(*this, *_node.expression);
for (auto const& var: _node.cases) for (auto const& var: _node.cases)
ret["cases"].append((*this)(var)); ret["cases"].append((*this)(var));
return ret; return ret;
@ -158,7 +158,7 @@ Json::Value AsmJsonConverter::operator()(ForLoop const& _node) const
solAssert(_node.condition, "Invalid for loop condition."); solAssert(_node.condition, "Invalid for loop condition.");
Json::Value ret = createAstNode(_node.location, "YulForLoop"); Json::Value ret = createAstNode(_node.location, "YulForLoop");
ret["pre"] = (*this)(_node.pre); ret["pre"] = (*this)(_node.pre);
ret["condition"] = boost::apply_visitor(*this, *_node.condition); ret["condition"] = std::visit(*this, *_node.condition);
ret["post"] = (*this)(_node.post); ret["post"] = (*this)(_node.post);
ret["body"] = (*this)(_node.body); ret["body"] = (*this)(_node.body);
return ret; return ret;
@ -195,7 +195,7 @@ Json::Value AsmJsonConverter::vectorOfVariantsToJson(vector<T> const& _vec) cons
{ {
Json::Value ret{Json::arrayValue}; Json::Value ret{Json::arrayValue};
for (auto const& var: _vec) for (auto const& var: _vec)
ret.append(boost::apply_visitor(*this, var)); ret.append(std::visit(*this, var));
return ret; return ret;
} }

View File

@ -177,7 +177,7 @@ Statement Parser::parseStatement()
while (true) while (true)
{ {
if (elementary.type() != typeid(Identifier)) if (!holds_alternative<Identifier>(elementary))
{ {
auto const token = currentToken() == Token::Comma ? "," : ":="; auto const token = currentToken() == Token::Comma ? "," : ":=";
@ -189,7 +189,7 @@ Statement Parser::parseStatement()
); );
} }
auto const& identifier = boost::get<Identifier>(elementary); auto const& identifier = std::get<Identifier>(elementary);
if (m_dialect.builtin(identifier.name)) if (m_dialect.builtin(identifier.name))
fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\".");
@ -205,7 +205,7 @@ Statement Parser::parseStatement()
} }
Assignment assignment = Assignment assignment =
createWithLocation<Assignment>(boost::get<Identifier>(elementary).location); createWithLocation<Assignment>(std::get<Identifier>(elementary).location);
assignment.variableNames = std::move(variableNames); assignment.variableNames = std::move(variableNames);
expectToken(Token::AssemblyAssign); expectToken(Token::AssemblyAssign);
@ -220,14 +220,14 @@ Statement Parser::parseStatement()
break; break;
} }
if (elementary.type() == typeid(Identifier)) if (holds_alternative<Identifier>(elementary))
{ {
Identifier& identifier = boost::get<Identifier>(elementary); Identifier& identifier = std::get<Identifier>(elementary);
return ExpressionStatement{identifier.location, { move(identifier) }}; return ExpressionStatement{identifier.location, { move(identifier) }};
} }
else if (elementary.type() == typeid(Literal)) else if (holds_alternative<Literal>(elementary))
{ {
Expression expr = boost::get<Literal>(elementary); Expression expr = std::get<Literal>(elementary);
return ExpressionStatement{locationOf(expr), expr}; return ExpressionStatement{locationOf(expr), expr};
} }
else else
@ -247,9 +247,9 @@ Case Parser::parseCase()
{ {
advance(); advance();
ElementaryOperation literal = parseElementaryOperation(); ElementaryOperation literal = parseElementaryOperation();
if (literal.type() != typeid(Literal)) if (!holds_alternative<Literal>(literal))
fatalParserError("Literal expected."); fatalParserError("Literal expected.");
_case.value = make_unique<Literal>(boost::get<Literal>(std::move(literal))); _case.value = make_unique<Literal>(std::get<Literal>(std::move(literal)));
} }
else else
solAssert(false, "Case or default case expected."); solAssert(false, "Case or default case expected.");
@ -286,14 +286,14 @@ Expression Parser::parseExpression()
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
ElementaryOperation operation = parseElementaryOperation(); ElementaryOperation operation = parseElementaryOperation();
if (operation.type() == typeid(FunctionCall) || currentToken() == Token::LParen) if (holds_alternative<FunctionCall>(operation) || currentToken() == Token::LParen)
return parseCall(std::move(operation)); return parseCall(std::move(operation));
else if (operation.type() == typeid(Identifier)) else if (holds_alternative<Identifier>(operation))
return boost::get<Identifier>(operation); return std::get<Identifier>(operation);
else else
{ {
solAssert(operation.type() == typeid(Literal), ""); solAssert(holds_alternative<Literal>(operation), "");
return boost::get<Literal>(operation); return std::get<Literal>(operation);
} }
} }
@ -464,13 +464,13 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp)
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
FunctionCall ret; FunctionCall ret;
if (_initialOp.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_initialOp))
{ {
ret.functionName = std::move(boost::get<Identifier>(_initialOp)); ret.functionName = std::move(std::get<Identifier>(_initialOp));
ret.location = ret.functionName.location; ret.location = ret.functionName.location;
} }
else if (_initialOp.type() == typeid(FunctionCall)) else if (holds_alternative<FunctionCall>(_initialOp))
ret = std::move(boost::get<FunctionCall>(_initialOp)); ret = std::move(std::get<FunctionCall>(_initialOp));
else else
fatalParserError( fatalParserError(
m_dialect.flavour == AsmFlavour::Yul ? m_dialect.flavour == AsmFlavour::Yul ?

View File

@ -30,9 +30,9 @@
#include <liblangutil/ParserBase.h> #include <liblangutil/ParserBase.h>
#include <memory> #include <memory>
#include <variant>
#include <vector> #include <vector>
namespace yul namespace yul
{ {
@ -56,7 +56,7 @@ public:
static std::map<std::string, dev::eth::Instruction> const& instructions(); static std::map<std::string, dev::eth::Instruction> const& instructions();
protected: protected:
using ElementaryOperation = boost::variant<Instruction, Literal, Identifier, FunctionCall>; using ElementaryOperation = std::variant<Instruction, Literal, Identifier, FunctionCall>;
/// Creates an inline assembly node with the given source location. /// Creates an inline assembly node with the given source location.
template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const

View File

@ -90,7 +90,7 @@ string AsmPrinter::operator()(Identifier const& _identifier) const
string AsmPrinter::operator()(ExpressionStatement const& _statement) const string AsmPrinter::operator()(ExpressionStatement const& _statement) const
{ {
return boost::apply_visitor(*this, _statement.expression); return std::visit(*this, _statement.expression);
} }
string AsmPrinter::operator()(Assignment const& _assignment) const string AsmPrinter::operator()(Assignment const& _assignment) const
@ -99,7 +99,7 @@ string AsmPrinter::operator()(Assignment const& _assignment) const
string variables = (*this)(_assignment.variableNames.front()); string variables = (*this)(_assignment.variableNames.front());
for (size_t i = 1; i < _assignment.variableNames.size(); ++i) for (size_t i = 1; i < _assignment.variableNames.size(); ++i)
variables += ", " + (*this)(_assignment.variableNames[i]); variables += ", " + (*this)(_assignment.variableNames[i]);
return variables + " := " + boost::apply_visitor(*this, *_assignment.value); return variables + " := " + std::visit(*this, *_assignment.value);
} }
string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) const string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) const
@ -114,7 +114,7 @@ string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) c
if (_variableDeclaration.value) if (_variableDeclaration.value)
{ {
out += " := "; out += " := ";
out += boost::apply_visitor(*this, *_variableDeclaration.value); out += std::visit(*this, *_variableDeclaration.value);
} }
return out; return out;
} }
@ -149,7 +149,7 @@ string AsmPrinter::operator()(FunctionCall const& _functionCall) const
return return
(*this)(_functionCall.functionName) + "(" + (*this)(_functionCall.functionName) + "(" +
boost::algorithm::join( boost::algorithm::join(
_functionCall.arguments | boost::adaptors::transformed(boost::apply_visitor(*this)), _functionCall.arguments | boost::adaptors::transformed([&](auto&& _node) { return std::visit(*this, _node); }),
", " ) + ", " ) +
")"; ")";
} }
@ -161,13 +161,13 @@ string AsmPrinter::operator()(If const& _if) const
char delim = '\n'; char delim = '\n';
if (body.find('\n') == string::npos) if (body.find('\n') == string::npos)
delim = ' '; delim = ' ';
return "if " + boost::apply_visitor(*this, *_if.condition) + delim + (*this)(_if.body); return "if " + std::visit(*this, *_if.condition) + delim + (*this)(_if.body);
} }
string AsmPrinter::operator()(Switch const& _switch) const string AsmPrinter::operator()(Switch const& _switch) const
{ {
solAssert(_switch.expression, "Invalid expression pointer."); solAssert(_switch.expression, "Invalid expression pointer.");
string out = "switch " + boost::apply_visitor(*this, *_switch.expression); string out = "switch " + std::visit(*this, *_switch.expression);
for (auto const& _case: _switch.cases) for (auto const& _case: _switch.cases)
{ {
if (!_case.value) if (!_case.value)
@ -183,7 +183,7 @@ string AsmPrinter::operator()(ForLoop const& _forLoop) const
{ {
solAssert(_forLoop.condition, "Invalid for loop condition."); solAssert(_forLoop.condition, "Invalid for loop condition.");
string pre = (*this)(_forLoop.pre); string pre = (*this)(_forLoop.pre);
string condition = boost::apply_visitor(*this, *_forLoop.condition); string condition = std::visit(*this, *_forLoop.condition);
string post = (*this)(_forLoop.post); string post = (*this)(_forLoop.post);
char delim = '\n'; char delim = '\n';
if ( if (
@ -217,7 +217,7 @@ string AsmPrinter::operator()(Block const& _block) const
if (_block.statements.empty()) if (_block.statements.empty())
return "{ }"; return "{ }";
string body = boost::algorithm::join( string body = boost::algorithm::join(
_block.statements | boost::adaptors::transformed(boost::apply_visitor(*this)), _block.statements | boost::adaptors::transformed([&](auto&& _node) { return std::visit(*this, _node); }),
"\n" "\n"
); );
if (body.size() < 30 && body.find('\n') == string::npos) if (body.size() < 30 && body.find('\n') == string::npos)

View File

@ -26,12 +26,10 @@
#include <libyul/YulString.h> #include <libyul/YulString.h>
#include <boost/variant.hpp>
namespace yul namespace yul
{ {
class AsmPrinter: public boost::static_visitor<std::string> class AsmPrinter
{ {
public: public:
explicit AsmPrinter(bool _yul = false): m_yul(_yul) {} explicit AsmPrinter(bool _yul = false): m_yul(_yul) {}

View File

@ -58,7 +58,7 @@ Scope::Identifier* Scope::lookup(YulString _name)
auto id = s->identifiers.find(_name); auto id = s->identifiers.find(_name);
if (id != s->identifiers.end()) if (id != s->identifiers.end())
{ {
if (crossedFunctionBoundary && id->second.type() == typeid(Scope::Variable)) if (crossedFunctionBoundary && holds_alternative<Scope::Variable>(id->second))
return nullptr; return nullptr;
else else
return &id->second; return &id->second;
@ -84,7 +84,7 @@ size_t Scope::numberOfVariables() const
{ {
size_t count = 0; size_t count = 0;
for (auto const& identifier: identifiers) for (auto const& identifier: identifiers)
if (identifier.second.type() == typeid(Scope::Variable)) if (holds_alternative<Scope::Variable>(identifier.second))
count++; count++;
return count; return count;
} }

View File

@ -26,11 +26,10 @@
#include <libdevcore/Visitor.h> #include <libdevcore/Visitor.h>
#include <boost/variant.hpp>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <variant>
namespace yul namespace yul
{ {
@ -48,7 +47,7 @@ struct Scope
std::vector<YulType> returns; std::vector<YulType> returns;
}; };
using Identifier = boost::variant<Variable, Label, Function>; using Identifier = std::variant<Variable, Label, Function>;
using Visitor = dev::GenericVisitor<Variable const, Label const, Function const>; using Visitor = dev::GenericVisitor<Variable const, Label const, Function const>;
using NonconstVisitor = dev::GenericVisitor<Variable, Label, Function>; using NonconstVisitor = dev::GenericVisitor<Variable, Label, Function>;
@ -74,7 +73,7 @@ struct Scope
{ {
if (Identifier* id = lookup(_name)) if (Identifier* id = lookup(_name))
{ {
boost::apply_visitor(_visitor, *id); std::visit(_visitor, *id);
return true; return true;
} }
else else

View File

@ -47,7 +47,7 @@ ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter):
bool ScopeFiller::operator()(ExpressionStatement const& _expr) bool ScopeFiller::operator()(ExpressionStatement const& _expr)
{ {
return boost::apply_visitor(*this, _expr.expression); return std::visit(*this, _expr.expression);
} }
bool ScopeFiller::operator()(VariableDeclaration const& _varDecl) bool ScopeFiller::operator()(VariableDeclaration const& _varDecl)
@ -102,7 +102,7 @@ bool ScopeFiller::operator()(ForLoop const& _forLoop)
if (!(*this)(_forLoop.pre)) if (!(*this)(_forLoop.pre))
success = false; success = false;
m_currentScope = &scope(&_forLoop.pre); m_currentScope = &scope(&_forLoop.pre);
if (!boost::apply_visitor(*this, *_forLoop.condition)) if (!std::visit(*this, *_forLoop.condition))
success = false; success = false;
if (!(*this)(_forLoop.body)) if (!(*this)(_forLoop.body))
success = false; success = false;
@ -123,11 +123,11 @@ bool ScopeFiller::operator()(Block const& _block)
// First visit all functions to make them create // First visit all functions to make them create
// an entry in the scope according to their visibility. // an entry in the scope according to their visibility.
for (auto const& s: _block.statements) for (auto const& s: _block.statements)
if (s.type() == typeid(FunctionDefinition)) if (holds_alternative<FunctionDefinition>(s))
if (!registerFunction(boost::get<FunctionDefinition>(s))) if (!registerFunction(std::get<FunctionDefinition>(s)))
success = false; success = false;
for (auto const& s: _block.statements) for (auto const& s: _block.statements)
if (!boost::apply_visitor(*this, s)) if (!std::visit(*this, s))
success = false; success = false;
m_currentScope = m_currentScope->superScope; m_currentScope = m_currentScope->superScope;

View File

@ -22,8 +22,6 @@
#include <libyul/AsmDataForward.h> #include <libyul/AsmDataForward.h>
#include <boost/variant.hpp>
#include <functional> #include <functional>
#include <memory> #include <memory>
@ -44,7 +42,7 @@ struct AsmAnalysisInfo;
* Fills scopes with identifiers and checks for name clashes. * Fills scopes with identifiers and checks for name clashes.
* Does not resolve references. * Does not resolve references.
*/ */
class ScopeFiller: public boost::static_visitor<bool> class ScopeFiller
{ {
public: public:
ScopeFiller(AsmAnalysisInfo& _info, langutil::ErrorReporter& _errorReporter); ScopeFiller(AsmAnalysisInfo& _info, langutil::ErrorReporter& _errorReporter);

View File

@ -27,6 +27,8 @@
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <variant>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace yul; using namespace yul;
@ -35,13 +37,13 @@ using Representation = ConstantOptimiser::Representation;
namespace namespace
{ {
struct MiniEVMInterpreter: boost::static_visitor<u256> struct MiniEVMInterpreter
{ {
explicit MiniEVMInterpreter(EVMDialect const& _dialect): m_dialect(_dialect) {} explicit MiniEVMInterpreter(EVMDialect const& _dialect): m_dialect(_dialect) {}
u256 eval(Expression const& _expr) u256 eval(Expression const& _expr)
{ {
return boost::apply_visitor(*this, _expr); return std::visit(*this, _expr);
} }
u256 eval(dev::eth::Instruction _instr, vector<Expression> const& _arguments) u256 eval(dev::eth::Instruction _instr, vector<Expression> const& _arguments)
@ -88,9 +90,9 @@ struct MiniEVMInterpreter: boost::static_visitor<u256>
void ConstantOptimiser::visit(Expression& _e) void ConstantOptimiser::visit(Expression& _e)
{ {
if (_e.type() == typeid(Literal)) if (holds_alternative<Literal>(_e))
{ {
Literal const& literal = boost::get<Literal>(_e); Literal const& literal = std::get<Literal>(_e);
if (literal.kind != LiteralKind::Number) if (literal.kind != LiteralKind::Number)
return; return;
@ -111,7 +113,7 @@ Expression const* RepresentationFinder::tryFindRepresentation(dev::u256 const& _
return nullptr; return nullptr;
Representation const& repr = findRepresentation(_value); Representation const& repr = findRepresentation(_value);
if (repr.expression->type() == typeid(Literal)) if (holds_alternative<Literal>(*repr.expression))
return nullptr; return nullptr;
else else
return repr.expression.get(); return repr.expression.get();

View File

@ -29,6 +29,8 @@
#include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/reversed.hpp>
#include <variant>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace yul; using namespace yul;
@ -146,9 +148,9 @@ void CodeTransform::freeUnusedVariables()
return; return;
for (auto const& identifier: m_scope->identifiers) for (auto const& identifier: m_scope->identifiers)
if (identifier.second.type() == typeid(Scope::Variable)) if (holds_alternative<Scope::Variable>(identifier.second))
{ {
Scope::Variable const& var = boost::get<Scope::Variable>(identifier.second); Scope::Variable const& var = std::get<Scope::Variable>(identifier.second);
if (m_variablesScheduledForDeletion.count(&var)) if (m_variablesScheduledForDeletion.count(&var))
deleteVariable(var); deleteVariable(var);
} }
@ -179,7 +181,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
int height = m_assembly.stackHeight(); int height = m_assembly.stackHeight();
if (_varDecl.value) if (_varDecl.value)
{ {
boost::apply_visitor(*this, *_varDecl.value); std::visit(*this, *_varDecl.value);
expectDeposit(numVariables, height); expectDeposit(numVariables, height);
} }
else else
@ -193,7 +195,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex) for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex)
{ {
YulString varName = _varDecl.variables[varIndex].name; YulString varName = _varDecl.variables[varIndex].name;
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(varName)); auto& var = std::get<Scope::Variable>(m_scope->identifiers.at(varName));
m_context->variableStackHeights[&var] = height + varIndex; m_context->variableStackHeights[&var] = height + varIndex;
if (!m_allowStackOpt) if (!m_allowStackOpt)
continue; continue;
@ -242,7 +244,7 @@ void CodeTransform::stackError(StackTooDeepError _error, int _targetStackHeight)
void CodeTransform::operator()(Assignment const& _assignment) void CodeTransform::operator()(Assignment const& _assignment)
{ {
int height = m_assembly.stackHeight(); int height = m_assembly.stackHeight();
boost::apply_visitor(*this, *_assignment.value); std::visit(*this, *_assignment.value);
expectDeposit(_assignment.variableNames.size(), height); expectDeposit(_assignment.variableNames.size(), height);
m_assembly.setSourceLocation(_assignment.location); m_assembly.setSourceLocation(_assignment.location);
@ -253,7 +255,7 @@ void CodeTransform::operator()(Assignment const& _assignment)
void CodeTransform::operator()(ExpressionStatement const& _statement) void CodeTransform::operator()(ExpressionStatement const& _statement)
{ {
m_assembly.setSourceLocation(_statement.location); m_assembly.setSourceLocation(_statement.location);
boost::apply_visitor(*this, _statement.expression); std::visit(*this, _statement.expression);
checkStackHeight(&_statement); checkStackHeight(&_statement);
} }
@ -423,7 +425,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
{ {
solAssert(m_scope, ""); solAssert(m_scope, "");
solAssert(m_scope->identifiers.count(_function.name), ""); solAssert(m_scope->identifiers.count(_function.name), "");
Scope::Function& function = boost::get<Scope::Function>(m_scope->identifiers.at(_function.name)); Scope::Function& function = std::get<Scope::Function>(m_scope->identifiers.at(_function.name));
int const localStackAdjustment = m_evm15 ? 0 : 1; int const localStackAdjustment = m_evm15 ? 0 : 1;
int height = localStackAdjustment; int height = localStackAdjustment;
@ -432,7 +434,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
solAssert(varScope, ""); solAssert(varScope, "");
for (auto const& v: _function.parameters | boost::adaptors::reversed) for (auto const& v: _function.parameters | boost::adaptors::reversed)
{ {
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name)); auto& var = std::get<Scope::Variable>(varScope->identifiers.at(v.name));
m_context->variableStackHeights[&var] = height++; m_context->variableStackHeights[&var] = height++;
} }
@ -450,7 +452,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
for (auto const& v: _function.returnVariables) for (auto const& v: _function.returnVariables)
{ {
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name)); auto& var = std::get<Scope::Variable>(varScope->identifiers.at(v.name));
m_context->variableStackHeights[&var] = height++; m_context->variableStackHeights[&var] = height++;
// Preset stack slots for return variables to zero. // Preset stack slots for return variables to zero.
m_assembly.appendConstant(u256(0)); m_assembly.appendConstant(u256(0));
@ -681,7 +683,7 @@ AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope:
void CodeTransform::visitExpression(Expression const& _expression) void CodeTransform::visitExpression(Expression const& _expression)
{ {
int height = m_assembly.stackHeight(); int height = m_assembly.stackHeight();
boost::apply_visitor(*this, _expression); std::visit(*this, _expression);
expectDeposit(1, height); expectDeposit(1, height);
} }
@ -692,7 +694,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements)
for (auto const& statement: _statements) for (auto const& statement: _statements)
{ {
freeUnusedVariables(); freeUnusedVariables();
auto const* functionDefinition = boost::get<FunctionDefinition>(&statement); auto const* functionDefinition = std::get_if<FunctionDefinition>(&statement);
if (functionDefinition && !jumpTarget) if (functionDefinition && !jumpTarget)
{ {
m_assembly.setSourceLocation(locationOf(statement)); m_assembly.setSourceLocation(locationOf(statement));
@ -705,7 +707,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements)
jumpTarget = std::nullopt; jumpTarget = std::nullopt;
} }
boost::apply_visitor(*this, statement); std::visit(*this, statement);
} }
// we may have a leftover jumpTarget // we may have a leftover jumpTarget
if (jumpTarget) if (jumpTarget)
@ -723,9 +725,9 @@ void CodeTransform::finalizeBlock(Block const& _block, int blockStartStackHeight
// pop variables // pop variables
solAssert(m_info.scopes.at(&_block).get() == m_scope, ""); solAssert(m_info.scopes.at(&_block).get() == m_scope, "");
for (auto const& id: m_scope->identifiers) for (auto const& id: m_scope->identifiers)
if (id.second.type() == typeid(Scope::Variable)) if (holds_alternative<Scope::Variable>(id.second))
{ {
Scope::Variable const& var = boost::get<Scope::Variable>(id.second); Scope::Variable const& var = std::get<Scope::Variable>(id.second);
if (m_allowStackOpt) if (m_allowStackOpt)
{ {
solAssert(!m_context->variableStackHeights.count(&var), ""); solAssert(!m_context->variableStackHeights.count(&var), "");
@ -753,7 +755,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
solAssert(m_scope, ""); solAssert(m_scope, "");
if (auto var = m_scope->lookup(_variableName.name)) if (auto var = m_scope->lookup(_variableName.name))
{ {
Scope::Variable const& _var = boost::get<Scope::Variable>(*var); Scope::Variable const& _var = std::get<Scope::Variable>(*var);
if (int heightDiff = variableHeightDiff(_var, _variableName.name, true)) if (int heightDiff = variableHeightDiff(_var, _variableName.name, true))
m_assembly.appendInstruction(dev::eth::swapInstruction(heightDiff - 1)); m_assembly.appendInstruction(dev::eth::swapInstruction(heightDiff - 1));
m_assembly.appendInstruction(dev::eth::Instruction::POP); m_assembly.appendInstruction(dev::eth::Instruction::POP);

View File

@ -27,8 +27,6 @@
#include <libyul/AsmDataForward.h> #include <libyul/AsmDataForward.h>
#include <libyul/AsmScope.h> #include <libyul/AsmScope.h>
#include <boost/variant.hpp>
#include <optional> #include <optional>
#include <stack> #include <stack>
@ -108,7 +106,7 @@ private:
Scope* m_scope = nullptr; Scope* m_scope = nullptr;
}; };
class CodeTransform: public boost::static_visitor<> class CodeTransform
{ {
public: public:
/// Create the code transformer. /// Create the code transformer.

View File

@ -113,7 +113,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
yulAssert(_context.currentObject, "No object available."); yulAssert(_context.currentObject, "No object available.");
yulAssert(_call.arguments.size() == 1, ""); yulAssert(_call.arguments.size() == 1, "");
Expression const& arg = _call.arguments.front(); Expression const& arg = _call.arguments.front();
YulString dataName = boost::get<Literal>(arg).value; YulString dataName = std::get<Literal>(arg).value;
if (_context.currentObject->name == dataName) if (_context.currentObject->name == dataName)
_assembly.appendAssemblySize(); _assembly.appendAssemblySize();
else else
@ -134,7 +134,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
yulAssert(_context.currentObject, "No object available."); yulAssert(_context.currentObject, "No object available.");
yulAssert(_call.arguments.size() == 1, ""); yulAssert(_call.arguments.size() == 1, "");
Expression const& arg = _call.arguments.front(); Expression const& arg = _call.arguments.front();
YulString dataName = boost::get<Literal>(arg).value; YulString dataName = std::get<Literal>(arg).value;
if (_context.currentObject->name == dataName) if (_context.currentObject->name == dataName)
_assembly.appendConstant(0); _assembly.appendConstant(0);
else else

View File

@ -90,7 +90,7 @@ void GasMeterVisitor::operator()(Literal const& _lit)
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1); m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1);
m_dataGas += m_dataGas +=
singleByteDataGas() + singleByteDataGas() +
size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation)); size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation, m_dialect.evmVersion()));
} }
void GasMeterVisitor::operator()(Identifier const&) void GasMeterVisitor::operator()(Identifier const&)
@ -102,7 +102,7 @@ void GasMeterVisitor::operator()(Identifier const&)
size_t GasMeterVisitor::singleByteDataGas() const size_t GasMeterVisitor::singleByteDataGas() const
{ {
if (m_isCreation) if (m_isCreation)
return dev::eth::GasCosts::txDataNonZeroGas; return dev::eth::GasCosts::txDataNonZeroGas(m_dialect.evmVersion());
else else
return dev::eth::GasCosts::createDataGas; return dev::eth::GasCosts::createDataGas;
} }

View File

@ -298,12 +298,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
// they are references to object names that should not end up in the code. // they are references to object names that should not end up in the code.
if (_call.functionName == "dataoffset") if (_call.functionName == "dataoffset")
{ {
string name = boost::get<StringLiteral>(_call.arguments.at(0)).value; string name = std::get<StringLiteral>(_call.arguments.at(0)).value;
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first); return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first);
} }
else if (_call.functionName == "datasize") else if (_call.functionName == "datasize")
{ {
string name = boost::get<StringLiteral>(_call.arguments.at(0)).value; string name = std::get<StringLiteral>(_call.arguments.at(0)).value;
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second); return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second);
} }
@ -333,7 +333,7 @@ bytes BinaryTransform::operator()(FunctionCall const& _call)
bytes BinaryTransform::operator()(LocalAssignment const& _assignment) bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
{ {
return return
boost::apply_visitor(*this, *_assignment.value) + std::visit(*this, *_assignment.value) +
toBytes(Opcode::LocalSet) + toBytes(Opcode::LocalSet) +
lebEncode(m_locals.at(_assignment.variableName)); lebEncode(m_locals.at(_assignment.variableName));
} }
@ -341,7 +341,7 @@ bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
bytes BinaryTransform::operator()(GlobalAssignment const& _assignment) bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
{ {
return return
boost::apply_visitor(*this, *_assignment.value) + std::visit(*this, *_assignment.value) +
toBytes(Opcode::GlobalSet) + toBytes(Opcode::GlobalSet) +
lebEncode(m_globals.at(_assignment.variableName)); lebEncode(m_globals.at(_assignment.variableName));
} }
@ -349,7 +349,7 @@ bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
bytes BinaryTransform::operator()(If const& _if) bytes BinaryTransform::operator()(If const& _if)
{ {
bytes result = bytes result =
boost::apply_visitor(*this, *_if.condition) + std::visit(*this, *_if.condition) +
toBytes(Opcode::If) + toBytes(Opcode::If) +
toBytes(ValueType::Void); toBytes(ValueType::Void);
@ -564,7 +564,7 @@ bytes BinaryTransform::visit(vector<Expression> const& _expressions)
{ {
bytes result; bytes result;
for (auto const& expr: _expressions) for (auto const& expr: _expressions)
result += boost::apply_visitor(*this, expr); result += std::visit(*this, expr);
return result; return result;
} }
@ -572,7 +572,7 @@ bytes BinaryTransform::visitReversed(vector<Expression> const& _expressions)
{ {
bytes result; bytes result;
for (auto const& expr: _expressions | boost::adaptors::reversed) for (auto const& expr: _expressions | boost::adaptors::reversed)
result += boost::apply_visitor(*this, expr); result += std::visit(*this, expr);
return result; return result;
} }

View File

@ -35,7 +35,7 @@ namespace wasm
/** /**
* Web assembly to binary transform. * Web assembly to binary transform.
*/ */
class BinaryTransform: public boost::static_visitor<dev::bytes> class BinaryTransform
{ {
public: public:
static dev::bytes run(Module const& _module); static dev::bytes run(Module const& _module);

View File

@ -694,7 +694,7 @@ Object EVMToEWasmTranslator::run(Object const& _object)
if (!m_polyfill) if (!m_polyfill)
parsePolyfill(); parsePolyfill();
Block ast = boost::get<Block>(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code)); Block ast = std::get<Block>(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code));
set<YulString> reservedIdentifiers; set<YulString> reservedIdentifiers;
NameDispenser nameDispenser{m_dialect, ast, reservedIdentifiers}; NameDispenser nameDispenser{m_dialect, ast, reservedIdentifiers};
OptimiserStepContext context{m_dialect, nameDispenser, reservedIdentifiers}; OptimiserStepContext context{m_dialect, nameDispenser, reservedIdentifiers};
@ -752,6 +752,6 @@ void EVMToEWasmTranslator::parsePolyfill()
m_polyfillFunctions.clear(); m_polyfillFunctions.clear();
for (auto const& statement: m_polyfill->statements) for (auto const& statement: m_polyfill->statements)
m_polyfillFunctions.insert(boost::get<FunctionDefinition>(statement).name); m_polyfillFunctions.insert(std::get<FunctionDefinition>(statement).name);
} }

View File

@ -20,7 +20,7 @@
#pragma once #pragma once
#include <boost/variant.hpp> #include <variant>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
@ -45,7 +45,7 @@ struct Loop;
struct Break; struct Break;
struct BreakIf; struct BreakIf;
struct Return; struct Return;
using Expression = boost::variant< using Expression = std::variant<
Literal, StringLiteral, LocalVariable, GlobalVariable, Literal, StringLiteral, LocalVariable, GlobalVariable,
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment, FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
Block, If, Loop, Break, BreakIf, Return Block, If, Loop, Break, BreakIf, Return

View File

@ -45,11 +45,11 @@ wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const&
for (auto const& statement: _ast.statements) for (auto const& statement: _ast.statements)
{ {
yulAssert( yulAssert(
statement.type() == typeid(yul::FunctionDefinition), holds_alternative<yul::FunctionDefinition>(statement),
"Expected only function definitions at the highest level." "Expected only function definitions at the highest level."
); );
if (statement.type() == typeid(yul::FunctionDefinition)) if (holds_alternative<yul::FunctionDefinition>(statement))
module.functions.emplace_back(transform.translateFunction(boost::get<yul::FunctionDefinition>(statement))); module.functions.emplace_back(transform.translateFunction(std::get<yul::FunctionDefinition>(statement)));
} }
for (auto& imp: transform.m_functionsToImport) for (auto& imp: transform.m_functionsToImport)
@ -139,7 +139,7 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call)
{ {
vector<wasm::Expression> literals; vector<wasm::Expression> literals;
for (auto const& arg: _call.arguments) for (auto const& arg: _call.arguments)
literals.emplace_back(wasm::StringLiteral{boost::get<Literal>(arg).value.str()}); literals.emplace_back(wasm::StringLiteral{std::get<Literal>(arg).value.str()});
return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)}; return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)};
} }
else else
@ -284,12 +284,12 @@ wasm::Expression EWasmCodeTransform::operator()(Block const& _block)
unique_ptr<wasm::Expression> EWasmCodeTransform::visit(yul::Expression const& _expression) unique_ptr<wasm::Expression> EWasmCodeTransform::visit(yul::Expression const& _expression)
{ {
return make_unique<wasm::Expression>(boost::apply_visitor(*this, _expression)); return make_unique<wasm::Expression>(std::visit(*this, _expression));
} }
wasm::Expression EWasmCodeTransform::visitReturnByValue(yul::Expression const& _expression) wasm::Expression EWasmCodeTransform::visitReturnByValue(yul::Expression const& _expression)
{ {
return boost::apply_visitor(*this, _expression); return std::visit(*this, _expression);
} }
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const& _expressions) vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const& _expressions)
@ -302,7 +302,7 @@ vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const
wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement) wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement)
{ {
return boost::apply_visitor(*this, _statement); return std::visit(*this, _statement);
} }
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const& _statements) vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const& _statements)

View File

@ -32,7 +32,7 @@ namespace yul
{ {
struct AsmAnalysisInfo; struct AsmAnalysisInfo;
class EWasmCodeTransform: public boost::static_visitor<wasm::Expression> class EWasmCodeTransform
{ {
public: public:
static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast); static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast);

View File

@ -176,7 +176,7 @@ string EWasmToText::transform(wasm::FunctionDefinition const& _function)
string EWasmToText::visit(wasm::Expression const& _expression) string EWasmToText::visit(wasm::Expression const& _expression)
{ {
return boost::apply_visitor(*this, _expression); return std::visit(*this, _expression);
} }
string EWasmToText::joinTransformed(vector<wasm::Expression> const& _expressions, char _separator) string EWasmToText::joinTransformed(vector<wasm::Expression> const& _expressions, char _separator)

View File

@ -28,7 +28,7 @@ namespace yul
{ {
struct AsmAnalysisInfo; struct AsmAnalysisInfo;
class EWasmToText: public boost::static_visitor<std::string> class EWasmToText
{ {
public: public:
std::string run(wasm::Module const& _module); std::string run(wasm::Module const& _module);

View File

@ -25,6 +25,7 @@
#include <array> #include <array>
#include <map> #include <map>
#include <variant>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -79,13 +80,13 @@ void WordSizeTransform::operator()(Block& _block)
_block.statements, _block.statements,
[&](Statement& _s) -> std::optional<vector<Statement>> [&](Statement& _s) -> std::optional<vector<Statement>>
{ {
if (_s.type() == typeid(VariableDeclaration)) if (holds_alternative<VariableDeclaration>(_s))
{ {
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_s); VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
// Special handling for datasize and dataoffset - they will only need one variable. // Special handling for datasize and dataoffset - they will only need one variable.
if (varDecl.value && varDecl.value->type() == typeid(FunctionCall)) if (varDecl.value && holds_alternative<FunctionCall>(*varDecl.value))
if (BuiltinFunction const* f = m_inputDialect.builtin(boost::get<FunctionCall>(*varDecl.value).functionName.name)) if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*varDecl.value).functionName.name))
if (f->literalArguments) if (f->literalArguments)
{ {
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, ""); yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
@ -106,7 +107,9 @@ void WordSizeTransform::operator()(Block& _block)
return {std::move(ret)}; return {std::move(ret)};
} }
if (!varDecl.value || varDecl.value->type() == typeid(FunctionCall) if (
!varDecl.value ||
holds_alternative<FunctionCall>(*varDecl.value)
) )
{ {
if (varDecl.value) visit(*varDecl.value); if (varDecl.value) visit(*varDecl.value);
@ -114,8 +117,8 @@ void WordSizeTransform::operator()(Block& _block)
return std::nullopt; return std::nullopt;
} }
else if ( else if (
varDecl.value->type() == typeid(Identifier) || holds_alternative<Identifier>(*varDecl.value) ||
varDecl.value->type() == typeid(Literal) holds_alternative<Literal>(*varDecl.value)
) )
{ {
yulAssert(varDecl.variables.size() == 1, ""); yulAssert(varDecl.variables.size() == 1, "");
@ -135,14 +138,14 @@ void WordSizeTransform::operator()(Block& _block)
else else
yulAssert(false, ""); yulAssert(false, "");
} }
else if (_s.type() == typeid(Assignment)) else if (holds_alternative<Assignment>(_s))
{ {
Assignment& assignment = boost::get<Assignment>(_s); Assignment& assignment = std::get<Assignment>(_s);
yulAssert(assignment.value, ""); yulAssert(assignment.value, "");
// Special handling for datasize and dataoffset - they will only need one variable. // Special handling for datasize and dataoffset - they will only need one variable.
if (assignment.value->type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(*assignment.value))
if (BuiltinFunction const* f = m_inputDialect.builtin(boost::get<FunctionCall>(*assignment.value).functionName.name)) if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*assignment.value).functionName.name))
if (f->literalArguments) if (f->literalArguments)
{ {
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, ""); yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
@ -163,15 +166,15 @@ void WordSizeTransform::operator()(Block& _block)
return {std::move(ret)}; return {std::move(ret)};
} }
if (assignment.value->type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(*assignment.value))
{ {
if (assignment.value) visit(*assignment.value); if (assignment.value) visit(*assignment.value);
rewriteIdentifierList(assignment.variableNames); rewriteIdentifierList(assignment.variableNames);
return std::nullopt; return std::nullopt;
} }
else if ( else if (
assignment.value->type() == typeid(Identifier) || holds_alternative<Identifier>(*assignment.value) ||
assignment.value->type() == typeid(Literal) holds_alternative<Literal>(*assignment.value)
) )
{ {
yulAssert(assignment.variableNames.size() == 1, ""); yulAssert(assignment.variableNames.size() == 1, "");
@ -191,8 +194,8 @@ void WordSizeTransform::operator()(Block& _block)
else else
yulAssert(false, ""); yulAssert(false, "");
} }
else if (_s.type() == typeid(Switch)) else if (holds_alternative<Switch>(_s))
return handleSwitch(boost::get<Switch>(_s)); return handleSwitch(std::get<Switch>(_s));
else else
visit(_s); visit(_s);
return std::nullopt; return std::nullopt;
@ -331,7 +334,7 @@ std::vector<Statement> WordSizeTransform::handleSwitch(Switch& _switch)
} }
vector<YulString> splitExpressions; vector<YulString> splitExpressions;
for (auto const& expr: expandValue(*_switch.expression)) for (auto const& expr: expandValue(*_switch.expression))
splitExpressions.emplace_back(boost::get<Identifier>(*expr).name); splitExpressions.emplace_back(std::get<Identifier>(*expr).name);
ret += handleSwitchInternal( ret += handleSwitchInternal(
_switch.location, _switch.location,
@ -361,15 +364,15 @@ array<YulString, 4> WordSizeTransform::generateU64IdentifierNames(YulString cons
array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const& _e) array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const& _e)
{ {
array<unique_ptr<Expression>, 4> ret; array<unique_ptr<Expression>, 4> ret;
if (_e.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_e))
{ {
Identifier const& id = boost::get<Identifier>(_e); Identifier const& id = std::get<Identifier>(_e);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]}); ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]});
} }
else if (_e.type() == typeid(Literal)) else if (holds_alternative<Literal>(_e))
{ {
Literal const& lit = boost::get<Literal>(_e); Literal const& lit = std::get<Literal>(_e);
u256 val = valueOfLiteral(lit); u256 val = valueOfLiteral(lit);
for (int i = 3; i >= 0; i--) for (int i = 3; i >= 0; i--)
{ {

View File

@ -133,12 +133,12 @@ Statement ASTCopier::operator ()(Block const& _block)
Expression ASTCopier::translate(Expression const& _expression) Expression ASTCopier::translate(Expression const& _expression)
{ {
return _expression.apply_visitor(static_cast<ExpressionCopier&>(*this)); return std::visit(static_cast<ExpressionCopier&>(*this), _expression);
} }
Statement ASTCopier::translate(Statement const& _statement) Statement ASTCopier::translate(Statement const& _statement)
{ {
return _statement.apply_visitor(static_cast<StatementCopier&>(*this)); return std::visit(static_cast<StatementCopier&>(*this), _statement);
} }
Block ASTCopier::translate(Block const& _block) Block ASTCopier::translate(Block const& _block)

View File

@ -24,8 +24,6 @@
#include <libyul/YulString.h> #include <libyul/YulString.h>
#include <boost/variant.hpp>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <set> #include <set>
@ -34,7 +32,7 @@
namespace yul namespace yul
{ {
class ExpressionCopier: public boost::static_visitor<Expression> class ExpressionCopier
{ {
public: public:
virtual ~ExpressionCopier() = default; virtual ~ExpressionCopier() = default;
@ -43,7 +41,7 @@ public:
virtual Expression operator()(FunctionCall const&) = 0; virtual Expression operator()(FunctionCall const&) = 0;
}; };
class StatementCopier: public boost::static_visitor<Statement> class StatementCopier
{ {
public: public:
virtual ~StatementCopier() = default; virtual ~StatementCopier() = default;

View File

@ -89,12 +89,12 @@ void ASTWalker::operator()(Block const& _block)
void ASTWalker::visit(Statement const& _st) void ASTWalker::visit(Statement const& _st)
{ {
boost::apply_visitor(*this, _st); std::visit(*this, _st);
} }
void ASTWalker::visit(Expression const& _e) void ASTWalker::visit(Expression const& _e)
{ {
boost::apply_visitor(*this, _e); std::visit(*this, _e);
} }
void ASTModifier::operator()(FunctionCall& _funCall) void ASTModifier::operator()(FunctionCall& _funCall)
@ -170,10 +170,10 @@ void ASTModifier::operator()(Block& _block)
void ASTModifier::visit(Statement& _st) void ASTModifier::visit(Statement& _st)
{ {
boost::apply_visitor(*this, _st); std::visit(*this, _st);
} }
void ASTModifier::visit(Expression& _e) void ASTModifier::visit(Expression& _e)
{ {
boost::apply_visitor(*this, _e); std::visit(*this, _e);
} }

View File

@ -25,8 +25,6 @@
#include <libyul/Exceptions.h> #include <libyul/Exceptions.h>
#include <libyul/YulString.h> #include <libyul/YulString.h>
#include <boost/variant.hpp>
#include <map> #include <map>
#include <optional> #include <optional>
#include <set> #include <set>
@ -38,7 +36,7 @@ namespace yul
/** /**
* Generic AST walker. * Generic AST walker.
*/ */
class ASTWalker: public boost::static_visitor<> class ASTWalker
{ {
public: public:
virtual ~ASTWalker() = default; virtual ~ASTWalker() = default;
@ -72,7 +70,7 @@ protected:
/** /**
* Generic AST modifier (i.e. non-const version of ASTWalker). * Generic AST modifier (i.e. non-const version of ASTWalker).
*/ */
class ASTModifier: public boost::static_visitor<> class ASTModifier
{ {
public: public:
virtual ~ASTModifier() = default; virtual ~ASTModifier() = default;

View File

@ -32,8 +32,8 @@ void BlockFlattener::operator()(Block& _block)
_block.statements, _block.statements,
[](Statement& _s) -> std::optional<vector<Statement>> [](Statement& _s) -> std::optional<vector<Statement>>
{ {
if (_s.type() == typeid(Block)) if (holds_alternative<Block>(_s))
return std::move(boost::get<Block>(_s).statements); return std::move(std::get<Block>(_s).statements);
else else
return {}; return {};
} }

View File

@ -56,8 +56,8 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
bool descend = true; bool descend = true;
// If this is a function call to a function that requires literal arguments, // If this is a function call to a function that requires literal arguments,
// do not try to simplify there. // do not try to simplify there.
if (_e.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_e))
if (BuiltinFunction const* builtin = m_dialect.builtin(boost::get<FunctionCall>(_e).functionName.name)) if (BuiltinFunction const* builtin = m_dialect.builtin(std::get<FunctionCall>(_e).functionName.name))
if (builtin->literalArguments) if (builtin->literalArguments)
// We should not modify function arguments that have to be literals // We should not modify function arguments that have to be literals
// Note that replacing the function call entirely is fine, // Note that replacing the function call entirely is fine,
@ -72,16 +72,16 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
if (descend) if (descend)
DataFlowAnalyzer::visit(_e); DataFlowAnalyzer::visit(_e);
if (_e.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_e))
{ {
Identifier& identifier = boost::get<Identifier>(_e); Identifier& identifier = std::get<Identifier>(_e);
YulString name = identifier.name; YulString name = identifier.name;
if (m_value.count(name)) if (m_value.count(name))
{ {
assertThrow(m_value.at(name), OptimizerException, ""); assertThrow(m_value.at(name), OptimizerException, "");
if (m_value.at(name)->type() == typeid(Identifier)) if (holds_alternative<Identifier>(*m_value.at(name)))
{ {
YulString value = boost::get<Identifier>(*m_value.at(name)).name; YulString value = std::get<Identifier>(*m_value.at(name)).name;
assertThrow(inScope(value), OptimizerException, ""); assertThrow(inScope(value), OptimizerException, "");
_e = Identifier{locationOf(_e), value}; _e = Identifier{locationOf(_e), value};
} }

View File

@ -29,12 +29,12 @@ using namespace yul;
void ConditionalSimplifier::operator()(Switch& _switch) void ConditionalSimplifier::operator()(Switch& _switch)
{ {
visit(*_switch.expression); visit(*_switch.expression);
if (_switch.expression->type() != typeid(Identifier)) if (!holds_alternative<Identifier>(*_switch.expression))
{ {
ASTModifier::operator()(_switch); ASTModifier::operator()(_switch);
return; return;
} }
YulString expr = boost::get<Identifier>(*_switch.expression).name; YulString expr = std::get<Identifier>(*_switch.expression).name;
for (auto& _case: _switch.cases) for (auto& _case: _switch.cases)
{ {
if (_case.value) if (_case.value)
@ -59,17 +59,17 @@ void ConditionalSimplifier::operator()(Block& _block)
[&](Statement& _s) -> std::optional<vector<Statement>> [&](Statement& _s) -> std::optional<vector<Statement>>
{ {
visit(_s); visit(_s);
if (_s.type() == typeid(If)) if (holds_alternative<If>(_s))
{ {
If& _if = boost::get<If>(_s); If& _if = std::get<If>(_s);
if ( if (
_if.condition->type() == typeid(Identifier) && holds_alternative<Identifier>(*_if.condition) &&
!_if.body.statements.empty() && !_if.body.statements.empty() &&
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) != TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
TerminationFinder::ControlFlow::FlowOut TerminationFinder::ControlFlow::FlowOut
) )
{ {
YulString condition = boost::get<Identifier>(*_if.condition).name; YulString condition = std::get<Identifier>(*_if.condition).name;
langutil::SourceLocation location = _if.location; langutil::SourceLocation location = _if.location;
return make_vector<Statement>( return make_vector<Statement>(
std::move(_s), std::move(_s),

View File

@ -29,12 +29,12 @@ using namespace yul;
void ConditionalUnsimplifier::operator()(Switch& _switch) void ConditionalUnsimplifier::operator()(Switch& _switch)
{ {
visit(*_switch.expression); visit(*_switch.expression);
if (_switch.expression->type() != typeid(Identifier)) if (!holds_alternative<Identifier>(*_switch.expression))
{ {
ASTModifier::operator()(_switch); ASTModifier::operator()(_switch);
return; return;
} }
YulString expr = boost::get<Identifier>(*_switch.expression).name; YulString expr = std::get<Identifier>(*_switch.expression).name;
for (auto& _case: _switch.cases) for (auto& _case: _switch.cases)
{ {
if (_case.value) if (_case.value)
@ -42,15 +42,15 @@ void ConditionalUnsimplifier::operator()(Switch& _switch)
(*this)(*_case.value); (*this)(*_case.value);
if ( if (
!_case.body.statements.empty() && !_case.body.statements.empty() &&
_case.body.statements.front().type() == typeid(Assignment) holds_alternative<Assignment>(_case.body.statements.front())
) )
{ {
Assignment const& assignment = boost::get<Assignment>(_case.body.statements.front()); Assignment const& assignment = std::get<Assignment>(_case.body.statements.front());
if ( if (
assignment.variableNames.size() == 1 && assignment.variableNames.size() == 1 &&
assignment.variableNames.front().name == expr && assignment.variableNames.front().name == expr &&
assignment.value->type() == typeid(Literal) && holds_alternative<Literal>(*assignment.value) &&
valueOfLiteral(boost::get<Literal>(*assignment.value)) == valueOfLiteral(*_case.value) valueOfLiteral(std::get<Literal>(*assignment.value)) == valueOfLiteral(*_case.value)
) )
_case.body.statements.erase(_case.body.statements.begin()); _case.body.statements.erase(_case.body.statements.begin());
} }
@ -66,27 +66,27 @@ void ConditionalUnsimplifier::operator()(Block& _block)
_block.statements, _block.statements,
[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>> [&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
{ {
if (_stmt1.type() == typeid(If)) if (holds_alternative<If>(_stmt1))
{ {
If& _if = boost::get<If>(_stmt1); If& _if = std::get<If>(_stmt1);
if ( if (
_if.condition->type() == typeid(Identifier) && holds_alternative<Identifier>(*_if.condition) &&
!_if.body.statements.empty() !_if.body.statements.empty()
) )
{ {
YulString condition = boost::get<Identifier>(*_if.condition).name; YulString condition = std::get<Identifier>(*_if.condition).name;
if ( if (
_stmt2.type() == typeid(Assignment) && holds_alternative<Assignment>(_stmt2) &&
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) != TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
TerminationFinder::ControlFlow::FlowOut TerminationFinder::ControlFlow::FlowOut
) )
{ {
Assignment const& assignment = boost::get<Assignment>(_stmt2); Assignment const& assignment = std::get<Assignment>(_stmt2);
if ( if (
assignment.variableNames.size() == 1 && assignment.variableNames.size() == 1 &&
assignment.variableNames.front().name == condition && assignment.variableNames.front().name == condition &&
assignment.value->type() == typeid(Literal) && holds_alternative<Literal>(*assignment.value) &&
valueOfLiteral(boost::get<Literal>(*assignment.value)) == 0 valueOfLiteral(std::get<Literal>(*assignment.value)) == 0
) )
return {make_vector<Statement>(std::move(_stmt1))}; return {make_vector<Statement>(std::move(_stmt1))};
} }

View File

@ -139,15 +139,15 @@ void ControlFlowSimplifier::operator()(Block& _block)
void ControlFlowSimplifier::operator()(FunctionDefinition& _funDef) void ControlFlowSimplifier::operator()(FunctionDefinition& _funDef)
{ {
ASTModifier::operator()(_funDef); ASTModifier::operator()(_funDef);
if (!_funDef.body.statements.empty() && _funDef.body.statements.back().type() == typeid(Leave)) if (!_funDef.body.statements.empty() && holds_alternative<Leave>(_funDef.body.statements.back()))
_funDef.body.statements.pop_back(); _funDef.body.statements.pop_back();
} }
void ControlFlowSimplifier::visit(Statement& _st) void ControlFlowSimplifier::visit(Statement& _st)
{ {
if (_st.type() == typeid(ForLoop)) if (holds_alternative<ForLoop>(_st))
{ {
ForLoop& forLoop = boost::get<ForLoop>(_st); ForLoop& forLoop = std::get<ForLoop>(_st);
yulAssert(forLoop.pre.statements.empty(), ""); yulAssert(forLoop.pre.statements.empty(), "");
size_t outerBreak = m_numBreakStatements; size_t outerBreak = m_numBreakStatements;
@ -221,7 +221,7 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
_statements, _statements,
[&](Statement& _stmt) -> OptionalStatements [&](Statement& _stmt) -> OptionalStatements
{ {
OptionalStatements result = boost::apply_visitor(visitor, _stmt); OptionalStatements result = std::visit(visitor, _stmt);
if (result) if (result)
simplify(*result); simplify(*result);
else else

View File

@ -32,6 +32,7 @@
#include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm_ext/erase.hpp> #include <boost/range/algorithm_ext/erase.hpp>
#include <variant>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -368,19 +369,19 @@ std::optional<pair<YulString, YulString>> DataFlowAnalyzer::isSimpleStore(
_store == dev::eth::Instruction::SSTORE, _store == dev::eth::Instruction::SSTORE,
"" ""
); );
if (_statement.expression.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_statement.expression))
{ {
FunctionCall const& funCall = boost::get<FunctionCall>(_statement.expression); FunctionCall const& funCall = std::get<FunctionCall>(_statement.expression);
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect)) if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
if (auto const* builtin = dialect->builtin(funCall.functionName.name)) if (auto const* builtin = dialect->builtin(funCall.functionName.name))
if (builtin->instruction == _store) if (builtin->instruction == _store)
if ( if (
funCall.arguments.at(0).type() == typeid(Identifier) && holds_alternative<Identifier>(funCall.arguments.at(0)) &&
funCall.arguments.at(1).type() == typeid(Identifier) holds_alternative<Identifier>(funCall.arguments.at(1))
) )
{ {
YulString key = boost::get<Identifier>(funCall.arguments.at(0)).name; YulString key = std::get<Identifier>(funCall.arguments.at(0)).name;
YulString value = boost::get<Identifier>(funCall.arguments.at(1)).name; YulString value = std::get<Identifier>(funCall.arguments.at(1)).name;
return make_pair(key, value); return make_pair(key, value);
} }
} }

View File

@ -56,7 +56,7 @@ void DeadCodeEliminator::operator()(Block& _block)
remove_if( remove_if(
_block.statements.begin() + index + 1, _block.statements.begin() + index + 1,
_block.statements.end(), _block.statements.end(),
[] (Statement const& _s) { return _s.type() != typeid(yul::FunctionDefinition); } [] (Statement const& _s) { return !holds_alternative<yul::FunctionDefinition>(_s); }
), ),
_block.statements.end() _block.statements.end()
); );

View File

@ -25,8 +25,6 @@
#include <libyul/optimiser/ASTCopier.h> #include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/NameDispenser.h> #include <libyul/optimiser/NameDispenser.h>
#include <boost/variant.hpp>
#include <optional> #include <optional>
#include <set> #include <set>

View File

@ -49,9 +49,9 @@ void ExpressionInliner::operator()(FunctionDefinition& _fun)
void ExpressionInliner::visit(Expression& _expression) void ExpressionInliner::visit(Expression& _expression)
{ {
ASTModifier::visit(_expression); ASTModifier::visit(_expression);
if (_expression.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_expression))
{ {
FunctionCall& funCall = boost::get<FunctionCall>(_expression); FunctionCall& funCall = std::get<FunctionCall>(_expression);
if (!m_inlinableFunctions.count(funCall.functionName.name)) if (!m_inlinableFunctions.count(funCall.functionName.name))
return; return;
FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name); FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
@ -74,6 +74,6 @@ void ExpressionInliner::visit(Expression& _expression)
substitutions[paraName] = &arg; substitutions[paraName] = &arg;
} }
_expression = Substitution(substitutions).translate(*boost::get<Assignment>(fun.body.statements.front()).value); _expression = Substitution(substitutions).translate(*std::get<Assignment>(fun.body.statements.front()).value);
} }
} }

View File

@ -22,9 +22,7 @@
#include <libyul/optimiser/ASTWalker.h> #include <libyul/optimiser/ASTWalker.h>
#include <libyul/AsmDataForward.h> #include <libyul/AsmDataForward.h>
#include <boost/variant.hpp>
#include <optional> #include <optional>
#include <set> #include <set>
namespace yul namespace yul

View File

@ -61,12 +61,12 @@ void ExpressionJoiner::operator()(Block& _block)
void ExpressionJoiner::visit(Expression& _e) void ExpressionJoiner::visit(Expression& _e)
{ {
if (_e.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_e))
{ {
Identifier const& identifier = boost::get<Identifier>(_e); Identifier const& identifier = std::get<Identifier>(_e);
if (isLatestStatementVarDeclJoinable(identifier)) if (isLatestStatementVarDeclJoinable(identifier))
{ {
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(*latestStatement()); VariableDeclaration& varDecl = std::get<VariableDeclaration>(*latestStatement());
_e = std::move(*varDecl.value); _e = std::move(*varDecl.value);
// Delete the variable declaration (also get the moved-from structure back into a sane state) // Delete the variable declaration (also get the moved-from structure back into a sane state)
@ -96,7 +96,7 @@ void ExpressionJoiner::handleArguments(vector<Expression>& _arguments)
for (Expression const& arg: _arguments | boost::adaptors::reversed) for (Expression const& arg: _arguments | boost::adaptors::reversed)
{ {
--i; --i;
if (arg.type() != typeid(Identifier) && arg.type() != typeid(Literal)) if (!holds_alternative<Identifier>(arg) && !holds_alternative<Literal>(arg))
break; break;
} }
// i points to the last element that is neither an identifier nor a literal, // i points to the last element that is neither an identifier nor a literal,
@ -133,9 +133,9 @@ Statement* ExpressionJoiner::latestStatement()
bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier) bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier)
{ {
Statement const* statement = latestStatement(); Statement const* statement = latestStatement();
if (!statement || statement->type() != typeid(VariableDeclaration)) if (!statement || !holds_alternative<VariableDeclaration>(*statement))
return false; return false;
VariableDeclaration const& varDecl = boost::get<VariableDeclaration>(*statement); VariableDeclaration const& varDecl = std::get<VariableDeclaration>(*statement);
if (varDecl.variables.size() != 1 || !varDecl.value) if (varDecl.variables.size() != 1 || !varDecl.value)
return false; return false;
assertThrow(varDecl.variables.size() == 1, OptimizerException, ""); assertThrow(varDecl.variables.size() == 1, OptimizerException, "");

View File

@ -95,7 +95,7 @@ void ExpressionSplitter::operator()(Block& _block)
void ExpressionSplitter::outlineExpression(Expression& _expr) void ExpressionSplitter::outlineExpression(Expression& _expr)
{ {
if (_expr.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_expr))
return; return;
visit(_expr); visit(_expr);

View File

@ -33,8 +33,8 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
{ {
if ( if (
m_dialect.booleanNegationFunction() && m_dialect.booleanNegationFunction() &&
_forLoop.condition->type() != typeid(Literal) && !holds_alternative<Literal>(*_forLoop.condition) &&
_forLoop.condition->type() != typeid(Identifier) !holds_alternative<Identifier>(*_forLoop.condition)
) )
{ {
langutil::SourceLocation const loc = locationOf(*_forLoop.condition); langutil::SourceLocation const loc = locationOf(*_forLoop.condition);

View File

@ -36,17 +36,17 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
if ( if (
!m_dialect.booleanNegationFunction() || !m_dialect.booleanNegationFunction() ||
_forLoop.condition->type() != typeid(Literal) || !holds_alternative<Literal>(*_forLoop.condition) ||
valueOfLiteral(boost::get<Literal>(*_forLoop.condition)) == u256(0) || valueOfLiteral(std::get<Literal>(*_forLoop.condition)) == u256(0) ||
_forLoop.body.statements.empty() || _forLoop.body.statements.empty() ||
_forLoop.body.statements.front().type() != typeid(If) !holds_alternative<If>(_forLoop.body.statements.front())
) )
return; return;
If& firstStatement = boost::get<If>(_forLoop.body.statements.front()); If& firstStatement = std::get<If>(_forLoop.body.statements.front());
if ( if (
firstStatement.body.statements.empty() || firstStatement.body.statements.empty() ||
firstStatement.body.statements.front().type() != typeid(Break) !holds_alternative<Break>(firstStatement.body.statements.front())
) )
return; return;
if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable()) if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable())
@ -56,10 +56,10 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
langutil::SourceLocation location = locationOf(*firstStatement.condition); langutil::SourceLocation location = locationOf(*firstStatement.condition);
if ( if (
firstStatement.condition->type() == typeid(FunctionCall) && holds_alternative<FunctionCall>(*firstStatement.condition) &&
boost::get<FunctionCall>(*firstStatement.condition).functionName.name == iszero std::get<FunctionCall>(*firstStatement.condition).functionName.name == iszero
) )
_forLoop.condition = make_unique<Expression>(std::move(boost::get<FunctionCall>(*firstStatement.condition).arguments.front())); _forLoop.condition = make_unique<Expression>(std::move(std::get<FunctionCall>(*firstStatement.condition).arguments.front()));
else else
_forLoop.condition = make_unique<Expression>(FunctionCall{ _forLoop.condition = make_unique<Expression>(FunctionCall{
location, location,

View File

@ -29,9 +29,9 @@ void ForLoopInitRewriter::operator()(Block& _block)
_block.statements, _block.statements,
[&](Statement& _stmt) -> std::optional<vector<Statement>> [&](Statement& _stmt) -> std::optional<vector<Statement>>
{ {
if (_stmt.type() == typeid(ForLoop)) if (holds_alternative<ForLoop>(_stmt))
{ {
auto& forLoop = boost::get<ForLoop>(_stmt); auto& forLoop = std::get<ForLoop>(_stmt);
(*this)(forLoop.pre); (*this)(forLoop.pre);
(*this)(forLoop.body); (*this)(forLoop.body);
(*this)(forLoop.post); (*this)(forLoop.post);

View File

@ -51,7 +51,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
SSAValueTracker tracker; SSAValueTracker tracker;
tracker(m_ast); tracker(m_ast);
for (auto const& ssaValue: tracker.values()) for (auto const& ssaValue: tracker.values())
if (ssaValue.second && ssaValue.second->type() == typeid(Literal)) if (ssaValue.second && holds_alternative<Literal>(*ssaValue.second))
m_constants.emplace(ssaValue.first); m_constants.emplace(ssaValue.first);
// Store size of global statements. // Store size of global statements.
@ -59,9 +59,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast); map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast);
for (auto& statement: m_ast.statements) for (auto& statement: m_ast.statements)
{ {
if (statement.type() != typeid(FunctionDefinition)) if (!holds_alternative<FunctionDefinition>(statement))
continue; continue;
FunctionDefinition& fun = boost::get<FunctionDefinition>(statement); FunctionDefinition& fun = std::get<FunctionDefinition>(statement);
m_functions[fun.name] = &fun; m_functions[fun.name] = &fun;
if (LeaveFinder::containsLeave(fun)) if (LeaveFinder::containsLeave(fun))
m_noInlineFunctions.insert(fun.name); m_noInlineFunctions.insert(fun.name);
@ -75,8 +75,8 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
void FullInliner::run() void FullInliner::run()
{ {
for (auto& statement: m_ast.statements) for (auto& statement: m_ast.statements)
if (statement.type() == typeid(Block)) if (holds_alternative<Block>(statement))
handleBlock({}, boost::get<Block>(statement)); handleBlock({}, std::get<Block>(statement));
// TODO it might be good to determine a visiting order: // TODO it might be good to determine a visiting order:
// first handle functions that are called from many places. // first handle functions that are called from many places.
@ -115,9 +115,9 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
// Constant arguments might provide a means for further optimization, so they cause a bonus. // Constant arguments might provide a means for further optimization, so they cause a bonus.
bool constantArg = false; bool constantArg = false;
for (auto const& argument: _funCall.arguments) for (auto const& argument: _funCall.arguments)
if (argument.type() == typeid(Literal) || ( if (holds_alternative<Literal>(argument) || (
argument.type() == typeid(Identifier) && holds_alternative<Identifier>(argument) &&
m_constants.count(boost::get<Identifier>(argument).name) m_constants.count(std::get<Identifier>(argument).name)
)) ))
{ {
constantArg = true; constantArg = true;
@ -160,7 +160,7 @@ void InlineModifier::operator()(Block& _block)
std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _statement) std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _statement)
{ {
// Only inline for expression statements, assignments and variable declarations. // Only inline for expression statements, assignments and variable declarations.
Expression* e = boost::apply_visitor(GenericFallbackReturnsVisitor<Expression*, ExpressionStatement, Assignment, VariableDeclaration>( Expression* e = std::visit(GenericFallbackReturnsVisitor<Expression*, ExpressionStatement, Assignment, VariableDeclaration>(
[](ExpressionStatement& _s) { return &_s.expression; }, [](ExpressionStatement& _s) { return &_s.expression; },
[](Assignment& _s) { return _s.value.get(); }, [](Assignment& _s) { return _s.value.get(); },
[](VariableDeclaration& _s) { return _s.value.get(); } [](VariableDeclaration& _s) { return _s.value.get(); }
@ -168,7 +168,7 @@ std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _
if (e) if (e)
{ {
// Only inline direct function calls. // Only inline direct function calls.
FunctionCall* funCall = boost::apply_visitor(GenericFallbackReturnsVisitor<FunctionCall*, FunctionCall&>( FunctionCall* funCall = std::visit(GenericFallbackReturnsVisitor<FunctionCall*, FunctionCall&>(
[](FunctionCall& _e) { return &_e; } [](FunctionCall& _e) { return &_e; }
), *e); ), *e);
if (funCall && m_driver.shallInline(*funCall, m_currentFunction)) if (funCall && m_driver.shallInline(*funCall, m_currentFunction))
@ -206,9 +206,9 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
newVariable(var, nullptr); newVariable(var, nullptr);
Statement newBody = BodyCopier(m_nameDispenser, variableReplacements)(function->body); Statement newBody = BodyCopier(m_nameDispenser, variableReplacements)(function->body);
newStatements += std::move(boost::get<Block>(newBody).statements); newStatements += std::move(std::get<Block>(newBody).statements);
boost::apply_visitor(GenericFallbackVisitor<Assignment, VariableDeclaration>{ std::visit(GenericFallbackVisitor<Assignment, VariableDeclaration>{
[&](Assignment& _assignment) [&](Assignment& _assignment)
{ {
for (size_t i = 0; i < _assignment.variableNames.size(); ++i) for (size_t i = 0; i < _assignment.variableNames.size(); ++i)

View File

@ -29,8 +29,6 @@
#include <liblangutil/SourceLocation.h> #include <liblangutil/SourceLocation.h>
#include <boost/variant.hpp>
#include <optional> #include <optional>
#include <set> #include <set>

View File

@ -40,10 +40,10 @@ void FunctionGrouper::operator()(Block& _block)
for (auto&& statement: _block.statements) for (auto&& statement: _block.statements)
{ {
if (statement.type() == typeid(FunctionDefinition)) if (holds_alternative<FunctionDefinition>(statement))
reordered.emplace_back(std::move(statement)); reordered.emplace_back(std::move(statement));
else else
boost::get<Block>(reordered.front()).statements.emplace_back(std::move(statement)); std::get<Block>(reordered.front()).statements.emplace_back(std::move(statement));
} }
_block.statements = std::move(reordered); _block.statements = std::move(reordered);
} }
@ -52,10 +52,10 @@ bool FunctionGrouper::alreadyGrouped(Block const& _block)
{ {
if (_block.statements.empty()) if (_block.statements.empty())
return false; return false;
if (_block.statements.front().type() != typeid(Block)) if (!holds_alternative<Block>(_block.statements.front()))
return false; return false;
for (size_t i = 1; i < _block.statements.size(); ++i) for (size_t i = 1; i < _block.statements.size(); ++i)
if (_block.statements.at(i).type() != typeid(FunctionDefinition)) if (!holds_alternative<FunctionDefinition>(_block.statements.at(i)))
return false; return false;
return true; return true;
} }

View File

@ -36,8 +36,8 @@ void FunctionHoister::operator()(Block& _block)
m_isTopLevel = false; m_isTopLevel = false;
for (auto&& statement: _block.statements) for (auto&& statement: _block.statements)
{ {
boost::apply_visitor(*this, statement); std::visit(*this, statement);
if (statement.type() == typeid(FunctionDefinition)) if (holds_alternative<FunctionDefinition>(statement))
{ {
m_functions.emplace_back(std::move(statement)); m_functions.emplace_back(std::move(statement));
statement = Block{_block.location, {}}; statement = Block{_block.location, {}};

View File

@ -45,9 +45,9 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
{ {
YulString retVariable = _function.returnVariables.front().name; YulString retVariable = _function.returnVariables.front().name;
Statement const& bodyStatement = _function.body.statements.front(); Statement const& bodyStatement = _function.body.statements.front();
if (bodyStatement.type() == typeid(Assignment)) if (holds_alternative<Assignment>(bodyStatement))
{ {
Assignment const& assignment = boost::get<Assignment>(bodyStatement); Assignment const& assignment = std::get<Assignment>(bodyStatement);
if (assignment.variableNames.size() == 1 && assignment.variableNames.front().name == retVariable) if (assignment.variableNames.size() == 1 && assignment.variableNames.front().name == retVariable)
{ {
// TODO: use code size metric here // TODO: use code size metric here
@ -57,7 +57,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
// function body. // function body.
assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, ""); assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
m_disallowedIdentifiers = set<YulString>{retVariable, _function.name}; m_disallowedIdentifiers = set<YulString>{retVariable, _function.name};
boost::apply_visitor(*this, *assignment.value); std::visit(*this, *assignment.value);
if (!m_foundDisallowedIdentifier) if (!m_foundDisallowedIdentifier)
m_inlinableFunctions[_function.name] = &_function; m_inlinableFunctions[_function.name] = &_function;
m_disallowedIdentifiers.clear(); m_disallowedIdentifiers.clear();

View File

@ -27,6 +27,9 @@
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <variant>
using namespace std;
using namespace yul; using namespace yul;
using namespace dev; using namespace dev;
@ -37,12 +40,12 @@ bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
// If that fails, try `eq(_a, _b)`. // If that fails, try `eq(_a, _b)`.
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})}); Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
if (expr1.type() == typeid(Literal)) if (holds_alternative<Literal>(expr1))
return valueOfLiteral(boost::get<Literal>(expr1)) != 0; return valueOfLiteral(std::get<Literal>(expr1)) != 0;
Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})}); Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
if (expr2.type() == typeid(Literal)) if (holds_alternative<Literal>(expr2))
return valueOfLiteral(boost::get<Literal>(expr2)) == 0; return valueOfLiteral(std::get<Literal>(expr2)) == 0;
return false; return false;
} }
@ -53,9 +56,9 @@ bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b)
// current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32. // current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32.
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})}); Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
if (expr1.type() == typeid(Literal)) if (holds_alternative<Literal>(expr1))
{ {
u256 val = valueOfLiteral(boost::get<Literal>(expr1)); u256 val = valueOfLiteral(std::get<Literal>(expr1));
return val >= 32 && val <= u256(0) - 32; return val >= 32 && val <= u256(0) - 32;
} }
@ -74,8 +77,8 @@ Expression KnowledgeBase::simplify(Expression _expression)
else else
--m_recursionCounter; --m_recursionCounter;
if (_expression.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_expression))
for (Expression& arg: boost::get<FunctionCall>(_expression).arguments) for (Expression& arg: std::get<FunctionCall>(_expression).arguments)
arg = simplify(arg); arg = simplify(arg);
if (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_variableValues)) if (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_variableValues))

View File

@ -48,9 +48,9 @@ void LoadResolver::visit(Expression& _e)
if (!dynamic_cast<EVMDialect const*>(&m_dialect)) if (!dynamic_cast<EVMDialect const*>(&m_dialect))
return; return;
if (_e.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_e))
{ {
FunctionCall const& funCall = boost::get<FunctionCall>(_e); FunctionCall const& funCall = std::get<FunctionCall>(_e);
if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name)) if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name))
if (builtin->instruction) if (builtin->instruction)
tryResolve(_e, *builtin->instruction, funCall.arguments); tryResolve(_e, *builtin->instruction, funCall.arguments);
@ -63,10 +63,10 @@ void LoadResolver::tryResolve(
vector<Expression> const& _arguments vector<Expression> const& _arguments
) )
{ {
if (_arguments.empty() || _arguments.at(0).type() != typeid(Identifier)) if (_arguments.empty() || !holds_alternative<Identifier>(_arguments.at(0)))
return; return;
YulString key = boost::get<Identifier>(_arguments.at(0)).name; YulString key = std::get<Identifier>(_arguments.at(0)).name;
if ( if (
_instruction == dev::eth::Instruction::SLOAD && _instruction == dev::eth::Instruction::SLOAD &&
m_storage.values.count(key) m_storage.values.count(key)

View File

@ -35,13 +35,13 @@ using namespace yul;
void MainFunction::operator()(Block& _block) void MainFunction::operator()(Block& _block)
{ {
assertThrow(_block.statements.size() >= 1, OptimizerException, ""); assertThrow(_block.statements.size() >= 1, OptimizerException, "");
assertThrow(_block.statements[0].type() == typeid(Block), OptimizerException, ""); assertThrow(holds_alternative<Block>(_block.statements[0]), OptimizerException, "");
for (size_t i = 1; i < _block.statements.size(); ++i) for (size_t i = 1; i < _block.statements.size(); ++i)
assertThrow(_block.statements.at(i).type() == typeid(FunctionDefinition), OptimizerException, ""); assertThrow(holds_alternative<FunctionDefinition>(_block.statements.at(i)), OptimizerException, "");
/// @todo this should handle scopes properly and instead of an assertion it should rename the conflicting function /// @todo this should handle scopes properly and instead of an assertion it should rename the conflicting function
assertThrow(NameCollector(_block).names().count("main"_yulstring) == 0, OptimizerException, ""); assertThrow(NameCollector(_block).names().count("main"_yulstring) == 0, OptimizerException, "");
Block& block = boost::get<Block>(_block.statements[0]); Block& block = std::get<Block>(_block.statements[0]);
FunctionDefinition main{ FunctionDefinition main{
block.location, block.location,
"main"_yulstring, "main"_yulstring,

View File

@ -65,24 +65,24 @@ size_t CodeSize::codeSizeIncludingFunctions(Block const& _block)
void CodeSize::visit(Statement const& _statement) void CodeSize::visit(Statement const& _statement)
{ {
if (_statement.type() == typeid(FunctionDefinition) && m_ignoreFunctions) if (holds_alternative<FunctionDefinition>(_statement) && m_ignoreFunctions)
return; return;
else if ( else if (
_statement.type() == typeid(If) || holds_alternative<If>(_statement) ||
_statement.type() == typeid(Break) || holds_alternative<Break>(_statement) ||
_statement.type() == typeid(Continue) || holds_alternative<Continue>(_statement) ||
_statement.type() == typeid(Leave) holds_alternative<Leave>(_statement)
) )
m_size += 2; m_size += 2;
else if (_statement.type() == typeid(ForLoop)) else if (holds_alternative<ForLoop>(_statement))
m_size += 3; m_size += 3;
else if (_statement.type() == typeid(Switch)) else if (holds_alternative<Switch>(_statement))
m_size += 1 + 2 * boost::get<Switch>(_statement).cases.size(); m_size += 1 + 2 * std::get<Switch>(_statement).cases.size();
else if (!( else if (!(
_statement.type() == typeid(Block) || holds_alternative<Block>(_statement) ||
_statement.type() == typeid(ExpressionStatement) || holds_alternative<ExpressionStatement>(_statement) ||
_statement.type() == typeid(Assignment) || holds_alternative<Assignment>(_statement) ||
_statement.type() == typeid(VariableDeclaration) holds_alternative<VariableDeclaration>(_statement)
)) ))
++m_size; ++m_size;
@ -91,7 +91,7 @@ void CodeSize::visit(Statement const& _statement)
void CodeSize::visit(Expression const& _expression) void CodeSize::visit(Expression const& _expression)
{ {
if (_expression.type() != typeid(Identifier)) if (!holds_alternative<Identifier>(_expression))
++m_size; ++m_size;
ASTWalker::visit(_expression); ASTWalker::visit(_expression);
} }

View File

@ -64,8 +64,8 @@ void NameDisplacer::operator()(Block& _block)
// First replace all the names of function definitions // First replace all the names of function definitions
// because of scoping. // because of scoping.
for (auto& st: _block.statements) for (auto& st: _block.statements)
if (st.type() == typeid(FunctionDefinition)) if (holds_alternative<FunctionDefinition>(st))
checkAndReplaceNew(boost::get<FunctionDefinition>(st).name); checkAndReplaceNew(std::get<FunctionDefinition>(st).name);
ASTModifier::operator()(_block); ASTModifier::operator()(_block);
} }

View File

@ -33,7 +33,7 @@ using namespace yul;
void yul::removeEmptyBlocks(Block& _block) void yul::removeEmptyBlocks(Block& _block)
{ {
auto isEmptyBlock = [](Statement const& _st) -> bool { auto isEmptyBlock = [](Statement const& _st) -> bool {
return _st.type() == typeid(Block) && boost::get<Block>(_st).statements.empty(); return holds_alternative<Block>(_st) && std::get<Block>(_st).statements.empty();
}; };
boost::range::remove_erase_if(_block.statements, isEmptyBlock); boost::range::remove_erase_if(_block.statements, isEmptyBlock);
} }

View File

@ -308,7 +308,7 @@ void RedundantAssignEliminator::finalize(
void AssignmentRemover::operator()(Block& _block) void AssignmentRemover::operator()(Block& _block)
{ {
boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool { boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool {
return _statement.type() == typeid(Assignment) && m_toRemove.count(&boost::get<Assignment>(_statement)); return holds_alternative<Assignment>(_statement) && m_toRemove.count(&std::get<Assignment>(_statement));
}); });
ASTModifier::operator()(_block); ASTModifier::operator()(_block);

View File

@ -68,9 +68,9 @@ Rematerialiser::Rematerialiser(
void Rematerialiser::visit(Expression& _e) void Rematerialiser::visit(Expression& _e)
{ {
if (_e.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_e))
{ {
Identifier& identifier = boost::get<Identifier>(_e); Identifier& identifier = std::get<Identifier>(_e);
YulString name = identifier.name; YulString name = identifier.name;
if (m_value.count(name)) if (m_value.count(name))
{ {
@ -96,15 +96,15 @@ void Rematerialiser::visit(Expression& _e)
void LiteralRematerialiser::visit(Expression& _e) void LiteralRematerialiser::visit(Expression& _e)
{ {
if (_e.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_e))
{ {
Identifier& identifier = boost::get<Identifier>(_e); Identifier& identifier = std::get<Identifier>(_e);
YulString name = identifier.name; YulString name = identifier.name;
if (m_value.count(name)) if (m_value.count(name))
{ {
Expression const* value = m_value.at(name); Expression const* value = m_value.at(name);
assertThrow(value, OptimizerException, ""); assertThrow(value, OptimizerException, "");
if (value->type() == typeid(Literal)) if (holds_alternative<Literal>(*value))
_e = *value; _e = *value;
} }
} }

View File

@ -19,6 +19,8 @@
#include <libyul/AsmData.h> #include <libyul/AsmData.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <variant>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace yul; using namespace yul;
@ -37,7 +39,7 @@ void SSAReverser::operator()(Block& _block)
_block.statements, _block.statements,
[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>> [&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
{ {
auto* varDecl = boost::get<VariableDeclaration>(&_stmt1); auto* varDecl = std::get_if<VariableDeclaration>(&_stmt1);
if (!varDecl || varDecl->variables.size() != 1 || !varDecl->value) if (!varDecl || varDecl->variables.size() != 1 || !varDecl->value)
return {}; return {};
@ -48,9 +50,9 @@ void SSAReverser::operator()(Block& _block)
// with // with
// a := E // a := E
// let a_1 := a // let a_1 := a
if (auto* assignment = boost::get<Assignment>(&_stmt2)) if (auto* assignment = std::get_if<Assignment>(&_stmt2))
{ {
auto* identifier = boost::get<Identifier>(assignment->value.get()); auto* identifier = std::get_if<Identifier>(assignment->value.get());
if ( if (
assignment->variableNames.size() == 1 && assignment->variableNames.size() == 1 &&
identifier && identifier &&
@ -81,9 +83,9 @@ void SSAReverser::operator()(Block& _block)
// with // with
// let a := E // let a := E
// let a_1 := a // let a_1 := a
else if (auto* varDecl2 = boost::get<VariableDeclaration>(&_stmt2)) else if (auto* varDecl2 = std::get_if<VariableDeclaration>(&_stmt2))
{ {
auto* identifier = boost::get<Identifier>(varDecl2->value.get()); auto* identifier = std::get_if<Identifier>(varDecl2->value.get());
if ( if (
varDecl2->variables.size() == 1 && varDecl2->variables.size() == 1 &&
identifier && identifier &&

View File

@ -60,9 +60,9 @@ void IntroduceSSA::operator()(Block& _block)
_block.statements, _block.statements,
[&](Statement& _s) -> std::optional<vector<Statement>> [&](Statement& _s) -> std::optional<vector<Statement>>
{ {
if (_s.type() == typeid(VariableDeclaration)) if (holds_alternative<VariableDeclaration>(_s))
{ {
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_s); VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
if (varDecl.value) if (varDecl.value)
visit(*varDecl.value); visit(*varDecl.value);
@ -90,12 +90,12 @@ void IntroduceSSA::operator()(Block& _block)
make_unique<Expression>(Identifier{loc, newName}) make_unique<Expression>(Identifier{loc, newName})
}); });
} }
boost::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables); std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
return { std::move(statements) }; return { std::move(statements) };
} }
else if (_s.type() == typeid(Assignment)) else if (holds_alternative<Assignment>(_s))
{ {
Assignment& assignment = boost::get<Assignment>(_s); Assignment& assignment = std::get<Assignment>(_s);
visit(*assignment.value); visit(*assignment.value);
for (auto const& var: assignment.variableNames) for (auto const& var: assignment.variableNames)
assertThrow(m_variablesToReplace.count(var.name), OptimizerException, ""); assertThrow(m_variablesToReplace.count(var.name), OptimizerException, "");
@ -117,7 +117,7 @@ void IntroduceSSA::operator()(Block& _block)
make_unique<Expression>(Identifier{loc, newName}) make_unique<Expression>(Identifier{loc, newName})
}); });
} }
boost::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables); std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
return { std::move(statements) }; return { std::move(statements) };
} }
else else
@ -228,9 +228,9 @@ void IntroduceControlFlowSSA::operator()(Block& _block)
} }
m_variablesToReassign.clear(); m_variablesToReassign.clear();
if (_s.type() == typeid(VariableDeclaration)) if (holds_alternative<VariableDeclaration>(_s))
{ {
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_s); VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
for (auto const& var: varDecl.variables) for (auto const& var: varDecl.variables)
if (m_variablesToReplace.count(var.name)) if (m_variablesToReplace.count(var.name))
{ {
@ -238,9 +238,9 @@ void IntroduceControlFlowSSA::operator()(Block& _block)
m_variablesInScope.insert(var.name); m_variablesInScope.insert(var.name);
} }
} }
else if (_s.type() == typeid(Assignment)) else if (holds_alternative<Assignment>(_s))
{ {
Assignment& assignment = boost::get<Assignment>(_s); Assignment& assignment = std::get<Assignment>(_s);
for (auto const& var: assignment.variableNames) for (auto const& var: assignment.variableNames)
if (m_variablesToReplace.count(var.name)) if (m_variablesToReplace.count(var.name))
assignedVariables.insert(var.name); assignedVariables.insert(var.name);
@ -304,14 +304,14 @@ void PropagateValues::operator()(VariableDeclaration& _varDecl)
if (m_variablesToReplace.count(variable)) if (m_variablesToReplace.count(variable))
{ {
// `let a := a_1` - regular declaration of non-SSA variable // `let a := a_1` - regular declaration of non-SSA variable
yulAssert(_varDecl.value->type() == typeid(Identifier), ""); yulAssert(holds_alternative<Identifier>(*_varDecl.value), "");
m_currentVariableValues[variable] = boost::get<Identifier>(*_varDecl.value).name; m_currentVariableValues[variable] = std::get<Identifier>(*_varDecl.value).name;
m_clearAtEndOfBlock.insert(variable); m_clearAtEndOfBlock.insert(variable);
} }
else if (_varDecl.value && _varDecl.value->type() == typeid(Identifier)) else if (_varDecl.value && holds_alternative<Identifier>(*_varDecl.value))
{ {
// `let a_1 := a` - assignment to SSA variable after a branch. // `let a_1 := a` - assignment to SSA variable after a branch.
YulString value = boost::get<Identifier>(*_varDecl.value).name; YulString value = std::get<Identifier>(*_varDecl.value).name;
if (m_variablesToReplace.count(value)) if (m_variablesToReplace.count(value))
{ {
// This is safe because `a_1` is not a "variable to replace" and thus // This is safe because `a_1` is not a "variable to replace" and thus
@ -333,8 +333,8 @@ void PropagateValues::operator()(Assignment& _assignment)
if (!m_variablesToReplace.count(name)) if (!m_variablesToReplace.count(name))
return; return;
yulAssert(_assignment.value && _assignment.value->type() == typeid(Identifier), ""); yulAssert(_assignment.value && holds_alternative<Identifier>(*_assignment.value), "");
m_currentVariableValues[name] = boost::get<Identifier>(*_assignment.value).name; m_currentVariableValues[name] = std::get<Identifier>(*_assignment.value).name;
m_clearAtEndOfBlock.insert(name); m_clearAtEndOfBlock.insert(name);
} }

View File

@ -150,15 +150,15 @@ pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUncondition
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement) TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
{ {
if ( if (
_statement.type() == typeid(ExpressionStatement) && holds_alternative<ExpressionStatement>(_statement) &&
isTerminatingBuiltin(boost::get<ExpressionStatement>(_statement)) isTerminatingBuiltin(std::get<ExpressionStatement>(_statement))
) )
return ControlFlow::Terminate; return ControlFlow::Terminate;
else if (_statement.type() == typeid(Break)) else if (holds_alternative<Break>(_statement))
return ControlFlow::Break; return ControlFlow::Break;
else if (_statement.type() == typeid(Continue)) else if (holds_alternative<Continue>(_statement))
return ControlFlow::Continue; return ControlFlow::Continue;
else if (_statement.type() == typeid(Leave)) else if (holds_alternative<Leave>(_statement))
return ControlFlow::Leave; return ControlFlow::Leave;
else else
return ControlFlow::FlowOut; return ControlFlow::FlowOut;
@ -166,9 +166,9 @@ TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement cons
bool TerminationFinder::isTerminatingBuiltin(ExpressionStatement const& _exprStmnt) bool TerminationFinder::isTerminatingBuiltin(ExpressionStatement const& _exprStmnt)
{ {
if (_exprStmnt.expression.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_exprStmnt.expression))
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect)) if (auto const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
if (auto const* builtin = dialect->builtin(boost::get<FunctionCall>(_exprStmnt.expression).functionName.name)) if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_exprStmnt.expression).functionName.name))
if (builtin->instruction) if (builtin->instruction)
return eth::SemanticInformation::terminatesControlFlow(*builtin->instruction); return eth::SemanticInformation::terminatesControlFlow(*builtin->instruction);
return false; return false;

View File

@ -67,11 +67,11 @@ bool SimplificationRules::isInitialized() const
std::optional<std::pair<dev::eth::Instruction, vector<Expression> const*>> std::optional<std::pair<dev::eth::Instruction, vector<Expression> const*>>
SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr) SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr)
{ {
if (_expr.type() == typeid(FunctionCall)) if (holds_alternative<FunctionCall>(_expr))
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect)) if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
if (auto const* builtin = dialect->builtin(boost::get<FunctionCall>(_expr).functionName.name)) if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_expr).functionName.name))
if (builtin->instruction) if (builtin->instruction)
return make_pair(*builtin->instruction, &boost::get<FunctionCall>(_expr).arguments); return make_pair(*builtin->instruction, &std::get<FunctionCall>(_expr).arguments);
return {}; return {};
} }
@ -134,9 +134,9 @@ bool Pattern::matches(
// Resolve the variable if possible. // Resolve the variable if possible.
// Do not do it for "Any" because we can check identity better for variables. // Do not do it for "Any" because we can check identity better for variables.
if (m_kind != PatternKind::Any && _expr.type() == typeid(Identifier)) if (m_kind != PatternKind::Any && holds_alternative<Identifier>(_expr))
{ {
YulString varName = boost::get<Identifier>(_expr).name; YulString varName = std::get<Identifier>(_expr).name;
if (_ssaValues.count(varName)) if (_ssaValues.count(varName))
if (Expression const* new_expr = _ssaValues.at(varName)) if (Expression const* new_expr = _ssaValues.at(varName))
expr = new_expr; expr = new_expr;
@ -145,9 +145,9 @@ bool Pattern::matches(
if (m_kind == PatternKind::Constant) if (m_kind == PatternKind::Constant)
{ {
if (expr->type() != typeid(Literal)) if (!holds_alternative<Literal>(*expr))
return false; return false;
Literal const& literal = boost::get<Literal>(*expr); Literal const& literal = std::get<Literal>(*expr);
if (literal.kind != LiteralKind::Number) if (literal.kind != LiteralKind::Number)
return false; return false;
if (m_data && *m_data != u256(literal.value.str())) if (m_data && *m_data != u256(literal.value.str()))
@ -238,7 +238,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const
u256 Pattern::d() const u256 Pattern::d() const
{ {
return valueOfNumberLiteral(boost::get<Literal>(matchGroupValue())); return valueOfNumberLiteral(std::get<Literal>(matchGroupValue()));
} }
Expression const& Pattern::matchGroupValue() const Expression const& Pattern::matchGroupValue() const

View File

@ -85,9 +85,9 @@ public:
// get called on left-hand-sides of assignments. // get called on left-hand-sides of assignments.
void visit(Expression& _e) override void visit(Expression& _e) override
{ {
if (_e.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_e))
{ {
YulString name = boost::get<Identifier>(_e).name; YulString name = std::get<Identifier>(_e).name;
if (m_expressionCodeCost.count(name)) if (m_expressionCodeCost.count(name))
{ {
if (!m_value.count(name)) if (!m_value.count(name))
@ -162,7 +162,7 @@ bool StackCompressor::run(
{ {
yulAssert( yulAssert(
_object.code && _object.code &&
_object.code->statements.size() > 0 && _object.code->statements.at(0).type() == typeid(Block), _object.code->statements.size() > 0 && holds_alternative<Block>(_object.code->statements.at(0)),
"Need to run the function grouper before the stack compressor." "Need to run the function grouper before the stack compressor."
); );
bool allowMSizeOptimzation = !MSizeFinder::containsMSize(_dialect, *_object.code); bool allowMSizeOptimzation = !MSizeFinder::containsMSize(_dialect, *_object.code);
@ -177,7 +177,7 @@ bool StackCompressor::run(
yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value."); yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value.");
eliminateVariables( eliminateVariables(
_dialect, _dialect,
boost::get<Block>(_object.code->statements.at(0)), std::get<Block>(_object.code->statements.at(0)),
stackSurplus.at({}), stackSurplus.at({}),
allowMSizeOptimzation allowMSizeOptimzation
); );
@ -185,7 +185,7 @@ bool StackCompressor::run(
for (size_t i = 1; i < _object.code->statements.size(); ++i) for (size_t i = 1; i < _object.code->statements.size(); ++i)
{ {
FunctionDefinition& fun = boost::get<FunctionDefinition>(_object.code->statements[i]); FunctionDefinition& fun = std::get<FunctionDefinition>(_object.code->statements[i]);
if (!stackSurplus.count(fun.name)) if (!stackSurplus.count(fun.name))
continue; continue;

View File

@ -95,7 +95,7 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
_statements, _statements,
[&](Statement& _stmt) -> OptionalStatements [&](Statement& _stmt) -> OptionalStatements
{ {
OptionalStatements result = boost::apply_visitor(visitor, _stmt); OptionalStatements result = std::visit(visitor, _stmt);
if (result) if (result)
simplify(*result); simplify(*result);
else else
@ -123,8 +123,8 @@ bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression)
std::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const std::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const
{ {
if (_expression.type() == typeid(Literal)) if (holds_alternative<Literal>(_expression))
return valueOfLiteral(boost::get<Literal>(_expression)); return valueOfLiteral(std::get<Literal>(_expression));
else else
return std::optional<u256>(); return std::optional<u256>();
} }

View File

@ -28,9 +28,9 @@ using namespace yul;
Expression Substitution::translate(Expression const& _expression) Expression Substitution::translate(Expression const& _expression)
{ {
if (_expression.type() == typeid(Identifier)) if (holds_alternative<Identifier>(_expression))
{ {
YulString name = boost::get<Identifier>(_expression).name; YulString name = std::get<Identifier>(_expression).name;
if (m_substitutions.count(name)) if (m_substitutions.count(name))
// No recursive substitution // No recursive substitution
return ASTCopier().translate(*m_substitutions.at(name)); return ASTCopier().translate(*m_substitutions.at(name));

View File

@ -80,7 +80,7 @@ void OptimiserSuite::run(
set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
reservedIdentifiers += _dialect.fixedFunctionNames(); reservedIdentifiers += _dialect.fixedFunctionNames();
*_object.code = boost::get<Block>(Disambiguator( *_object.code = std::get<Block>(Disambiguator(
_dialect, _dialect,
*_object.analysisInfo, *_object.analysisInfo,
reservedIdentifiers reservedIdentifiers
@ -291,7 +291,7 @@ void OptimiserSuite::run(
{ {
// If the first statement is an empty block, remove it. // If the first statement is an empty block, remove it.
// We should only have function definitions after that. // We should only have function definitions after that.
if (ast.statements.size() > 1 && boost::get<Block>(ast.statements.front()).statements.empty()) if (ast.statements.size() > 1 && std::get<Block>(ast.statements.front()).statements.empty())
ast.statements.erase(ast.statements.begin()); ast.statements.erase(ast.statements.begin());
} }
suite.runSequence({ suite.runSequence({
@ -361,7 +361,7 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
{ {
unique_ptr<Block> copy; unique_ptr<Block> copy;
if (m_debug == Debug::PrintChanges) if (m_debug == Debug::PrintChanges)
copy = make_unique<Block>(boost::get<Block>(ASTCopier{}(_ast))); copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
for (string const& step: _steps) for (string const& step: _steps)
{ {
if (m_debug == Debug::PrintStep) if (m_debug == Debug::PrintStep)
@ -376,7 +376,7 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
{ {
cout << "== Running " << step << " changed the AST." << endl; cout << "== Running " << step << " changed the AST." << endl;
cout << AsmPrinter{}(_ast) << endl; cout << AsmPrinter{}(_ast) << endl;
copy = make_unique<Block>(boost::get<Block>(ASTCopier{}(_ast))); copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
} }
} }
} }

View File

@ -32,7 +32,7 @@ using namespace yul;
bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _rhs) bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _rhs)
{ {
return boost::apply_visitor([this](auto&& _lhsExpr, auto&& _rhsExpr) -> bool { return std::visit([this](auto&& _lhsExpr, auto&& _rhsExpr) -> bool {
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x. // ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
return this->expressionEqual(_lhsExpr, _rhsExpr); return this->expressionEqual(_lhsExpr, _rhsExpr);
}, _lhs, _rhs); }, _lhs, _rhs);
@ -40,7 +40,7 @@ bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _r
bool SyntacticallyEqual::operator()(Statement const& _lhs, Statement const& _rhs) bool SyntacticallyEqual::operator()(Statement const& _lhs, Statement const& _rhs)
{ {
return boost::apply_visitor([this](auto&& _lhsStmt, auto&& _rhsStmt) -> bool { return std::visit([this](auto&& _lhsStmt, auto&& _rhsStmt) -> bool {
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x. // ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
return this->statementEqual(_lhsStmt, _rhsStmt); return this->statementEqual(_lhsStmt, _rhsStmt);
}, _lhs, _rhs); }, _lhs, _rhs);

View File

@ -68,18 +68,18 @@ UnusedPruner::UnusedPruner(
void UnusedPruner::operator()(Block& _block) void UnusedPruner::operator()(Block& _block)
{ {
for (auto&& statement: _block.statements) for (auto&& statement: _block.statements)
if (statement.type() == typeid(FunctionDefinition)) if (holds_alternative<FunctionDefinition>(statement))
{ {
FunctionDefinition& funDef = boost::get<FunctionDefinition>(statement); FunctionDefinition& funDef = std::get<FunctionDefinition>(statement);
if (!used(funDef.name)) if (!used(funDef.name))
{ {
subtractReferences(ReferencesCounter::countReferences(funDef.body)); subtractReferences(ReferencesCounter::countReferences(funDef.body));
statement = Block{std::move(funDef.location), {}}; statement = Block{std::move(funDef.location), {}};
} }
} }
else if (statement.type() == typeid(VariableDeclaration)) else if (holds_alternative<VariableDeclaration>(statement))
{ {
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(statement); VariableDeclaration& varDecl = std::get<VariableDeclaration>(statement);
// Multi-variable declarations are special. We can only remove it // Multi-variable declarations are special. We can only remove it
// if all variables are unused and the right-hand-side is either // if all variables are unused and the right-hand-side is either
// movable or it returns a single value. In the latter case, we // movable or it returns a single value. In the latter case, we
@ -108,9 +108,9 @@ void UnusedPruner::operator()(Block& _block)
}}; }};
} }
} }
else if (statement.type() == typeid(ExpressionStatement)) else if (holds_alternative<ExpressionStatement>(statement))
{ {
ExpressionStatement& exprStmt = boost::get<ExpressionStatement>(statement); ExpressionStatement& exprStmt = std::get<ExpressionStatement>(statement);
if ( if (
SideEffectsCollector(m_dialect, exprStmt.expression, m_functionSideEffects). SideEffectsCollector(m_dialect, exprStmt.expression, m_functionSideEffects).
sideEffectFree(m_allowMSizeOptimization) sideEffectFree(m_allowMSizeOptimization)

View File

@ -51,5 +51,5 @@ void VarDeclInitializer::operator()(Block& _block)
} }
} }
}; };
iterateReplacing(_block.statements, boost::apply_visitor(visitor)); iterateReplacing(_block.statements, [&](auto&& _statement) { return std::visit(visitor, _statement); });
} }

View File

@ -40,8 +40,8 @@ VarNameCleaner::VarNameCleaner(
m_translatedNames{} m_translatedNames{}
{ {
for (auto const& statement: _ast.statements) for (auto const& statement: _ast.statements)
if (statement.type() == typeid(FunctionDefinition)) if (holds_alternative<FunctionDefinition>(statement))
m_blacklist.insert(boost::get<FunctionDefinition>(statement).name); m_blacklist.insert(std::get<FunctionDefinition>(statement).name);
m_usedNames = m_blacklist; m_usedNames = m_blacklist;
} }

View File

@ -81,7 +81,7 @@ EVM_VERSIONS="homestead byzantium"
if [ -z "$CI" ] if [ -z "$CI" ]
then then
EVM_VERSIONS+=" constantinople petersburg" EVM_VERSIONS+=" constantinople petersburg istanbul"
fi fi
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer # And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
@ -91,9 +91,9 @@ do
for vm in $EVM_VERSIONS for vm in $EVM_VERSIONS
do do
FORCE_ABIV2_RUNS="no" FORCE_ABIV2_RUNS="no"
if [[ "$vm" == "constantinople" ]] if [[ "$vm" == "istanbul" ]]
then then
FORCE_ABIV2_RUNS="no yes" # run both in constantinople FORCE_ABIV2_RUNS="no yes" # run both in istanbul
fi fi
for abiv2 in $FORCE_ABIV2_RUNS for abiv2 in $FORCE_ABIV2_RUNS
do do

View File

@ -32,13 +32,13 @@ namespace test
#ifdef _WIN32 #ifdef _WIN32
static constexpr auto evmoneFilename = "evmone.dll"; static constexpr auto evmoneFilename = "evmone.dll";
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-windows-amd64.zip"; static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-windows-amd64.zip";
#elif defined(__APPLE__) #elif defined(__APPLE__)
static constexpr auto evmoneFilename = "libevmone.dylib"; static constexpr auto evmoneFilename = "libevmone.dylib";
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-darwin-x86_64.tar.gz"; static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-darwin-x86_64.tar.gz";
#else #else
static constexpr auto evmoneFilename = "libevmone.so"; static constexpr auto evmoneFilename = "libevmone.so";
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz"; static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-linux-x86_64.tar.gz";
#endif #endif

View File

@ -64,7 +64,8 @@ evmc::VM* EVMHost::getVM(string const& _path)
} }
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm): EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm):
m_vm(_vm) m_vm(_vm),
m_evmVersion(_evmVersion)
{ {
if (!m_vm) if (!m_vm)
{ {
@ -73,21 +74,21 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm):
} }
if (_evmVersion == langutil::EVMVersion::homestead()) if (_evmVersion == langutil::EVMVersion::homestead())
m_evmVersion = EVMC_HOMESTEAD; m_evmRevision = EVMC_HOMESTEAD;
else if (_evmVersion == langutil::EVMVersion::tangerineWhistle()) else if (_evmVersion == langutil::EVMVersion::tangerineWhistle())
m_evmVersion = EVMC_TANGERINE_WHISTLE; m_evmRevision = EVMC_TANGERINE_WHISTLE;
else if (_evmVersion == langutil::EVMVersion::spuriousDragon()) else if (_evmVersion == langutil::EVMVersion::spuriousDragon())
m_evmVersion = EVMC_SPURIOUS_DRAGON; m_evmRevision = EVMC_SPURIOUS_DRAGON;
else if (_evmVersion == langutil::EVMVersion::byzantium()) else if (_evmVersion == langutil::EVMVersion::byzantium())
m_evmVersion = EVMC_BYZANTIUM; m_evmRevision = EVMC_BYZANTIUM;
else if (_evmVersion == langutil::EVMVersion::constantinople()) else if (_evmVersion == langutil::EVMVersion::constantinople())
m_evmVersion = EVMC_CONSTANTINOPLE; m_evmRevision = EVMC_CONSTANTINOPLE;
else if (_evmVersion == langutil::EVMVersion::istanbul()) else if (_evmVersion == langutil::EVMVersion::istanbul())
m_evmVersion = EVMC_ISTANBUL; m_evmRevision = EVMC_ISTANBUL;
else if (_evmVersion == langutil::EVMVersion::berlin()) else if (_evmVersion == langutil::EVMVersion::berlin())
assertThrow(false, Exception, "Berlin is not supported yet."); assertThrow(false, Exception, "Berlin is not supported yet.");
else //if (_evmVersion == langutil::EVMVersion::petersburg()) else //if (_evmVersion == langutil::EVMVersion::petersburg())
m_evmVersion = EVMC_PETERSBURG; m_evmRevision = EVMC_PETERSBURG;
} }
evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept
@ -146,7 +147,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
{ {
message.gas -= message.kind == EVMC_CREATE ? eth::GasCosts::txCreateGas : eth::GasCosts::txGas; message.gas -= message.kind == EVMC_CREATE ? eth::GasCosts::txCreateGas : eth::GasCosts::txGas;
for (size_t i = 0; i < message.input_size; ++i) for (size_t i = 0; i < message.input_size; ++i)
message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas; message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas(m_evmVersion);
if (message.gas < 0) if (message.gas < 0)
{ {
evmc::result result({}); evmc::result result({});
@ -191,7 +192,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
evmc::address currentAddress = m_currentAddress; evmc::address currentAddress = m_currentAddress;
m_currentAddress = message.destination; m_currentAddress = message.destination;
evmc::result result = m_vm->execute(*this, m_evmVersion, message, code.data(), code.size()); evmc::result result = m_vm->execute(*this, m_evmRevision, message, code.data(), code.size());
m_currentAddress = currentAddress; m_currentAddress = currentAddress;
if (message.kind == EVMC_CREATE) if (message.kind == EVMC_CREATE)

View File

@ -180,7 +180,10 @@ private:
static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept; static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept;
evmc::VM* m_vm = nullptr; evmc::VM* m_vm = nullptr;
evmc_revision m_evmVersion; // EVM version requested by the testing tool
langutil::EVMVersion m_evmVersion;
// EVM version requested from EVMC (matches the above)
evmc_revision m_evmRevision;
}; };

View File

@ -16,7 +16,6 @@ target_sources(evmc INTERFACE
${PROJECT_SOURCE_DIR}/test/evmc/evmc.h ${PROJECT_SOURCE_DIR}/test/evmc/evmc.h
${PROJECT_SOURCE_DIR}/test/evmc/evmc.hpp ${PROJECT_SOURCE_DIR}/test/evmc/evmc.hpp
${PROJECT_SOURCE_DIR}/test/evmc/helpers.h ${PROJECT_SOURCE_DIR}/test/evmc/helpers.h
${PROJECT_SOURCE_DIR}/test/evmc/helpers.hpp
${PROJECT_SOURCE_DIR}/test/evmc/utils.h ${PROJECT_SOURCE_DIR}/test/evmc/utils.h
) )
target_include_directories(evmc INTERFACE ${PROJECT_SOURCE_DIR}/test/) target_include_directories(evmc INTERFACE ${PROJECT_SOURCE_DIR}/test/)

3
test/evmc/README.md Normal file
View File

@ -0,0 +1,3 @@
# EVMC
This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.0.0](https://github.com/ethereum/evmc/releases/tag/v7.0.0).

View File

@ -334,118 +334,6 @@ public:
} }
}; };
class Host;
/// @copybrief evmc_vm
///
/// This is a RAII wrapper for evmc_vm and objects of this type
/// automatically destroys the VM instance.
class VM
{
public:
VM() noexcept = default;
/// Converting constructor from evmc_vm.
explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
/// Destructor responsible for automatically destroying the VM instance.
~VM() noexcept
{
if (m_instance)
m_instance->destroy(m_instance);
}
VM(const VM&) = delete;
VM& operator=(const VM&) = delete;
/// Move constructor.
VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
/// Move assignment operator.
VM& operator=(VM&& other) noexcept
{
this->~VM();
m_instance = other.m_instance;
other.m_instance = nullptr;
return *this;
}
/// The constructor that captures a VM instance and configures the instance
/// with the provided list of options.
inline VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
/// Checks if contains a valid pointer to the VM instance.
explicit operator bool() const noexcept { return m_instance != nullptr; }
/// Checks whenever the VM instance is ABI compatible with the current EVMC API.
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
/// @copydoc evmc_vm::name
char const* name() const noexcept { return m_instance->name; }
/// @copydoc evmc_vm::version
char const* version() const noexcept { return m_instance->version; }
/// @copydoc evmc::vm::get_capabilities
evmc_capabilities_flagset get_capabilities() const noexcept
{
return m_instance->get_capabilities(m_instance);
}
/// @copydoc evmc_set_option()
evmc_set_option_result set_option(const char name[], const char value[]) noexcept
{
return evmc_set_option(m_instance, name, value);
}
/// @copydoc evmc_execute()
result execute(const evmc_host_interface& host,
evmc_host_context* ctx,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)};
}
/// Convenient variant of the VM::execute() that takes reference to evmc::Host class.
inline result execute(Host& host,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept;
/// Executes code without the Host context.
///
/// The same as
/// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision,
/// const evmc_message&, const uint8_t*, size_t),
/// but without providing the Host context and interface.
/// This method is for experimental precompiles support where execution is
/// guaranteed not to require any Host access.
result execute(evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{
m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)};
}
private:
evmc_vm* m_instance = nullptr;
};
inline VM::VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
: m_instance{vm}
{
for (const auto& option : options)
set_option(option.first, option.second);
}
/// The EVMC Host interface /// The EVMC Host interface
class HostInterface class HostInterface
@ -514,8 +402,10 @@ public:
HostContext() = default; HostContext() = default;
/// Constructor from the EVMC Host primitives. /// Constructor from the EVMC Host primitives.
HostContext(const evmc_host_interface* interface, evmc_host_context* ctx) noexcept /// @param interface The reference to the Host interface.
: host{interface}, context{ctx} /// @param ctx The pointer to the Host context object. This parameter MAY be null.
HostContext(const evmc_host_interface& interface, evmc_host_context* ctx) noexcept
: host{&interface}, context{ctx}
{} {}
bool account_exists(const address& address) noexcept final bool account_exists(const address& address) noexcept final
@ -596,6 +486,7 @@ public:
} }
}; };
/// Abstract class to be used by Host implementations. /// Abstract class to be used by Host implementations.
/// ///
/// When implementing EVMC Host, you can directly inherit from the evmc::Host class. /// When implementing EVMC Host, you can directly inherit from the evmc::Host class.
@ -628,7 +519,82 @@ public:
}; };
inline result VM::execute(Host& host, /// @copybrief evmc_vm
///
/// This is a RAII wrapper for evmc_vm, and object of this type
/// automatically destroys the VM instance.
class VM
{
public:
VM() noexcept = default;
/// Converting constructor from evmc_vm.
explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
/// Destructor responsible for automatically destroying the VM instance.
~VM() noexcept
{
if (m_instance)
m_instance->destroy(m_instance);
}
VM(const VM&) = delete;
VM& operator=(const VM&) = delete;
/// Move constructor.
VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
/// Move assignment operator.
VM& operator=(VM&& other) noexcept
{
this->~VM();
m_instance = other.m_instance;
other.m_instance = nullptr;
return *this;
}
/// The constructor that captures a VM instance and configures the instance
/// with the provided list of options.
inline VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
/// Checks if contains a valid pointer to the VM instance.
explicit operator bool() const noexcept { return m_instance != nullptr; }
/// Checks whenever the VM instance is ABI compatible with the current EVMC API.
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
/// @copydoc evmc_vm::name
char const* name() const noexcept { return m_instance->name; }
/// @copydoc evmc_vm::version
char const* version() const noexcept { return m_instance->version; }
/// @copydoc evmc::vm::get_capabilities
evmc_capabilities_flagset get_capabilities() const noexcept
{
return m_instance->get_capabilities(m_instance);
}
/// @copydoc evmc_set_option()
evmc_set_option_result set_option(const char name[], const char value[]) noexcept
{
return evmc_set_option(m_instance, name, value);
}
/// @copydoc evmc_execute()
result execute(const evmc_host_interface& host,
evmc_host_context* ctx,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)};
}
/// Convenient variant of the VM::execute() that takes reference to evmc::Host class.
result execute(Host& host,
evmc_revision rev, evmc_revision rev,
const evmc_message& msg, const evmc_message& msg,
const uint8_t* code, const uint8_t* code,
@ -637,6 +603,36 @@ inline result VM::execute(Host& host,
return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size); return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size);
} }
/// Executes code without the Host context.
///
/// The same as
/// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision,
/// const evmc_message&, const uint8_t*, size_t),
/// but without providing the Host context and interface.
/// This method is for experimental precompiles support where execution is
/// guaranteed not to require any Host access.
result execute(evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{
m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)};
}
private:
evmc_vm* m_instance = nullptr;
};
inline VM::VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
: m_instance{vm}
{
// This constructor is implemented outside of the class definition to workaround a doxygen bug.
for (const auto& option : options)
set_option(option.first, option.second);
}
namespace internal namespace internal
{ {

View File

@ -1,116 +0,0 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018-2019 The EVMC Authors.
* Licensed under the Apache License, Version 2.0.
*/
/**
* @file
* A collection of helpers (overloaded operators) for using EVMC types effectively in C++.
*
* @addtogroup helpers
* @{
*/
#pragma once
#include <evmc/evmc.hpp>
#include <cstring>
#include <functional>
using evmc::is_zero;
/// The comparator for std::map<evmc_address, ...>.
EVMC_DEPRECATED
inline bool operator<(const evmc_address& a, const evmc_address& b)
{
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
}
/// The comparator for std::map<evmc_bytes32, ...>.
EVMC_DEPRECATED
inline bool operator<(const evmc_bytes32& a, const evmc_bytes32& b)
{
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
}
/// The comparator for equality.
EVMC_DEPRECATED
inline bool operator==(const evmc_address& a, const evmc_address& b)
{
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
}
/// The comparator for equality.
EVMC_DEPRECATED
inline bool operator==(const evmc_bytes32& a, const evmc_bytes32& b)
{
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
}
/// Parameters for the fnv1a hash function, specialized by the hash result size (size_t).
///
/// The values for the matching size are taken from
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters.
///
/// @tparam size The size of the hash result (size_t).
template <size_t size>
struct fnv1_params
{
};
/// Parameters for the fnv1a hash function, specialized for the hash result of 4 bytes.
template <>
struct fnv1_params<4>
{
static constexpr auto prime = 0x1000193; ///< The FNV prime.
static constexpr auto offset_basis = 0x811c9dc5; ///< The FNV offset basis.
};
/// Parameters for the fnv1a hash function, specialized for the hash result of 8 bytes.
template <>
struct fnv1_params<8>
{
static constexpr auto prime = 0x100000001b3; ///< The FNV prime.
static constexpr auto offset_basis = 0xcbf29ce484222325; ///< The FNV offset basis.
};
/// FNV1a hash function.
inline size_t fnv1a(const uint8_t* ptr, size_t len) noexcept
{
using params = fnv1_params<sizeof(size_t)>;
auto ret = size_t{params::offset_basis};
for (size_t i = 0; i < len; i++)
{
ret ^= ptr[i];
ret *= params::prime;
}
return ret;
}
namespace std
{
/// Hash operator template specialization for evmc_address needed for unordered containers.
template <>
struct EVMC_DEPRECATED hash<evmc_address>
{
/// Hash operator using FNV1a.
size_t operator()(const evmc_address& s) const noexcept
{
return fnv1a(s.bytes, sizeof(s.bytes));
}
};
/// Hash operator template needed for std::unordered_set and others using hashes.
template <>
struct EVMC_DEPRECATED hash<evmc_bytes32>
{
/// Hash operator using FNV1a.
size_t operator()(const evmc_bytes32& s) const noexcept
{
return fnv1a(s.bytes, sizeof(s.bytes));
}
};
} // namespace std
/** @} */

View File

@ -246,7 +246,7 @@ function truffle_run_test
for optimize in "${optimizer_settings[@]}" for optimize in "${optimizer_settings[@]}"
do do
clean clean
force_solc_settings "$CONFIG" "$optimize" "petersburg" force_solc_settings "$CONFIG" "$optimize" "istanbul"
# Force ABIEncoderV2 in the last step. Has to be the last because code is modified. # Force ABIEncoderV2 in the last step. Has to be the last because code is modified.
if [ "$FORCE_ABIv2" = true ]; then if [ "$FORCE_ABIv2" = true ]; then
[[ "$optimize" =~ yul ]] && force_abi_v2 [[ "$optimize" =~ yul ]] && force_abi_v2

View File

@ -19,6 +19,7 @@
*/ */
#include <test/libsolidity/SolidityExecutionFramework.h> #include <test/libsolidity/SolidityExecutionFramework.h>
#include <liblangutil/EVMVersion.h>
#include <libdevcore/IpfsHash.h> #include <libdevcore/IpfsHash.h>
#include <libevmasm/GasMeter.h> #include <libevmasm/GasMeter.h>
@ -37,10 +38,10 @@ namespace solidity
namespace test namespace test
{ {
#define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt) \ #define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt, _evmVersion) \
do \ do \
{ \ { \
u256 ipfsCost = GasMeter::dataGas(dev::ipfsHash(m_compiler.metadata(m_compiler.lastContractName())), true); \ u256 ipfsCost = GasMeter::dataGas(dev::ipfsHash(m_compiler.metadata(m_compiler.lastContractName())), true, _evmVersion); \
u256 gasOpt{_gasOpt}; \ u256 gasOpt{_gasOpt}; \
u256 gasNoOpt{_gasNoOpt}; \ u256 gasNoOpt{_gasNoOpt}; \
u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \ u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \
@ -95,34 +96,61 @@ BOOST_AUTO_TEST_CASE(string_storage)
m_compiler.overwriteReleaseFlag(true); m_compiler.overwriteReleaseFlag(true);
compileAndRun(sourceCode); compileAndRun(sourceCode);
if (Options::get().evmVersion() <= EVMVersion::byzantium()) auto evmVersion = dev::test::Options::get().evmVersion();
CHECK_DEPLOY_GAS(134145, 130831);
if (evmVersion <= EVMVersion::byzantium())
CHECK_DEPLOY_GAS(134145, 130831, evmVersion);
// This is only correct on >=Constantinople. // This is only correct on >=Constantinople.
else if (Options::get().useABIEncoderV2) else if (Options::get().useABIEncoderV2)
{ {
if (Options::get().optimizeYul) if (Options::get().optimizeYul)
CHECK_DEPLOY_GAS(127785, 127721); {
// Costs with 0 are cases which cannot be triggered in tests.
if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(0, 127721, evmVersion);
else else
CHECK_DEPLOY_GAS(151587, 135371); CHECK_DEPLOY_GAS(0, 113993, evmVersion);
} }
else else
CHECK_DEPLOY_GAS(126929, 119659); {
if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(151523, 135371, evmVersion);
else
CHECK_DEPLOY_GAS(134883, 120083, evmVersion);
}
}
else if (evmVersion < EVMVersion::istanbul())
CHECK_DEPLOY_GAS(126929, 119659, evmVersion);
else
CHECK_DEPLOY_GAS(114345, 107335, evmVersion);
if (Options::get().evmVersion() >= EVMVersion::byzantium()) if (evmVersion >= EVMVersion::byzantium())
{ {
callContractFunction("f()"); callContractFunction("f()");
if (Options::get().evmVersion() == EVMVersion::byzantium()) if (evmVersion == EVMVersion::byzantium())
CHECK_GAS(21551, 21526, 20); CHECK_GAS(21545, 21526, 20);
// This is only correct on >=Constantinople. // This is only correct on >=Constantinople.
else if (Options::get().useABIEncoderV2) else if (Options::get().useABIEncoderV2)
{ {
if (Options::get().optimizeYul) if (Options::get().optimizeYul)
CHECK_GAS(21713, 21567, 20); {
if (evmVersion < EVMVersion::istanbul())
CHECK_GAS(0, 21567, 20);
else else
CHECK_GAS(21713, 21635, 20); CHECK_GAS(0, 21351, 20);
} }
else else
{
if (evmVersion < EVMVersion::istanbul())
CHECK_GAS(21707, 21635, 20);
else
CHECK_GAS(21499, 21431, 20);
}
}
else if (evmVersion < EVMVersion::istanbul())
CHECK_GAS(21546, 21526, 20); CHECK_GAS(21546, 21526, 20);
else
CHECK_GAS(21332, 21322, 20);
} }
} }

View File

@ -114,9 +114,10 @@ public:
static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation) static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
{ {
auto evmVersion = dev::test::Options::get().evmVersion();
GasMeter::GasConsumption gas = _isCreation ? GasCosts::txCreateGas : GasCosts::txGas; GasMeter::GasConsumption gas = _isCreation ? GasCosts::txCreateGas : GasCosts::txGas;
for (auto i: _data) for (auto i: _data)
gas += i != 0 ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas; gas += i != 0 ? GasCosts::txDataNonZeroGas(evmVersion) : GasCosts::txDataZeroGas;
return gas; return gas;
} }

View File

@ -0,0 +1,12 @@
contract C {
function f() public returns (uint id) {
assembly {
id := chainid()
}
}
}
// ====
// compileViaYul: also
// EVMVersion: >=istanbul
// ----
// f() -> 1

View File

@ -0,0 +1,12 @@
contract C {
function f() public payable returns (uint ret) {
assembly {
ret := selfbalance()
}
}
}
// ====
// EVMVersion: >=istanbul
// compileViaYul: also
// ----
// f(), 254 ether -> 254

View File

@ -0,0 +1,15 @@
contract S
{
int o;
function foo() public returns (int) { return o = 3; }
}
contract B is S
{
function fii() public
{
o = S(super).foo();
}
}
// ----
// TypeError: (129-137): Explicit type conversion not allowed from "contract super B" to "contract S".

Some files were not shown because too many files have changed in this diff Show More