diff options
92 files changed, 721 insertions, 456 deletions
diff --git a/docs/types.rst b/docs/types.rst index bd5d1734..34b94b88 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -1225,7 +1225,6 @@ is possible if it makes sense semantically and no information is lost: ``uint8`` is convertible to ``uint16`` and ``int128`` to ``int256``, but ``int8`` is not convertible to ``uint256`` (because ``uint256`` cannot hold e.g. ``-1``). -Any integer type that can be converted to ``uint160`` can also be converted to ``address``. For more details, please consult the sections about the types themselves. @@ -1335,4 +1334,4 @@ Addresses As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type. -Explicit conversions from ``bytes20`` or any integer type to ``address`` results in ``address payable``.
\ No newline at end of file +Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``. diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 0363d9a2..6208424e 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -64,15 +64,13 @@ #include <functional> #include <string> -using byte = uint8_t; - namespace dev { // Binary data types. -using bytes = std::vector<byte>; -using bytesRef = vector_ref<byte>; -using bytesConstRef = vector_ref<byte const>; +using bytes = std::vector<uint8_t>; +using bytesRef = vector_ref<uint8_t>; +using bytesConstRef = vector_ref<uint8_t const>; // Numeric types. using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>; diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index fa1a5353..91c60ffe 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -64,7 +64,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) int h = fromHex(_s[i], WhenError::DontThrow); int l = fromHex(_s[i + 1], WhenError::DontThrow); if (h != -1 && l != -1) - ret.push_back((byte)(h * 16 + l)); + ret.push_back((uint8_t)(h * 16 + l)); else if (_throw == WhenError::Throw) BOOST_THROW_EXCEPTION(BadHexCharacter()); else diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 0782fabc..fedd3af2 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -88,7 +88,7 @@ inline std::string asString(bytesConstRef _b) /// Converts a string to a byte array containing the string's (byte) data. inline bytes asBytes(std::string const& _b) { - return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size())); + return bytes((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size())); } // Big-endian to/from host endian conversion functions. @@ -117,7 +117,7 @@ inline T fromBigEndian(_In const& _bytes) { T ret = (T)0; for (auto i: _bytes) - ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i); + ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned<typename _In::value_type>::type)i); return ret; } inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } @@ -135,7 +135,7 @@ inline bytes toCompactBigEndian(T _val, unsigned _min = 0) toBigEndian(_val, ret); return ret; } -inline bytes toCompactBigEndian(byte _val, unsigned _min = 0) +inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0) { return (_min || _val) ? bytes{ _val } : bytes{}; } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index cd6e1da1..24b89840 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -79,7 +79,7 @@ public: operator Arith() const { return fromBigEndian<Arith>(m_data); } /// @returns true iff this is the empty hash. - explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 0; }); } + explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](uint8_t _b) { return _b != 0; }); } // The obvious comparison operators. bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } @@ -90,9 +90,9 @@ public: FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; } /// @returns a particular byte from the hash. - byte& operator[](unsigned _i) { return m_data[_i]; } + uint8_t& operator[](unsigned _i) { return m_data[_i]; } /// @returns a particular byte from the hash. - byte operator[](unsigned _i) const { return m_data[_i]; } + uint8_t operator[](unsigned _i) const { return m_data[_i]; } /// @returns the hash as a user-readable hex string. std::string hex() const { return toHex(ref()); } @@ -104,19 +104,19 @@ public: bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); } /// @returns a mutable byte pointer to the object's data. - byte* data() { return m_data.data(); } + uint8_t* data() { return m_data.data(); } /// @returns a constant byte pointer to the object's data. - byte const* data() const { return m_data.data(); } + uint8_t const* data() const { return m_data.data(); } /// @returns a copy of the object's data as a byte vector. bytes asBytes() const { return bytes(data(), data() + N); } /// @returns a mutable reference to the object's data as an STL array. - std::array<byte, N>& asArray() { return m_data; } + std::array<uint8_t, N>& asArray() { return m_data; } /// @returns a constant reference to the object's data as an STL array. - std::array<byte, N> const& asArray() const { return m_data; } + std::array<uint8_t, N> const& asArray() const { return m_data; } /// Returns the index of the first bit set to one, or size() * 8 if no bits are set. inline unsigned firstBitSet() const @@ -137,7 +137,7 @@ public: void clear() { m_data.fill(0); } private: - std::array<byte, N> m_data; ///< The binary data. + std::array<uint8_t, N> m_data; ///< The binary data. }; /// Stream I/O for the FixedHash class. diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index c2eaa1ca..e63194a0 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -525,14 +525,14 @@ LinkerObject const& Assembly::assemble() const multimap<size_t, size_t> subRef; vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted unsigned bytesPerTag = dev::bytesRequired(bytesRequiredForCode); - byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + uint8_t tagPush = (uint8_t)Instruction::PUSH1 - 1 + bytesPerTag; unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + m_auxiliaryData.size(); for (auto const& sub: m_subs) bytesRequiredIncludingData += sub->assemble().bytecode.size(); unsigned bytesPerDataRef = dev::bytesRequired(bytesRequiredIncludingData); - byte dataRefPush = (byte)Instruction::PUSH1 - 1 + bytesPerDataRef; + uint8_t dataRefPush = (uint8_t)Instruction::PUSH1 - 1 + bytesPerDataRef; ret.bytecode.reserve(bytesRequiredIncludingData); for (AssemblyItem const& i: m_items) @@ -544,25 +544,25 @@ LinkerObject const& Assembly::assemble() const switch (i.type()) { case Operation: - ret.bytecode.push_back((byte)i.instruction()); + ret.bytecode.push_back((uint8_t)i.instruction()); break; case PushString: { - ret.bytecode.push_back((byte)Instruction::PUSH32); + ret.bytecode.push_back((uint8_t)Instruction::PUSH32); unsigned ii = 0; for (auto j: m_strings.at((h256)i.data())) if (++ii > 32) break; else - ret.bytecode.push_back((byte)j); + ret.bytecode.push_back((uint8_t)j); while (ii++ < 32) ret.bytecode.push_back(0); break; } case Push: { - byte b = max<unsigned>(1, dev::bytesRequired(i.data())); - ret.bytecode.push_back((byte)Instruction::PUSH1 - 1 + b); + uint8_t b = max<unsigned>(1, dev::bytesRequired(i.data())); + ret.bytecode.push_back((uint8_t)Instruction::PUSH1 - 1 + b); ret.bytecode.resize(ret.bytecode.size() + b); bytesRef byr(&ret.bytecode.back() + 1 - b, b); toBigEndian(i.data(), byr); @@ -589,8 +589,8 @@ LinkerObject const& Assembly::assemble() const { auto s = m_subs.at(size_t(i.data()))->assemble().bytecode.size(); i.setPushedValue(u256(s)); - byte b = max<unsigned>(1, dev::bytesRequired(s)); - ret.bytecode.push_back((byte)Instruction::PUSH1 - 1 + b); + uint8_t b = max<unsigned>(1, dev::bytesRequired(s)); + ret.bytecode.push_back((uint8_t)Instruction::PUSH1 - 1 + b); ret.bytecode.resize(ret.bytecode.size() + b); bytesRef byr(&ret.bytecode.back() + 1 - b, b); toBigEndian(s, byr); @@ -604,12 +604,12 @@ LinkerObject const& Assembly::assemble() const break; } case PushLibraryAddress: - ret.bytecode.push_back(byte(Instruction::PUSH20)); + ret.bytecode.push_back(uint8_t(Instruction::PUSH20)); ret.linkReferences[ret.bytecode.size()] = m_libraries.at(i.data()); ret.bytecode.resize(ret.bytecode.size() + 20); break; case PushDeployTimeAddress: - ret.bytecode.push_back(byte(Instruction::PUSH20)); + ret.bytecode.push_back(uint8_t(Instruction::PUSH20)); ret.bytecode.resize(ret.bytecode.size() + 20); break; case Tag: @@ -618,7 +618,7 @@ LinkerObject const& Assembly::assemble() const assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large."); assertThrow(m_tagPositionsInBytecode[size_t(i.data())] == size_t(-1), AssemblyException, "Duplicate tag position."); m_tagPositionsInBytecode[size_t(i.data())] = ret.bytecode.size(); - ret.bytecode.push_back((byte)Instruction::JUMPDEST); + ret.bytecode.push_back((uint8_t)Instruction::JUMPDEST); break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); @@ -627,7 +627,7 @@ LinkerObject const& Assembly::assemble() const if (!m_subs.empty() || !m_data.empty() || !m_auxiliaryData.empty()) // Append an INVALID here to help tests find miscompilation. - ret.bytecode.push_back(byte(Instruction::INVALID)); + ret.bytecode.push_back(uint8_t(Instruction::INVALID)); for (size_t i = 0; i < m_subs.size(); ++i) { diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 5319a2b6..6187e18f 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -69,7 +69,7 @@ public: m_location(_location) { if (m_type == Operation) - m_instruction = Instruction(byte(_data)); + m_instruction = Instruction(uint8_t(_data)); else m_data = std::make_shared<u256>(_data); } diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 63424eeb..539a83b0 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -228,25 +228,25 @@ inline bool isLogInstruction(Instruction _inst) /// @returns the number of PUSH Instruction _inst inline unsigned getPushNumber(Instruction _inst) { - return (byte)_inst - unsigned(Instruction::PUSH1) + 1; + return (uint8_t)_inst - unsigned(Instruction::PUSH1) + 1; } /// @returns the number of DUP Instruction _inst inline unsigned getDupNumber(Instruction _inst) { - return (byte)_inst - unsigned(Instruction::DUP1) + 1; + return (uint8_t)_inst - unsigned(Instruction::DUP1) + 1; } /// @returns the number of SWAP Instruction _inst inline unsigned getSwapNumber(Instruction _inst) { - return (byte)_inst - unsigned(Instruction::SWAP1) + 1; + return (uint8_t)_inst - unsigned(Instruction::SWAP1) + 1; } /// @returns the number of LOG Instruction _inst inline unsigned getLogNumber(Instruction _inst) { - return (byte)_inst - unsigned(Instruction::LOG0); + return (uint8_t)_inst - unsigned(Instruction::LOG0); } /// @returns the PUSH<_number> instruction diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index ba13a611..120d1787 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -48,7 +48,7 @@ SimplificationRule<Pattern> const* Rules::findFirstMatch( resetMatchGroups(); assertThrow(_expr.item, OptimizerException, ""); - for (auto const& rule: m_rules[byte(_expr.item->instruction())]) + for (auto const& rule: m_rules[uint8_t(_expr.item->instruction())]) { if (rule.pattern.matches(_expr, _classes)) return &rule; @@ -59,7 +59,7 @@ SimplificationRule<Pattern> const* Rules::findFirstMatch( bool Rules::isInitialized() const { - return !m_rules[byte(Instruction::ADD)].empty(); + return !m_rules[uint8_t(Instruction::ADD)].empty(); } void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules) @@ -70,7 +70,7 @@ void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules) void Rules::addRule(SimplificationRule<Pattern> const& _rule) { - m_rules[byte(_rule.pattern.instruction())].push_back(_rule); + m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule); } Rules::Rules() diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 0aef05a9..85480119 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -348,7 +348,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (i.which() == sp::utree_type::string_type) { auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>(); - data.insert(data.end(), (byte const *)sr.begin(), (byte const*)sr.end()); + data.insert(data.end(), (uint8_t const *)sr.begin(), (uint8_t const*)sr.end()); } else if (i.which() == sp::utree_type::any_type) { diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f62d9c3b..2adc8e77 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -271,16 +271,16 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) ErrorReporter errorsIgnored(errors); yul::ExternalIdentifierAccess::Resolver resolver = [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) { - auto declarations = m_resolver.nameFromCurrentScope(_identifier.name); - bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot"); - bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset"); + auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str()); + bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot"); + bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset"); if (isSlot || isOffset) { // special mode to access storage variables if (!declarations.empty()) // the special identifier exists itself, we should not allow that. return size_t(-1); - string realName = _identifier.name.substr(0, _identifier.name.size() - ( + string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - ( isSlot ? string("_slot").size() : string("_offset").size() diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 569e5b0e..2d26ce8a 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -459,7 +459,7 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node) if (it.first) { Json::Value tuple(Json::objectValue); - tuple[it.first->name] = inlineAssemblyIdentifierToJson(it); + tuple[it.first->name.str()] = inlineAssemblyIdentifierToJson(it); externalReferences.append(tuple); } } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d5d11478..6c3863e6 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1144,10 +1144,10 @@ TypePointer RationalNumberType::binaryOperatorResult(Token _operator, TypePointe bigint denominator = optimizedPow(m_value.denominator(), absExp); if (exp >= 0) - value = rational(numerator, denominator); + value = makeRational(numerator, denominator); else // invert - value = rational(denominator, numerator); + value = makeRational(denominator, numerator); } break; } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index b764717f..24ace447 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -51,6 +51,15 @@ using FunctionTypePointer = std::shared_ptr<FunctionType const>; using TypePointers = std::vector<TypePointer>; using rational = boost::rational<dev::bigint>; +inline rational makeRational(bigint const& _numerator, bigint const& _denominator) +{ + solAssert(_denominator != 0, "division by zero"); + // due to a bug in certain versions of boost the denominator has to be positive + if (_denominator < 0) + return rational(-_numerator, -_denominator); + else + return rational(_numerator, _denominator); +} enum class DataLocation { Storage, CallData, Memory }; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 210b613d..6e14d68a 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -32,6 +32,7 @@ #include <libsolidity/inlineasm/AsmCodeGen.h> #include <libsolidity/inlineasm/AsmAnalysis.h> #include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/YulString.h> #include <boost/algorithm/string/replace.hpp> @@ -326,7 +327,7 @@ void CompilerContext::appendInlineAssembly( bool ) { - auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); + auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); return it == _localVariables.end() ? size_t(-1) : 1; }; identifierAccess.generateCode = [&]( @@ -335,7 +336,7 @@ void CompilerContext::appendInlineAssembly( yul::AbstractAssembly& _assembly ) { - auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); + auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); solAssert(it != _localVariables.end(), ""); int stackDepth = _localVariables.end() - it; int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index d89d023e..90eb74fe 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1016,8 +1016,22 @@ void CompilerUtils::convertType( } else { - // All other types should not be convertible to non-equal types. - solAssert(_typeOnStack == _targetType, "Invalid type conversion requested."); + if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function) + { + FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack); + FunctionType const& targetType = dynamic_cast<FunctionType const&>(_targetType); + solAssert( + typeOnStack.isImplicitlyConvertibleTo(targetType) && + typeOnStack.sizeOnStack() == targetType.sizeOnStack() && + (typeOnStack.kind() == FunctionType::Kind::Internal || typeOnStack.kind() == FunctionType::Kind::External) && + typeOnStack.kind() == targetType.kind(), + "Invalid function type conversion requested." + ); + } + else + // All other types should not be convertible to non-equal types. + solAssert(_typeOnStack == _targetType, "Invalid type conversion requested."); + if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32) m_context << ((u256(1) << (8 * _targetType.storageBytes())) - 1) diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 04b5d1a8..ac019c06 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -79,17 +79,17 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) bool AsmAnalyzer::operator()(assembly::Literal const& _literal) { - expectValidType(_literal.type, _literal.location); + expectValidType(_literal.type.str(), _literal.location); ++m_stackHeight; - if (_literal.kind == assembly::LiteralKind::String && _literal.value.size() > 32) + if (_literal.kind == assembly::LiteralKind::String && _literal.value.str().size() > 32) { m_errorReporter.typeError( _literal.location, - "String literal too long (" + to_string(_literal.value.size()) + " > 32)" + "String literal too long (" + to_string(_literal.value.str().size()) + " > 32)" ); return false; } - else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value) > u256(-1)) + else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value.str()) > u256(-1)) { m_errorReporter.typeError( _literal.location, @@ -100,7 +100,7 @@ bool AsmAnalyzer::operator()(assembly::Literal const& _literal) else if (_literal.kind == assembly::LiteralKind::Boolean) { solAssert(m_flavour == AsmFlavour::Yul, ""); - solAssert(_literal.value == "true" || _literal.value == "false", ""); + solAssert(_literal.value == YulString{string("true")} || _literal.value == YulString{string("false")}, ""); } m_info.stackHeightInfo[&_literal] = m_stackHeight; return true; @@ -118,7 +118,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier) { m_errorReporter.declarationError( _identifier.location, - "Variable " + _identifier.name + " used before it was declared." + "Variable " + _identifier.name.str() + " used before it was declared." ); success = false; } @@ -132,7 +132,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier) { m_errorReporter.typeError( _identifier.location, - "Function " + _identifier.name + " used without being called." + "Function " + _identifier.name.str() + " used without being called." ); success = false; } @@ -253,7 +253,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl) for (auto const& variable: _varDecl.variables) { - expectValidType(variable.type, variable.location); + expectValidType(variable.type.str(), variable.location); m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name))); } m_info.stackHeightInfo[&_varDecl] = m_stackHeight; @@ -268,7 +268,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef) Scope& varScope = scope(virtualBlock); for (auto const& var: _funDef.parameters + _funDef.returnVariables) { - expectValidType(var.type, var.location); + expectValidType(var.type.str(), var.location); m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name))); } @@ -361,7 +361,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch) if (!expectExpression(*_switch.expression)) success = false; - set<tuple<LiteralKind, string>> cases; + set<tuple<LiteralKind, YulString>> cases; for (auto const& _case: _switch.cases) { if (_case.value) @@ -503,7 +503,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t { m_errorReporter.declarationError( _variable.location, - "Variable " + _variable.name + " used before it was declared." + "Variable " + _variable.name.str() + " used before it was declared." ); success = false; } diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index 2982d5e0..a8d5e327 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -27,7 +27,13 @@ #include <libevmasm/Instruction.h> #include <libevmasm/SourceLocation.h> +#include <libyul/YulString.h> + #include <boost/variant.hpp> +#include <boost/noncopyable.hpp> + +#include <map> +#include <memory> namespace dev { @@ -36,20 +42,21 @@ namespace solidity namespace assembly { -using Type = std::string; +using YulString = dev::yul::YulString; +using Type = YulString; -struct TypedName { SourceLocation location; std::string name; Type type; }; +struct TypedName { SourceLocation location; YulString name; Type type; }; using TypedNameList = std::vector<TypedName>; /// Direct EVM instruction (except PUSHi and JUMPDEST) struct Instruction { SourceLocation location; solidity::Instruction instruction; }; /// Literal number or string (up to 32 bytes) enum class LiteralKind { Number, Boolean, String }; -struct Literal { SourceLocation location; LiteralKind kind; std::string value; Type type; }; +struct Literal { SourceLocation location; LiteralKind kind; YulString value; Type type; }; /// External / internal identifier or label reference -struct Identifier { SourceLocation location; std::string name; }; +struct Identifier { SourceLocation location; YulString name; }; /// Jump label ("name:") -struct Label { SourceLocation location; std::string name; }; +struct Label { SourceLocation location; YulString name; }; /// Assignment from stack (":= x", moves stack top into x, potentially multiple slots) struct StackAssignment { SourceLocation location; Identifier variableName; }; /// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand @@ -69,7 +76,7 @@ struct VariableDeclaration { SourceLocation location; TypedNameList variables; s /// Block that creates a scope (frees declared stack variables) struct Block { SourceLocation location; std::vector<Statement> statements; }; /// Function definition ("function f(a, b) -> (d, e) { ... }") -struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList parameters; TypedNameList returnVariables; Block body; }; +struct FunctionDefinition { SourceLocation location; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; }; /// Conditional execution without "else" part. struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; }; /// Switch case or default case diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 54cdc1c6..1f399edc 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -112,8 +112,8 @@ assembly::Statement Parser::parseStatement() advance(); expectToken(Token::Colon); assignment.variableName.location = location(); - assignment.variableName.name = currentLiteral(); - if (instructions().count(assignment.variableName.name)) + assignment.variableName.name = YulString(currentLiteral()); + if (instructions().count(assignment.variableName.name.str())) fatalParserError("Identifier expected, got instruction name."); assignment.location.end = endPosition(); expectToken(Token::Identifier); @@ -173,7 +173,7 @@ assembly::Statement Parser::parseStatement() if (currentToken() == Token::Assign && peekNextToken() != Token::Colon) { assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location); - if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name)) + if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name.str())) fatalParserError("Cannot use instruction names for identifier names."); advance(); assignment.variableNames.emplace_back(identifier); @@ -363,7 +363,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() ret = Instruction{location(), instr}; } else - ret = Identifier{location(), literal}; + ret = Identifier{location(), YulString{literal}}; advance(); break; } @@ -394,15 +394,15 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() Literal literal{ location(), kind, - currentLiteral(), - "" + YulString{currentLiteral()}, + {} }; advance(); if (m_flavour == AsmFlavour::Yul) { expectToken(Token::Colon); literal.location.end = endPosition(); - literal.type = expectAsmIdentifier(); + literal.type = YulString{expectAsmIdentifier()}; } else if (kind == LiteralKind::Boolean) fatalParserError("True and false are not valid literals."); @@ -449,7 +449,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() RecursionGuard recursionGuard(*this); FunctionDefinition funDef = createWithLocation<FunctionDefinition>(); expectToken(Token::Function); - funDef.name = expectAsmIdentifier(); + funDef.name = YulString{expectAsmIdentifier()}; expectToken(Token::LParen); while (currentToken() != Token::RParen) { @@ -564,12 +564,12 @@ TypedName Parser::parseTypedName() { RecursionGuard recursionGuard(*this); TypedName typedName = createWithLocation<TypedName>(); - typedName.name = expectAsmIdentifier(); + typedName.name = YulString{expectAsmIdentifier()}; if (m_flavour == AsmFlavour::Yul) { expectToken(Token::Colon); typedName.location.end = endPosition(); - typedName.type = expectAsmIdentifier(); + typedName.type = YulString{expectAsmIdentifier()}; } return typedName; } diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index 4b8c9538..ae0bd1eb 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -52,17 +52,17 @@ string AsmPrinter::operator()(assembly::Literal const& _literal) switch (_literal.kind) { case LiteralKind::Number: - solAssert(isValidDecimal(_literal.value) || isValidHex(_literal.value), "Invalid number literal"); - return _literal.value + appendTypeName(_literal.type); + solAssert(isValidDecimal(_literal.value.str()) || isValidHex(_literal.value.str()), "Invalid number literal"); + return _literal.value.str() + appendTypeName(_literal.type); case LiteralKind::Boolean: - solAssert(_literal.value == "true" || _literal.value == "false", "Invalid bool literal."); - return ((_literal.value == "true") ? "true" : "false") + appendTypeName(_literal.type); + solAssert(_literal.value.str() == "true" || _literal.value.str() == "false", "Invalid bool literal."); + return ((_literal.value.str() == "true") ? "true" : "false") + appendTypeName(_literal.type); case LiteralKind::String: break; } string out; - for (char c: _literal.value) + for (char c: _literal.value.str()) if (c == '\\') out += "\\\\"; else if (c == '"') @@ -93,7 +93,7 @@ string AsmPrinter::operator()(assembly::Literal const& _literal) string AsmPrinter::operator()(assembly::Identifier const& _identifier) { solAssert(!_identifier.name.empty(), "Invalid identifier."); - return _identifier.name; + return _identifier.name.str(); } string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction) @@ -118,7 +118,7 @@ string AsmPrinter::operator()(assembly::Label const& _label) { solAssert(!m_yul, ""); solAssert(!_label.name.empty(), "Invalid label."); - return _label.name + ":"; + return _label.name.str() + ":"; } string AsmPrinter::operator()(assembly::StackAssignment const& _assignment) @@ -157,7 +157,7 @@ string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDecl string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition) { solAssert(!_functionDefinition.name.empty(), "Invalid function name."); - string out = "function " + _functionDefinition.name + "("; + string out = "function " + _functionDefinition.name.str() + "("; out += boost::algorithm::join( _functionDefinition.parameters | boost::adaptors::transformed( [this](TypedName argument) { return formatTypedName(argument); } @@ -239,12 +239,12 @@ string AsmPrinter::operator()(Block const& _block) string AsmPrinter::formatTypedName(TypedName _variable) const { solAssert(!_variable.name.empty(), "Invalid variable name."); - return _variable.name + appendTypeName(_variable.type); + return _variable.name.str() + appendTypeName(_variable.type); } -string AsmPrinter::appendTypeName(std::string const& _type) const +string AsmPrinter::appendTypeName(YulString _type) const { if (m_yul) - return ":" + _type; + return ":" + _type.str(); return ""; } diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h index 971822bf..72048975 100644 --- a/libsolidity/inlineasm/AsmPrinter.h +++ b/libsolidity/inlineasm/AsmPrinter.h @@ -24,6 +24,8 @@ #include <libsolidity/inlineasm/AsmDataForward.h> +#include <libyul/YulString.h> + #include <boost/variant.hpp> namespace dev @@ -56,7 +58,7 @@ public: private: std::string formatTypedName(TypedName _variable) const; - std::string appendTypeName(std::string const& _type) const; + std::string appendTypeName(yul::YulString _type) const; bool m_yul = false; }; diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libsolidity/inlineasm/AsmScope.cpp index af81b301..019170ca 100644 --- a/libsolidity/inlineasm/AsmScope.cpp +++ b/libsolidity/inlineasm/AsmScope.cpp @@ -24,7 +24,7 @@ using namespace std; using namespace dev::solidity::assembly; -bool Scope::registerLabel(string const& _name) +bool Scope::registerLabel(yul::YulString _name) { if (exists(_name)) return false; @@ -32,7 +32,7 @@ bool Scope::registerLabel(string const& _name) return true; } -bool Scope::registerVariable(string const& _name, YulType const& _type) +bool Scope::registerVariable(yul::YulString _name, YulType const& _type) { if (exists(_name)) return false; @@ -42,7 +42,7 @@ bool Scope::registerVariable(string const& _name, YulType const& _type) return true; } -bool Scope::registerFunction(string const& _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns) +bool Scope::registerFunction(yul::YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns) { if (exists(_name)) return false; @@ -50,7 +50,7 @@ bool Scope::registerFunction(string const& _name, std::vector<YulType> const& _a return true; } -Scope::Identifier* Scope::lookup(string const& _name) +Scope::Identifier* Scope::lookup(yul::YulString _name) { bool crossedFunctionBoundary = false; for (Scope* s = this; s; s = s->superScope) @@ -70,7 +70,7 @@ Scope::Identifier* Scope::lookup(string const& _name) return nullptr; } -bool Scope::exists(string const& _name) const +bool Scope::exists(yul::YulString _name) const { if (identifiers.count(_name)) return true; diff --git a/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h index fc674e71..65848018 100644 --- a/libsolidity/inlineasm/AsmScope.h +++ b/libsolidity/inlineasm/AsmScope.h @@ -22,6 +22,8 @@ #include <libsolidity/interface/Exceptions.h> +#include <libyul/YulString.h> + #include <libdevcore/Visitor.h> #include <boost/variant.hpp> @@ -39,7 +41,7 @@ namespace assembly struct Scope { - using YulType = std::string; + using YulType = yul::YulString; using LabelID = size_t; struct Variable { YulType type; }; @@ -54,10 +56,10 @@ struct Scope using Visitor = GenericVisitor<Variable const, Label const, Function const>; using NonconstVisitor = GenericVisitor<Variable, Label, Function>; - bool registerVariable(std::string const& _name, YulType const& _type); - bool registerLabel(std::string const& _name); + bool registerVariable(yul::YulString _name, YulType const& _type); + bool registerLabel(yul::YulString _name); bool registerFunction( - std::string const& _name, + yul::YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns ); @@ -67,12 +69,12 @@ struct Scope /// will any lookups across assembly boundaries. /// The pointer will be invalidated if the scope is modified. /// @param _crossedFunction if true, we already crossed a function boundary during recursive lookup - Identifier* lookup(std::string const& _name); + Identifier* lookup(yul::YulString _name); /// Looks up the identifier in this and super scopes (will not find variables across function /// boundaries and generally stops at assembly boundaries) and calls the visitor, returns /// false if not found. template <class V> - bool lookup(std::string const& _name, V const& _visitor) + bool lookup(yul::YulString _name, V const& _visitor) { if (Identifier* id = lookup(_name)) { @@ -84,7 +86,7 @@ struct Scope } /// @returns true if the name exists in this scope or in super scopes (also searches /// across function and assembly boundaries). - bool exists(std::string const& _name) const; + bool exists(yul::YulString _name) const; /// @returns the number of variables directly registered inside the scope. size_t numberOfVariables() const; @@ -95,7 +97,7 @@ struct Scope /// If true, variables from the super scope are not visible here (other identifiers are), /// but they are still taken into account to prevent shadowing. bool functionScope = false; - std::map<std::string, Identifier> identifiers; + std::map<yul::YulString, Identifier> identifiers; }; } diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp index 2d15c820..d1f98083 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libsolidity/inlineasm/AsmScopeFiller.cpp @@ -57,7 +57,7 @@ bool ScopeFiller::operator()(Label const& _item) //@TODO secondary location m_errorReporter.declarationError( _item.location, - "Label name " + _item.name + " already taken in this scope." + "Label name " + _item.name.str() + " already taken in this scope." ); return false; } @@ -77,16 +77,16 @@ bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef) bool success = true; vector<Scope::YulType> arguments; for (auto const& _argument: _funDef.parameters) - arguments.push_back(_argument.type); + arguments.emplace_back(_argument.type.str()); vector<Scope::YulType> returns; for (auto const& _return: _funDef.returnVariables) - returns.push_back(_return.type); + returns.emplace_back(_return.type.str()); if (!m_currentScope->registerFunction(_funDef.name, arguments, returns)) { //@TODO secondary location m_errorReporter.declarationError( _funDef.location, - "Function name " + _funDef.name + " already taken in this scope." + "Function name " + _funDef.name.str() + " already taken in this scope." ); success = false; } @@ -164,7 +164,7 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& //@TODO secondary location m_errorReporter.declarationError( _location, - "Variable name " + _name.name + " already taken in this scope." + "Variable name " + _name.name.str() + " already taken in this scope." ); return false; } diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp index a35bfd29..b5f68ce8 100644 --- a/libsolidity/interface/Version.cpp +++ b/libsolidity/interface/Version.cpp @@ -55,13 +55,13 @@ bytes dev::solidity::binaryVersion() ret = ret * 10 + (VersionString[i] - '0'); return ret; }; - ret.push_back(byte(parseDecimal())); + ret.push_back(uint8_t(parseDecimal())); solAssert(i < VersionString.size() && VersionString[i] == '.', ""); ++i; - ret.push_back(byte(parseDecimal())); + ret.push_back(uint8_t(parseDecimal())); solAssert(i < VersionString.size() && VersionString[i] == '.', ""); ++i; - ret.push_back(byte(parseDecimal())); + ret.push_back(uint8_t(parseDecimal())); solAssert(i < VersionString.size() && (VersionString[i] == '-' || VersionString[i] == '+'), ""); ++i; size_t commitpos = VersionString.find("commit."); diff --git a/libyul/ASTDataForward.h b/libyul/ASTDataForward.h index 7f131b5e..8c49e68f 100644 --- a/libyul/ASTDataForward.h +++ b/libyul/ASTDataForward.h @@ -46,6 +46,7 @@ using ExpressionStatement = solidity::assembly::ExpressionStatement; using Block = solidity::assembly::Block; using TypedName = solidity::assembly::TypedName; +class YulString; using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>; using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; diff --git a/libyul/YulString.h b/libyul/YulString.h new file mode 100644 index 00000000..ae01c83f --- /dev/null +++ b/libyul/YulString.h @@ -0,0 +1,96 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * String abstraction that avoids copies. + */ + +#pragma once + +#include <boost/noncopyable.hpp> + +#include <map> +#include <memory> +#include <vector> +#include <string> + +namespace dev +{ +namespace yul +{ + +class YulStringRepository: boost::noncopyable +{ +public: + YulStringRepository(): m_strings{std::make_shared<std::string>()} + { + m_ids[std::string{}] = 0; + } + static YulStringRepository& instance() + { + static YulStringRepository inst; + return inst; + } + size_t stringToId(std::string const& _string) + { + if (_string.empty()) + return 0; + size_t& id = m_ids[_string]; + if (id == 0) + { + m_strings.emplace_back(std::make_shared<std::string>(_string)); + id = m_strings.size() - 1; + } + return id; + } + std::string const& idToString(size_t _id) const + { + return *m_strings.at(_id); + } + +private: + std::vector<std::shared_ptr<std::string>> m_strings; + std::map<std::string, size_t> m_ids; +}; + +class YulString +{ +public: + YulString() = default; + explicit YulString(std::string const& _s): m_id(YulStringRepository::instance().stringToId(_s)) {} + YulString(YulString const&) = default; + YulString(YulString&&) = default; + YulString& operator=(YulString const&) = default; + YulString& operator=(YulString&&) = default; + + /// This is not consistent with the string <-operator! + bool operator<(YulString const& _other) const { return m_id < _other.m_id; } + bool operator==(YulString const& _other) const { return m_id == _other.m_id; } + bool operator!=(YulString const& _other) const { return m_id != _other.m_id; } + + bool empty() const { return m_id == 0; } + std::string const& str() const + { + return YulStringRepository::instance().idToString(m_id); + } + +private: + /// ID of the string. Assumes that the empty string has ID zero. + size_t m_id = 0; +}; + +} +} diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index b2f0878f..b37a3231 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -44,7 +44,7 @@ void EVMAssembly::setSourceLocation(SourceLocation const&) void EVMAssembly::appendInstruction(solidity::Instruction _instr) { - m_bytecode.push_back(byte(_instr)); + m_bytecode.push_back(uint8_t(_instr)); m_stackHeight += solidity::instructionInfo(_instr).ret - solidity::instructionInfo(_instr).args; } @@ -101,7 +101,7 @@ void EVMAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter) { if (m_evm15) { - m_bytecode.push_back(byte(solidity::Instruction::JUMPTO)); + m_bytecode.push_back(uint8_t(solidity::Instruction::JUMPTO)); appendLabelReferenceInternal(_labelId); m_stackHeight += _stackDiffAfter; } @@ -116,7 +116,7 @@ void EVMAssembly::appendJumpToIf(LabelID _labelId) { if (m_evm15) { - m_bytecode.push_back(byte(solidity::Instruction::JUMPIF)); + m_bytecode.push_back(uint8_t(solidity::Instruction::JUMPIF)); appendLabelReferenceInternal(_labelId); m_stackHeight--; } @@ -132,7 +132,7 @@ void EVMAssembly::appendBeginsub(LabelID _labelId, int _arguments) solAssert(m_evm15, "BEGINSUB used for EVM 1.0"); solAssert(_arguments >= 0, ""); setLabelToCurrentPosition(_labelId); - m_bytecode.push_back(byte(solidity::Instruction::BEGINSUB)); + m_bytecode.push_back(uint8_t(solidity::Instruction::BEGINSUB)); m_stackHeight += _arguments; } @@ -140,7 +140,7 @@ void EVMAssembly::appendJumpsub(LabelID _labelId, int _arguments, int _returns) { solAssert(m_evm15, "JUMPSUB used for EVM 1.0"); solAssert(_arguments >= 0 && _returns >= 0, ""); - m_bytecode.push_back(byte(solidity::Instruction::JUMPSUB)); + m_bytecode.push_back(uint8_t(solidity::Instruction::JUMPSUB)); appendLabelReferenceInternal(_labelId); m_stackHeight += _returns - _arguments; } @@ -149,7 +149,7 @@ void EVMAssembly::appendReturnsub(int _returns, int _stackDiffAfter) { solAssert(m_evm15, "RETURNSUB used for EVM 1.0"); solAssert(_returns >= 0, ""); - m_bytecode.push_back(byte(solidity::Instruction::RETURNSUB)); + m_bytecode.push_back(uint8_t(solidity::Instruction::RETURNSUB)); m_stackHeight += _stackDiffAfter - _returns; } @@ -198,5 +198,5 @@ void EVMAssembly::updateReference(size_t pos, size_t size, u256 value) solAssert(m_bytecode.size() >= size && pos <= m_bytecode.size() - size, ""); solAssert(value < (u256(1) << (8 * size)), ""); for (size_t i = 0; i < size; i++) - m_bytecode[pos + i] = byte((value >> (8 * (size - i - 1))) & 0xff); + m_bytecode[pos + i] = uint8_t((value >> (8 * (size - i - 1))) & 0xff); } diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 89086b4e..650a8c0a 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -201,18 +201,18 @@ void CodeTransform::operator()(assembly::Literal const& _literal) { m_assembly.setSourceLocation(_literal.location); if (_literal.kind == assembly::LiteralKind::Number) - m_assembly.appendConstant(u256(_literal.value)); + m_assembly.appendConstant(u256(_literal.value.str())); else if (_literal.kind == assembly::LiteralKind::Boolean) { - if (_literal.value == "true") + if (_literal.value.str() == "true") m_assembly.appendConstant(u256(1)); else m_assembly.appendConstant(u256(0)); } else { - solAssert(_literal.value.size() <= 32, ""); - m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); + solAssert(_literal.value.str().size() <= 32, ""); + m_assembly.appendConstant(u256(h256(_literal.value.str(), h256::FromBinary, h256::AlignLeft))); } checkStackHeight(&_literal); } @@ -454,13 +454,13 @@ AbstractAssembly::LabelID CodeTransform::labelID(Scope::Label const& _label) return m_context->labelIDs[&_label]; } -AbstractAssembly::LabelID CodeTransform::functionEntryID(string const& _name, Scope::Function const& _function) +AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope::Function const& _function) { if (!m_context->functionEntryIDs.count(&_function)) { AbstractAssembly::LabelID id = m_useNamedLabelsForFunctions ? - m_assembly.namedLabel(_name) : + m_assembly.namedLabel(_name.str()) : m_assembly.newLabelId(); m_context->functionEntryIDs[&_function] = id; } diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 22ebbf43..c0de8ad6 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -117,7 +117,7 @@ private: /// @returns the label ID corresponding to the given label, allocating a new one if /// necessary. AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label); - AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function); + AbstractAssembly::LabelID functionEntryID(YulString _name, solidity::assembly::Scope::Function const& _function); /// Generates code for an expression that is supposed to return a single value. void visitExpression(Expression const& _expression); diff --git a/libyul/optimiser/ASTCopier.cpp b/libyul/optimiser/ASTCopier.cpp index 4b7f21f8..d0c8dd45 100644 --- a/libyul/optimiser/ASTCopier.cpp +++ b/libyul/optimiser/ASTCopier.cpp @@ -111,14 +111,14 @@ Statement ASTCopier::operator()(Switch const& _switch) Statement ASTCopier::operator()(FunctionDefinition const& _function) { - string translatedName = translateIdentifier(_function.name); + YulString translatedName = translateIdentifier(_function.name); enterFunction(_function); ScopeGuard g([&]() { this->leaveFunction(_function); }); return FunctionDefinition{ _function.location, - move(translatedName), + translatedName, translateVector(_function.parameters), translateVector(_function.returnVariables), translate(_function.body) diff --git a/libyul/optimiser/ASTCopier.h b/libyul/optimiser/ASTCopier.h index 13369cef..b6aceee3 100644 --- a/libyul/optimiser/ASTCopier.h +++ b/libyul/optimiser/ASTCopier.h @@ -22,6 +22,8 @@ #include <libyul/ASTDataForward.h> +#include <libyul/YulString.h> + #include <boost/variant.hpp> #include <boost/optional.hpp> @@ -107,7 +109,7 @@ protected: virtual void leaveScope(Block const&) { } virtual void enterFunction(FunctionDefinition const&) { } virtual void leaveFunction(FunctionDefinition const&) { } - virtual std::string translateIdentifier(std::string const& _name) { return _name; } + virtual YulString translateIdentifier(YulString _name) { return _name; } }; template <typename T> diff --git a/libyul/optimiser/ASTWalker.h b/libyul/optimiser/ASTWalker.h index 41617d55..38cb85ea 100644 --- a/libyul/optimiser/ASTWalker.h +++ b/libyul/optimiser/ASTWalker.h @@ -23,6 +23,7 @@ #include <libyul/ASTDataForward.h> #include <libyul/Exceptions.h> +#include <libyul/YulString.h> #include <boost/variant.hpp> #include <boost/optional.hpp> diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index 51737097..64605362 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -43,13 +43,13 @@ void CommonSubexpressionEliminator::visit(Expression& _e) if (_e.type() == typeid(Identifier)) { Identifier& identifier = boost::get<Identifier>(_e); - string const& name = identifier.name; + YulString name = identifier.name; if (m_value.count(name)) { assertThrow(m_value.at(name), OptimizerException, ""); if (m_value.at(name)->type() == typeid(Identifier)) { - string const& value = boost::get<Identifier>(*m_value.at(name)).name; + YulString value = boost::get<Identifier>(*m_value.at(name)).name; assertThrow(inScope(value), OptimizerException, ""); _e = Identifier{locationOf(_e), value}; } diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 7ac42c30..1ff1d2f0 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -38,9 +38,9 @@ using namespace dev::yul; void DataFlowAnalyzer::operator()(Assignment& _assignment) { - set<string> names; + set<YulString> names; for (auto const& var: _assignment.variableNames) - names.insert(var.name); + names.emplace(var.name); assertThrow(_assignment.value, OptimizerException, ""); visit(*_assignment.value); handleAssignment(names, _assignment.value.get()); @@ -48,9 +48,9 @@ void DataFlowAnalyzer::operator()(Assignment& _assignment) void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl) { - set<string> names; + set<YulString> names; for (auto const& var: _varDecl.variables) - names.insert(var.name); + names.emplace(var.name); m_variableScopes.back().variables += names; if (_varDecl.value) visit(*_varDecl.value); @@ -69,7 +69,7 @@ void DataFlowAnalyzer::operator()(If& _if) void DataFlowAnalyzer::operator()(Switch& _switch) { visit(*_switch.expression); - set<string> assignedVariables; + set<YulString> assignedVariables; for (auto& _case: _switch.cases) { (*this)(_case.body); @@ -86,9 +86,9 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun) { pushScope(true); for (auto const& parameter: _fun.parameters) - m_variableScopes.back().variables.insert(parameter.name); + m_variableScopes.back().variables.emplace(parameter.name); for (auto const& var: _fun.returnVariables) - m_variableScopes.back().variables.insert(var.name); + m_variableScopes.back().variables.emplace(var.name); ASTModifier::operator()(_fun); popScope(); } @@ -122,7 +122,7 @@ void DataFlowAnalyzer::operator()(Block& _block) assertThrow(numScopes == m_variableScopes.size(), OptimizerException, ""); } -void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expression* _value) +void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value) { clearValues(_variables); @@ -131,7 +131,7 @@ void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expressio movableChecker.visit(*_value); if (_variables.size() == 1) { - string const& name = *_variables.begin(); + YulString name = *_variables.begin(); // Expression has to be movable and cannot contain a reference // to the variable that will be assigned to. if (_value && movableChecker.movable() && !movableChecker.referencedVariables().count(name)) @@ -143,7 +143,7 @@ void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expressio { m_references[name] = referencedVariables; for (auto const& ref: referencedVariables) - m_referencedBy[ref].insert(name); + m_referencedBy[ref].emplace(name); } } @@ -158,7 +158,7 @@ void DataFlowAnalyzer::popScope() m_variableScopes.pop_back(); } -void DataFlowAnalyzer::clearValues(set<string> _variables) +void DataFlowAnalyzer::clearValues(set<YulString> _variables) { // All variables that reference variables to be cleared also have to be // cleared, but not recursively, since only the value of the original @@ -176,7 +176,7 @@ void DataFlowAnalyzer::clearValues(set<string> _variables) // Clear variables that reference variables to be cleared. for (auto const& name: _variables) for (auto const& ref: m_referencedBy[name]) - _variables.insert(ref); + _variables.emplace(ref); // Clear the value and update the reference relation. for (auto const& name: _variables) @@ -189,7 +189,7 @@ void DataFlowAnalyzer::clearValues(set<string> _variables) } } -bool DataFlowAnalyzer::inScope(string const& _variableName) const +bool DataFlowAnalyzer::inScope(YulString _variableName) const { for (auto const& scope: m_variableScopes | boost::adaptors::reversed) { diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index 95671467..a0c21eee 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -24,7 +24,8 @@ #include <libyul/optimiser/ASTWalker.h> -#include <string> +#include <libyul/YulString.h> + #include <map> #include <set> @@ -54,7 +55,7 @@ public: protected: /// Registers the assignment. - void handleAssignment(std::set<std::string> const& _names, Expression* _value); + void handleAssignment(std::set<YulString> const& _names, Expression* _value); /// Creates a new inner scope. void pushScope(bool _functionScope); @@ -64,22 +65,22 @@ protected: /// Clears information about the values assigned to the given variables, /// for example at points where control flow is merged. - void clearValues(std::set<std::string> _names); + void clearValues(std::set<YulString> _names); /// Returns true iff the variable is in scope. - bool inScope(std::string const& _variableName) const; + bool inScope(YulString _variableName) const; /// Current values of variables, always movable. - std::map<std::string, Expression const*> m_value; + std::map<YulString, Expression const*> m_value; /// m_references[a].contains(b) <=> the current expression assigned to a references b - std::map<std::string, std::set<std::string>> m_references; + std::map<YulString, std::set<YulString>> m_references; /// m_referencedBy[b].contains(a) <=> the current expression assigned to a references b - std::map<std::string, std::set<std::string>> m_referencedBy; + std::map<YulString, std::set<YulString>> m_referencedBy; struct Scope { explicit Scope(bool _isFunction): isFunction(_isFunction) {} - std::set<std::string> variables; + std::set<YulString> variables; bool isFunction; }; /// List of scopes. diff --git a/libyul/optimiser/Disambiguator.cpp b/libyul/optimiser/Disambiguator.cpp index dcba97c9..4303f412 100644 --- a/libyul/optimiser/Disambiguator.cpp +++ b/libyul/optimiser/Disambiguator.cpp @@ -32,7 +32,7 @@ using namespace dev::solidity; using Scope = dev::solidity::assembly::Scope; -string Disambiguator::translateIdentifier(string const& _originalName) +YulString Disambiguator::translateIdentifier(YulString _originalName) { if ((m_externallyUsedIdentifiers.count(_originalName))) return _originalName; diff --git a/libyul/optimiser/Disambiguator.h b/libyul/optimiser/Disambiguator.h index 74a491ab..bfb65682 100644 --- a/libyul/optimiser/Disambiguator.h +++ b/libyul/optimiser/Disambiguator.h @@ -45,7 +45,7 @@ class Disambiguator: public ASTCopier public: explicit Disambiguator( solidity::assembly::AsmAnalysisInfo const& _analysisInfo, - std::set<std::string> const& _externallyUsedIdentifiers = {} + std::set<YulString> const& _externallyUsedIdentifiers = {} ): m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers), m_nameDispenser(m_externallyUsedIdentifiers) { @@ -56,16 +56,16 @@ protected: virtual void leaveScope(Block const& _block) override; virtual void enterFunction(FunctionDefinition const& _function) override; virtual void leaveFunction(FunctionDefinition const& _function) override; - virtual std::string translateIdentifier(std::string const& _name) override; + virtual YulString translateIdentifier(YulString _name) override; void enterScopeInternal(solidity::assembly::Scope& _scope); void leaveScopeInternal(solidity::assembly::Scope& _scope); solidity::assembly::AsmAnalysisInfo const& m_info; - std::set<std::string> const& m_externallyUsedIdentifiers; + std::set<YulString> const& m_externallyUsedIdentifiers; std::vector<solidity::assembly::Scope*> m_scopes; - std::map<void const*, std::string> m_translations; + std::map<void const*, YulString> m_translations; NameDispenser m_nameDispenser; }; diff --git a/libyul/optimiser/ExpressionInliner.cpp b/libyul/optimiser/ExpressionInliner.cpp index 9bf0a3fb..07e88191 100644 --- a/libyul/optimiser/ExpressionInliner.cpp +++ b/libyul/optimiser/ExpressionInliner.cpp @@ -62,7 +62,7 @@ void ExpressionInliner::visit(Expression& _expression) if (m_inlinableFunctions.count(funCall.functionName.name) && movable) { FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name); - map<string, Expression const*> substitutions; + map<YulString, Expression const*> substitutions; for (size_t i = 0; i < fun.parameters.size(); ++i) substitutions[fun.parameters[i].name] = &funCall.arguments[i]; _expression = Substitution(substitutions).translate(*boost::get<Assignment>(fun.body.statements.front()).value); diff --git a/libyul/optimiser/ExpressionInliner.h b/libyul/optimiser/ExpressionInliner.h index 971a2ee0..d903664f 100644 --- a/libyul/optimiser/ExpressionInliner.h +++ b/libyul/optimiser/ExpressionInliner.h @@ -59,10 +59,10 @@ public: virtual void visit(Expression& _expression) override; private: - std::map<std::string, FunctionDefinition const*> m_inlinableFunctions; - std::map<std::string, std::string> m_varReplacements; + std::map<YulString, FunctionDefinition const*> m_inlinableFunctions; + std::map<YulString, YulString> m_varReplacements; /// Set of functions we are currently visiting inside. - std::set<std::string> m_currentFunctions; + std::set<YulString> m_currentFunctions; Block& m_block; }; diff --git a/libyul/optimiser/ExpressionJoiner.h b/libyul/optimiser/ExpressionJoiner.h index 4f06cc0f..0cc61981 100644 --- a/libyul/optimiser/ExpressionJoiner.h +++ b/libyul/optimiser/ExpressionJoiner.h @@ -93,9 +93,9 @@ private: bool isLatestStatementVarDeclJoinable(Identifier const& _identifier); private: - Block* m_currentBlock = nullptr; ///< Pointer to currently block holding the visiting statement. - size_t m_latestStatementInBlock = 0; ///< Offset to m_currentBlock's statements of the last visited statement. - std::map<std::string, size_t> m_references; ///< Holds reference counts to all variable declarations in current block. + Block* m_currentBlock = nullptr; ///< Pointer to current block holding the statement being visited. + size_t m_latestStatementInBlock = 0; ///< Offset to m_currentBlock's statements of the last visited statement. + std::map<YulString, size_t> m_references; ///< Holds reference counts to all variable declarations in current block. }; } diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h index 5419ff6a..5965a1bb 100644 --- a/libyul/optimiser/ExpressionSimplifier.h +++ b/libyul/optimiser/ExpressionSimplifier.h @@ -44,11 +44,11 @@ public: static void run(Block& _ast); private: - explicit ExpressionSimplifier(std::map<std::string, Expression const*> _ssaValues): + explicit ExpressionSimplifier(std::map<YulString, Expression const*> _ssaValues): m_ssaValues(std::move(_ssaValues)) {} - std::map<std::string, Expression const*> m_ssaValues; + std::map<YulString, Expression const*> m_ssaValues; }; } diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp index a2ecc546..a4b7a909 100644 --- a/libyul/optimiser/ExpressionSplitter.cpp +++ b/libyul/optimiser/ExpressionSplitter.cpp @@ -95,10 +95,10 @@ void ExpressionSplitter::outlineExpression(Expression& _expr) visit(_expr); SourceLocation location = locationOf(_expr); - string var = m_nameDispenser.newName(""); + YulString var = m_nameDispenser.newName({}); m_statementsToPrefix.emplace_back(VariableDeclaration{ location, - {{TypedName{location, var, ""}}}, + {{TypedName{location, var, {}}}}, make_shared<Expression>(std::move(_expr)) }); _expr = Identifier{location, var}; diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 280d625a..c9057cf3 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -48,9 +48,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): tracker(m_ast); for (auto const& ssaValue: tracker.values()) if (ssaValue.second && ssaValue.second->type() == typeid(Literal)) - m_constants.insert(ssaValue.first); + m_constants.emplace(ssaValue.first); - map<string, size_t> references = ReferencesCounter::countReferences(m_ast); + map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast); for (auto& statement: m_ast.statements) { if (statement.type() != typeid(FunctionDefinition)) @@ -59,7 +59,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): m_functions[fun.name] = &fun; // Always inline functions that are only called once. if (references[fun.name] == 1) - m_alwaysInline.insert(fun.name); + m_alwaysInline.emplace(fun.name); updateCodeSize(fun); } } @@ -68,7 +68,7 @@ void FullInliner::run() { for (auto& statement: m_ast.statements) if (statement.type() == typeid(Block)) - handleBlock("", boost::get<Block>(statement)); + handleBlock({}, boost::get<Block>(statement)); // TODO it might be good to determine a visiting order: // first handle functions that are called from many places. @@ -84,12 +84,12 @@ void FullInliner::updateCodeSize(FunctionDefinition& fun) m_functionSizes[fun.name] = CodeSize::codeSize(fun.body); } -void FullInliner::handleBlock(string const& _currentFunctionName, Block& _block) +void FullInliner::handleBlock(YulString _currentFunctionName, Block& _block) { InlineModifier{*this, m_nameDispenser, _currentFunctionName}(_block); } -bool FullInliner::shallInline(FunctionCall const& _funCall, string const& _callSite) +bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) { // No recursive inlining if (_funCall.functionName.name == _callSite) @@ -148,14 +148,14 @@ boost::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall) { vector<Statement> newStatements; - map<string, string> variableReplacements; + map<YulString, YulString> variableReplacements; FunctionDefinition& function = m_driver.function(_funCall.functionName.name); // helper function to create a new variable that is supposed to model // an existing variable. auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) { - string newName = m_nameDispenser.newName(_existingVariable.name, function.name); + YulString newName = m_nameDispenser.newName(_existingVariable.name, function.name); variableReplacements[_existingVariable.name] = newName; VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}}; if (_value) @@ -214,7 +214,7 @@ Statement BodyCopier::operator()(FunctionDefinition const& _funDef) return _funDef; } -string BodyCopier::translateIdentifier(string const& _name) +YulString BodyCopier::translateIdentifier(YulString _name) { if (m_variableReplacements.count(_name)) return m_variableReplacements.at(_name); diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 5ecfb57a..66ce8e2f 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -77,23 +77,23 @@ public: /// Inlining heuristic. /// @param _callSite the name of the function in which the function call is located. - bool shallInline(FunctionCall const& _funCall, std::string const& _callSite); + bool shallInline(FunctionCall const& _funCall, YulString _callSite); - FunctionDefinition& function(std::string _name) { return *m_functions.at(_name); } + FunctionDefinition& function(YulString _name) { return *m_functions.at(_name); } private: void updateCodeSize(FunctionDefinition& fun); - void handleBlock(std::string const& _currentFunctionName, Block& _block); + void handleBlock(YulString _currentFunctionName, Block& _block); /// The AST to be modified. The root block itself will not be modified, because /// we store pointers to functions. Block& m_ast; - std::map<std::string, FunctionDefinition*> m_functions; + std::map<YulString, FunctionDefinition*> m_functions; /// Names of functions to always inline. - std::set<std::string> m_alwaysInline; + std::set<YulString> m_alwaysInline; /// Variables that are constants (used for inlining heuristic) - std::set<std::string> m_constants; - std::map<std::string, size_t> m_functionSizes; + std::set<YulString> m_constants; + std::map<YulString, size_t> m_functionSizes; NameDispenser& m_nameDispenser; }; @@ -104,7 +104,7 @@ private: class InlineModifier: public ASTModifier { public: - InlineModifier(FullInliner& _driver, NameDispenser& _nameDispenser, std::string _functionName): + InlineModifier(FullInliner& _driver, NameDispenser& _nameDispenser, YulString _functionName): m_currentFunction(std::move(_functionName)), m_driver(_driver), m_nameDispenser(_nameDispenser) @@ -116,7 +116,7 @@ private: boost::optional<std::vector<Statement>> tryInlineStatement(Statement& _statement); std::vector<Statement> performInline(Statement& _statement, FunctionCall& _funCall); - std::string m_currentFunction; + YulString m_currentFunction; FullInliner& m_driver; NameDispenser& m_nameDispenser; }; @@ -131,8 +131,8 @@ class BodyCopier: public ASTCopier public: BodyCopier( NameDispenser& _nameDispenser, - std::string const& _varNamePrefix, - std::map<std::string, std::string> const& _variableReplacements + YulString _varNamePrefix, + std::map<YulString, YulString> const& _variableReplacements ): m_nameDispenser(_nameDispenser), m_varNamePrefix(_varNamePrefix), @@ -144,11 +144,11 @@ public: virtual Statement operator()(VariableDeclaration const& _varDecl) override; virtual Statement operator()(FunctionDefinition const& _funDef) override; - virtual std::string translateIdentifier(std::string const& _name) override; + virtual YulString translateIdentifier(YulString _name) override; NameDispenser& m_nameDispenser; - std::string const& m_varNamePrefix; - std::map<std::string, std::string> m_variableReplacements; + YulString m_varNamePrefix; + std::map<YulString, YulString> m_variableReplacements; }; diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp index 69dd2095..deaaee97 100644 --- a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp +++ b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp @@ -44,7 +44,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu { if (_function.returnVariables.size() == 1 && _function.body.statements.size() == 1) { - string const& retVariable = _function.returnVariables.front().name; + YulString retVariable = _function.returnVariables.front().name; Statement const& bodyStatement = _function.body.statements.front(); if (bodyStatement.type() == typeid(Assignment)) { @@ -57,7 +57,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu // would not be valid here if we were searching inside a functionally inlinable // function body. assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, ""); - m_disallowedIdentifiers = set<string>{retVariable, _function.name}; + m_disallowedIdentifiers = set<YulString>{retVariable, _function.name}; boost::apply_visitor(*this, *assignment.value); if (!m_foundDisallowedIdentifier) m_inlinableFunctions[_function.name] = &_function; diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.h b/libyul/optimiser/InlinableExpressionFunctionFinder.h index 3887e6e5..baf4bbfc 100644 --- a/libyul/optimiser/InlinableExpressionFunctionFinder.h +++ b/libyul/optimiser/InlinableExpressionFunctionFinder.h @@ -43,7 +43,7 @@ class InlinableExpressionFunctionFinder: public ASTWalker { public: - std::map<std::string, FunctionDefinition const*> const& inlinableFunctions() const + std::map<YulString, FunctionDefinition const*> const& inlinableFunctions() const { return m_inlinableFunctions; } @@ -54,15 +54,15 @@ public: virtual void operator()(FunctionDefinition const& _function) override; private: - void checkAllowed(std::string const& _name) + void checkAllowed(YulString _name) { if (m_disallowedIdentifiers.count(_name)) m_foundDisallowedIdentifier = true; } bool m_foundDisallowedIdentifier = false; - std::set<std::string> m_disallowedIdentifiers; - std::map<std::string, FunctionDefinition const*> m_inlinableFunctions; + std::set<YulString> m_disallowedIdentifiers; + std::map<YulString, FunctionDefinition const*> m_inlinableFunctions; }; } diff --git a/libyul/optimiser/MainFunction.cpp b/libyul/optimiser/MainFunction.cpp index c8f35207..f3306598 100644 --- a/libyul/optimiser/MainFunction.cpp +++ b/libyul/optimiser/MainFunction.cpp @@ -40,12 +40,12 @@ void MainFunction::operator()(Block& _block) for (size_t i = 1; i < _block.statements.size(); ++i) assertThrow(_block.statements.at(i).type() == typeid(FunctionDefinition), OptimizerException, ""); /// @todo this should handle scopes properly and instead of an assertion it should rename the conflicting function - assertThrow(NameCollector(_block).names().count("main") == 0, OptimizerException, ""); + assertThrow(NameCollector(_block).names().count(YulString{"main"}) == 0, OptimizerException, ""); Block& block = boost::get<Block>(_block.statements[0]); FunctionDefinition main{ block.location, - "main", + YulString{"main"}, {}, {}, std::move(block) diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp index b71fa982..36f55b99 100644 --- a/libyul/optimiser/NameCollector.cpp +++ b/libyul/optimiser/NameCollector.cpp @@ -29,16 +29,16 @@ using namespace dev::yul; void NameCollector::operator()(VariableDeclaration const& _varDecl) { for (auto const& var: _varDecl.variables) - m_names.insert(var.name); + m_names.emplace(var.name); } void NameCollector::operator ()(FunctionDefinition const& _funDef) { - m_names.insert(_funDef.name); + m_names.emplace(_funDef.name); for (auto const arg: _funDef.parameters) - m_names.insert(arg.name); + m_names.emplace(arg.name); for (auto const ret: _funDef.returnVariables) - m_names.insert(ret.name); + m_names.emplace(ret.name); ASTWalker::operator ()(_funDef); } @@ -53,14 +53,14 @@ void ReferencesCounter::operator()(FunctionCall const& _funCall) ASTWalker::operator()(_funCall); } -map<string, size_t> ReferencesCounter::countReferences(Block const& _block) +map<YulString, size_t> ReferencesCounter::countReferences(Block const& _block) { ReferencesCounter counter; counter(_block); return counter.references(); } -map<string, size_t> ReferencesCounter::countReferences(Expression const& _expression) +map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _expression) { ReferencesCounter counter; counter.visit(_expression); @@ -70,5 +70,5 @@ map<string, size_t> ReferencesCounter::countReferences(Expression const& _expres void Assignments::operator()(Assignment const& _assignment) { for (auto const& var: _assignment.variableNames) - m_names.insert(var.name); + m_names.emplace(var.name); } diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h index b8f6c1d7..b76eec30 100644 --- a/libyul/optimiser/NameCollector.h +++ b/libyul/optimiser/NameCollector.h @@ -22,7 +22,6 @@ #include <libyul/optimiser/ASTWalker.h> -#include <string> #include <map> #include <set> @@ -46,9 +45,9 @@ public: virtual void operator()(VariableDeclaration const& _varDecl) override; virtual void operator()(FunctionDefinition const& _funDef) override; - std::set<std::string> names() const { return m_names; } + std::set<YulString> names() const { return m_names; } private: - std::set<std::string> m_names; + std::set<YulString> m_names; }; /** @@ -61,12 +60,12 @@ public: virtual void operator()(Identifier const& _identifier); virtual void operator()(FunctionCall const& _funCall); - static std::map<std::string, size_t> countReferences(Block const& _block); - static std::map<std::string, size_t> countReferences(Expression const& _expression); + static std::map<YulString, size_t> countReferences(Block const& _block); + static std::map<YulString, size_t> countReferences(Expression const& _expression); - std::map<std::string, size_t> const& references() const { return m_references; } + std::map<YulString, size_t> const& references() const { return m_references; } private: - std::map<std::string, size_t> m_references; + std::map<YulString, size_t> m_references; }; /** @@ -78,9 +77,9 @@ public: using ASTWalker::operator (); virtual void operator()(Assignment const& _assignment) override; - std::set<std::string> const& names() const { return m_names; } + std::set<YulString> const& names() const { return m_names; } private: - std::set<std::string> m_names; + std::set<YulString> m_names; }; } diff --git a/libyul/optimiser/NameDispenser.cpp b/libyul/optimiser/NameDispenser.cpp index d3f10bc2..492c863d 100644 --- a/libyul/optimiser/NameDispenser.cpp +++ b/libyul/optimiser/NameDispenser.cpp @@ -33,31 +33,31 @@ NameDispenser::NameDispenser(Block const& _ast): { } -NameDispenser::NameDispenser(set<string> _usedNames): +NameDispenser::NameDispenser(set<YulString> _usedNames): m_usedNames(std::move(_usedNames)) { } -string NameDispenser::newName(string const& _nameHint, string const& _context) +YulString NameDispenser::newName(YulString _nameHint, YulString _context) { // Shortening rules: Use a suffix of _prefix and a prefix of _context. - string prefix = _nameHint; + YulString prefix = _nameHint; if (!_context.empty()) - prefix = _context.substr(0, 10) + "_" + prefix; + prefix = YulString{_context.str().substr(0, 10) + "_" + prefix.str()}; return newNameInternal(prefix); } -string NameDispenser::newNameInternal(string const& _nameHint) +YulString NameDispenser::newNameInternal(YulString _nameHint) { + YulString name = _nameHint; size_t suffix = 0; - string name = _nameHint; while (name.empty() || m_usedNames.count(name)) { suffix++; - name = _nameHint + "_" + to_string(suffix); + name = YulString(_nameHint.str() + "_" + to_string(suffix)); } - m_usedNames.insert(name); + m_usedNames.emplace(name); return name; } diff --git a/libyul/optimiser/NameDispenser.h b/libyul/optimiser/NameDispenser.h index 5fbf5f8e..57adbcad 100644 --- a/libyul/optimiser/NameDispenser.h +++ b/libyul/optimiser/NameDispenser.h @@ -21,8 +21,9 @@ #include <libyul/ASTDataForward.h> +#include <libyul/YulString.h> + #include <set> -#include <string> namespace dev { @@ -41,18 +42,18 @@ public: /// Initialize the name dispenser with all the names used in the given AST. explicit NameDispenser(Block const& _ast); /// Initialize the name dispenser with the given used names. - explicit NameDispenser(std::set<std::string> _usedNames); + explicit NameDispenser(std::set<YulString> _usedNames); /// @returns a currently unused name that should be similar to _nameHint /// and prefixed by _context if present. /// If the resulting name would be too long, trims the context at the end /// and the name hint at the start. - std::string newName(std::string const& _nameHint, std::string const& _context = {}); + YulString newName(YulString _nameHint, YulString _context = {}); private: - std::string newNameInternal(std::string const& _nameHint); + YulString newNameInternal(YulString _nameHint); - std::set<std::string> m_usedNames; + std::set<YulString> m_usedNames; }; } diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index 478858e4..775b7673 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -44,7 +44,7 @@ void RedundantAssignEliminator::operator()(VariableDeclaration const& _variableD ASTWalker::operator()(_variableDeclaration); for (auto const& var: _variableDeclaration.variables) - m_declaredVariables.insert(var.name); + m_declaredVariables.emplace(var.name); } void RedundantAssignEliminator::operator()(Assignment const& _assignment) @@ -156,7 +156,7 @@ void RedundantAssignEliminator::run(Block& _ast) { assertThrow(assignment.second != State::Undecided, OptimizerException, ""); if (assignment.second == State::Unused && MovableChecker{*assignment.first->value}.movable()) - assignmentsToRemove.insert(assignment.first); + assignmentsToRemove.emplace(assignment.first); } AssignmentRemover remover{assignmentsToRemove}; @@ -176,7 +176,7 @@ void RedundantAssignEliminator::join(RedundantAssignEliminator& _other) m_assignments[var.first] = std::move(var.second); } -void RedundantAssignEliminator::changeUndecidedTo(string const& _variable, RedundantAssignEliminator::State _newState) +void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState) { for (auto& assignment: m_assignments[_variable]) if (assignment.second == State{State::Undecided}) diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h index 52092138..805a1f63 100644 --- a/libyul/optimiser/RedundantAssignEliminator.h +++ b/libyul/optimiser/RedundantAssignEliminator.h @@ -125,9 +125,9 @@ private: public: enum Value { Unused, Undecided, Used }; State(Value _value = Undecided): m_value(_value) {} - bool operator==(State _other) const { return m_value == _other.m_value; } - bool operator!=(State _other) const { return !operator==(_other); } - void join(State _other) + inline bool operator==(State _other) const { return m_value == _other.m_value; } + inline bool operator!=(State _other) const { return !operator==(_other); } + inline void join(State const& _other) { // Using "max" works here because of the order of the values in the enum. m_value = Value(std::max(int(_other.m_value), int(m_value))); @@ -156,17 +156,18 @@ private: private: RedundantAssignEliminator& m_rae; - std::set<std::string> m_outerDeclaredVariables; + std::set<YulString> m_outerDeclaredVariables; }; /// Joins the assignment mapping with @a _other according to the rules laid out /// above. /// Will destroy @a _other. void join(RedundantAssignEliminator& _other); - void changeUndecidedTo(std::string const& _variable, State _newState); + void changeUndecidedTo(YulString _variable, State _newState); - std::set<std::string> m_declaredVariables; - std::map<std::string, std::map<Assignment const*, State>> m_assignments; + std::set<YulString> m_declaredVariables; + // TODO check that this does not cause nondeterminism! + std::map<YulString, std::map<Assignment const*, State>> m_assignments; }; class AssignmentRemover: public ASTModifier diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index a99db0b6..38d50ef4 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -37,7 +37,7 @@ void Rematerialiser::visit(Expression& _e) Identifier& identifier = boost::get<Identifier>(_e); if (m_value.count(identifier.name)) { - string name = identifier.name; + YulString name = identifier.name; for (auto const& ref: m_references[name]) assertThrow(inScope(ref), OptimizerException, ""); assertThrow(m_value.at(name), OptimizerException, ""); diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index afcfab3e..f82465eb 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -22,10 +22,6 @@ #include <libyul/optimiser/DataFlowAnalyzer.h> -#include <string> -#include <map> -#include <set> - namespace dev { namespace yul diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp index 9db7bd03..f209ee7b 100644 --- a/libyul/optimiser/SSATransform.cpp +++ b/libyul/optimiser/SSATransform.cpp @@ -62,15 +62,15 @@ void SSATransform::operator()(ForLoop& _for) void SSATransform::operator()(Block& _block) { - set<string> variablesToClearAtEnd; + set<YulString> variablesToClearAtEnd; // Creates a new variable (and returns its declaration) with value _value // and replaces _value by a reference to that new variable. - auto replaceByNew = [&](SourceLocation _loc, string _varName, string _type, shared_ptr<Expression>& _value) -> VariableDeclaration + auto replaceByNew = [&](SourceLocation _loc, YulString _varName, YulString _type, shared_ptr<Expression>& _value) -> VariableDeclaration { - string newName = m_nameDispenser.newName(_varName); + YulString newName = m_nameDispenser.newName(_varName); m_currentVariableValues[_varName] = newName; - variablesToClearAtEnd.insert(_varName); + variablesToClearAtEnd.emplace(_varName); shared_ptr<Expression> v = make_shared<Expression>(Identifier{_loc, newName}); _value.swap(v); return VariableDeclaration{_loc, {TypedName{_loc, std::move(newName), std::move(_type)}}, std::move(v)}; diff --git a/libyul/optimiser/SSATransform.h b/libyul/optimiser/SSATransform.h index 2adc657d..bb642549 100644 --- a/libyul/optimiser/SSATransform.h +++ b/libyul/optimiser/SSATransform.h @@ -85,13 +85,13 @@ public: static void run(Block& _ast, NameDispenser& _nameDispenser); private: - explicit SSATransform(NameDispenser& _nameDispenser, std::set<std::string> const& _variablesToReplace): + explicit SSATransform(NameDispenser& _nameDispenser, std::set<YulString> const& _variablesToReplace): m_nameDispenser(_nameDispenser), m_variablesToReplace(_variablesToReplace) { } NameDispenser& m_nameDispenser; - std::set<std::string> const& m_variablesToReplace; - std::map<std::string, std::string> m_currentVariableValues; + std::set<YulString> const& m_variablesToReplace; + std::map<YulString, YulString> m_currentVariableValues; }; } diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp index a1291d67..491117da 100644 --- a/libyul/optimiser/SSAValueTracker.cpp +++ b/libyul/optimiser/SSAValueTracker.cpp @@ -42,7 +42,7 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl) setValue(var.name, nullptr); } -void SSAValueTracker::setValue(string const& _name, Expression const* _value) +void SSAValueTracker::setValue(YulString _name, Expression const* _value) { assertThrow( m_values.count(_name) == 0, diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h index 8c39a98e..d1539c86 100644 --- a/libyul/optimiser/SSAValueTracker.h +++ b/libyul/optimiser/SSAValueTracker.h @@ -23,7 +23,6 @@ #include <libyul/optimiser/ASTWalker.h> -#include <string> #include <map> #include <set> @@ -45,13 +44,13 @@ public: virtual void operator()(VariableDeclaration const& _varDecl) override; virtual void operator()(Assignment const& _assignment) override; - std::map<std::string, Expression const*> const& values() const { return m_values; } - Expression const* value(std::string const& _name) const { return m_values.at(_name); } + std::map<YulString, Expression const*> const& values() const { return m_values; } + Expression const* value(YulString _name) const { return m_values.at(_name); } private: - void setValue(std::string const& _name, Expression const* _value); + void setValue(YulString _name, Expression const* _value); - std::map<std::string, Expression const*> m_values; + std::map<YulString, Expression const*> m_values; }; } diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index 33f3af77..3c49016e 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -40,7 +40,7 @@ MovableChecker::MovableChecker(Expression const& _expression) void MovableChecker::operator()(Identifier const& _identifier) { ASTWalker::operator()(_identifier); - m_variableReferences.insert(_identifier.name); + m_variableReferences.emplace(_identifier.name); } void MovableChecker::operator()(FunctionalInstruction const& _instr) diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h index 1caa12fb..620a91cb 100644 --- a/libyul/optimiser/Semantics.h +++ b/libyul/optimiser/Semantics.h @@ -22,8 +22,6 @@ #include <libyul/optimiser/ASTWalker.h> -#include <string> -#include <map> #include <set> namespace dev @@ -49,11 +47,11 @@ public: using ASTWalker::visit; bool movable() const { return m_movable; } - std::set<std::string> const& referencedVariables() const { return m_variableReferences; } + std::set<YulString> const& referencedVariables() const { return m_variableReferences; } private: /// Which variables the current expression references. - std::set<std::string> m_variableReferences; + std::set<YulString> m_variableReferences; /// Is the current expression movable or not. bool m_movable = true; }; diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index aca943b0..5721042f 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -36,7 +36,7 @@ using namespace dev::yul; SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch( Expression const& _expr, - map<string, Expression const*> const& _ssaValues + map<YulString, Expression const*> const& _ssaValues ) { if (_expr.type() != typeid(FunctionalInstruction)) @@ -46,7 +46,7 @@ SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch( assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized."); FunctionalInstruction const& instruction = boost::get<FunctionalInstruction>(_expr); - for (auto const& rule: rules.m_rules[byte(instruction.instruction)]) + for (auto const& rule: rules.m_rules[uint8_t(instruction.instruction)]) { rules.resetMatchGroups(); if (rule.pattern.matches(_expr, _ssaValues)) @@ -57,7 +57,7 @@ SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch( bool SimplificationRules::isInitialized() const { - return !m_rules[byte(solidity::Instruction::ADD)].empty(); + return !m_rules[uint8_t(solidity::Instruction::ADD)].empty(); } void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules) @@ -68,7 +68,7 @@ void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _r void SimplificationRules::addRule(SimplificationRule<Pattern> const& _rule) { - m_rules[byte(_rule.pattern.instruction())].push_back(_rule); + m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule); } SimplificationRules::SimplificationRules() @@ -104,7 +104,7 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _ m_matchGroups = &_matchGroups; } -bool Pattern::matches(Expression const& _expr, map<string, Expression const*> const& _ssaValues) const +bool Pattern::matches(Expression const& _expr, map<YulString, Expression const*> const& _ssaValues) const { Expression const* expr = &_expr; @@ -112,7 +112,7 @@ bool Pattern::matches(Expression const& _expr, map<string, Expression const*> co // Do not do it for "Any" because we can check identity better for variables. if (m_kind != PatternKind::Any && _expr.type() == typeid(Identifier)) { - string const& varName = boost::get<Identifier>(_expr).name; + YulString varName = boost::get<Identifier>(_expr).name; if (_ssaValues.count(varName)) expr = _ssaValues.at(varName); } @@ -125,7 +125,7 @@ bool Pattern::matches(Expression const& _expr, map<string, Expression const*> co Literal const& literal = boost::get<Literal>(*expr); if (literal.kind != assembly::LiteralKind::Number) return false; - if (m_data && *m_data != u256(literal.value)) + if (m_data && *m_data != u256(literal.value.str())) return false; assertThrow(m_arguments.empty(), OptimizerException, ""); } @@ -193,7 +193,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const if (m_kind == PatternKind::Constant) { assertThrow(m_data, OptimizerException, "No match group and no constant value given."); - return Literal{_location, assembly::LiteralKind::Number, formatNumber(*m_data), ""}; + return Literal{_location, assembly::LiteralKind::Number, YulString{formatNumber(*m_data)}, {}}; } else if (m_kind == PatternKind::Operation) { @@ -209,8 +209,8 @@ u256 Pattern::d() const { Literal const& literal = boost::get<Literal>(matchGroupValue()); assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, ""); - assertThrow(isValidDecimal(literal.value) || isValidHex(literal.value), OptimizerException, ""); - return u256(literal.value); + assertThrow(isValidDecimal(literal.value.str()) || isValidHex(literal.value.str()), OptimizerException, ""); + return u256(literal.value.str()); } Expression const& Pattern::matchGroupValue() const diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index 82ae5d22..b608ca91 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -52,7 +52,7 @@ public: /// @param _ssaValues values of variables that are assigned exactly once. static SimplificationRule<Pattern> const* findFirstMatch( Expression const& _expr, - std::map<std::string, Expression const*> const& _ssaValues + std::map<YulString, Expression const*> const& _ssaValues ); /// Checks whether the rulelist is non-empty. This is usually enforced @@ -96,7 +96,7 @@ public: /// same expression equivalence class. void setMatchGroup(unsigned _group, std::map<unsigned, Expression const*>& _matchGroups); unsigned matchGroup() const { return m_matchGroup; } - bool matches(Expression const& _expr, std::map<std::string, Expression const*> const& _ssaValues) const; + bool matches(Expression const& _expr, std::map<YulString, Expression const*> const& _ssaValues) const; std::vector<Pattern> arguments() const { return m_arguments; } diff --git a/libyul/optimiser/Substitution.cpp b/libyul/optimiser/Substitution.cpp index 4a000a85..9b3d4c03 100644 --- a/libyul/optimiser/Substitution.cpp +++ b/libyul/optimiser/Substitution.cpp @@ -30,7 +30,7 @@ Expression Substitution::translate(Expression const& _expression) { if (_expression.type() == typeid(Identifier)) { - string const& name = boost::get<Identifier>(_expression).name; + YulString name = boost::get<Identifier>(_expression).name; if (m_substitutions.count(name)) // No recursive substitution return ASTCopier().translate(*m_substitutions.at(name)); diff --git a/libyul/optimiser/Substitution.h b/libyul/optimiser/Substitution.h index b734cdca..59ee4620 100644 --- a/libyul/optimiser/Substitution.h +++ b/libyul/optimiser/Substitution.h @@ -22,9 +22,9 @@ #include <libyul/optimiser/ASTCopier.h> -#include <string> +#include <libyul/YulString.h> + #include <map> -#include <set> namespace dev { @@ -37,13 +37,13 @@ namespace yul class Substitution: public ASTCopier { public: - Substitution(std::map<std::string, Expression const*> const& _substitutions): + Substitution(std::map<YulString, Expression const*> const& _substitutions): m_substitutions(_substitutions) {} virtual Expression translate(Expression const& _expression) override; private: - std::map<std::string, Expression const*> const& m_substitutions; + std::map<YulString, Expression const*> const& m_substitutions; }; } diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 5b325afd..c7339d2e 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -48,10 +48,10 @@ using namespace dev::yul; void OptimiserSuite::run( Block& _ast, solidity::assembly::AsmAnalysisInfo const& _analysisInfo, - set<string> const& _externallyUsedIdentifiers + set<YulString> const& _externallyUsedIdentifiers ) { - set<string> reservedIdentifiers = _externallyUsedIdentifiers; + set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast)); diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index bb6274bd..5b564c56 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -21,9 +21,8 @@ #pragma once #include <libyul/ASTDataForward.h> +#include <libyul/YulString.h> -#include <string> -#include <map> #include <set> namespace dev @@ -47,7 +46,8 @@ public: static void run( Block& _ast, solidity::assembly::AsmAnalysisInfo const& _analysisInfo, - std::set<std::string> const& _externallyUsedIdentifiers = std::set<std::string>() + + std::set<YulString> const& _externallyUsedIdentifiers = {} ); }; diff --git a/libyul/optimiser/SyntacticalEquality.cpp b/libyul/optimiser/SyntacticalEquality.cpp index f22b5c31..66912383 100644 --- a/libyul/optimiser/SyntacticalEquality.cpp +++ b/libyul/optimiser/SyntacticalEquality.cpp @@ -34,6 +34,7 @@ bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const& { if (_e1.type() != _e2.type()) return false; + // TODO This somehow calls strcmp - WHERE? // TODO This should be replaced by some kind of AST walker as soon as it gets // more complex. diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 37a74553..a7b32873 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -33,7 +33,7 @@ using namespace std; using namespace dev; using namespace dev::yul; -UnusedPruner::UnusedPruner(Block& _ast, set<string> const& _externallyUsedFunctions) +UnusedPruner::UnusedPruner(Block& _ast, set<YulString> const& _externallyUsedFunctions) { ReferencesCounter counter; counter(_ast); @@ -91,7 +91,7 @@ void UnusedPruner::operator()(Block& _block) ASTModifier::operator()(_block); } -void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externallyUsedFunctions) +void UnusedPruner::runUntilStabilised(Block& _ast, set<YulString> const& _externallyUsedFunctions) { while (true) { @@ -102,12 +102,12 @@ void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externall } } -bool UnusedPruner::used(string const& _name) const +bool UnusedPruner::used(YulString _name) const { return m_references.count(_name) && m_references.at(_name) > 0; } -void UnusedPruner::subtractReferences(map<string, size_t> const& _subtrahend) +void UnusedPruner::subtractReferences(map<YulString, size_t> const& _subtrahend) { for (auto const& ref: _subtrahend) { diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h index 30617ff3..2dd74940 100644 --- a/libyul/optimiser/UnusedPruner.h +++ b/libyul/optimiser/UnusedPruner.h @@ -21,8 +21,8 @@ #pragma once #include <libyul/optimiser/ASTWalker.h> +#include <libyul/YulString.h> -#include <string> #include <map> #include <set> @@ -44,7 +44,7 @@ namespace yul class UnusedPruner: public ASTModifier { public: - explicit UnusedPruner(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>()); + explicit UnusedPruner(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {}); using ASTModifier::operator(); virtual void operator()(Block& _block) override; @@ -53,14 +53,14 @@ public: bool shouldRunAgain() const { return m_shouldRunAgain; } // Run the pruner until the code does not change anymore. - static void runUntilStabilised(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>()); + static void runUntilStabilised(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {}); private: - bool used(std::string const& _name) const; - void subtractReferences(std::map<std::string, size_t> const& _subtrahend); + bool used(YulString _name) const; + void subtractReferences(std::map<YulString, size_t> const& _subtrahend); bool m_shouldRunAgain = false; - std::map<std::string, size_t> m_references; + std::map<YulString, size_t> m_references; }; } diff --git a/libyul/optimiser/VarDeclPropagator.cpp b/libyul/optimiser/VarDeclPropagator.cpp index 39337b3d..537b7020 100644 --- a/libyul/optimiser/VarDeclPropagator.cpp +++ b/libyul/optimiser/VarDeclPropagator.cpp @@ -31,8 +31,8 @@ using dev::solidity::assembly::TypedNameList; void VarDeclPropagator::operator()(Block& _block) { - map<string, TypedName> outerEmptyVarDecls; - map<string, TypedName> outerLazyInitializedVarDecls; + map<YulString, TypedName> outerEmptyVarDecls; + map<YulString, TypedName> outerLazyInitializedVarDecls; swap(m_emptyVarDecls, outerEmptyVarDecls); swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls); diff --git a/libyul/optimiser/VarDeclPropagator.h b/libyul/optimiser/VarDeclPropagator.h index 8cba8649..4522d23a 100644 --- a/libyul/optimiser/VarDeclPropagator.h +++ b/libyul/optimiser/VarDeclPropagator.h @@ -53,10 +53,10 @@ private: private: /// Holds a list of variables from current Block that have no value assigned yet. - std::map<std::string, TypedName> m_emptyVarDecls; + std::map<YulString, TypedName> m_emptyVarDecls; /// Holds a list variables (and their TypedName) within the current block. - std::map<std::string, TypedName> m_lazyInitializedVarDecls; + std::map<YulString, TypedName> m_lazyInitializedVarDecls; }; } diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 0b42f9d0..e275147b 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -147,11 +147,11 @@ public: static std::pair<bool, std::string> compareAndCreateMessage(bytes const& _result, bytes const& _expectation); - static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(bool _value) { return encode(uint8_t(_value)); } static bytes encode(int _value) { return encode(u256(_value)); } static bytes encode(size_t _value) { return encode(u256(_value)); } static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(uint8_t _value) { return bytes(31, 0) + bytes{_value}; } static bytes encode(u256 const& _value) { return toBigEndian(_value); } /// @returns the fixed-point encoding of a rational number with a given /// number of fractional bits. diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 8d17e56f..87646737 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1259,14 +1259,14 @@ BOOST_AUTO_TEST_CASE(state_smoke_test) } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(0)); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(0)); - ABI_CHECK(callContractFunction("set(uint8,uint256)", byte(0x00), 0x1234), encodeArgs()); - ABI_CHECK(callContractFunction("set(uint8,uint256)", byte(0x01), 0x8765), encodeArgs()); - ABI_CHECK(callContractFunction("get(uint8)", byte( 0x00)), encodeArgs(0x1234)); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(0x8765)); - ABI_CHECK(callContractFunction("set(uint8,uint256)", byte(0x00), 0x3), encodeArgs()); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(0x3)); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0)); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0)); + ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x1234), encodeArgs()); + ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x01), 0x8765), encodeArgs()); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t( 0x00)), encodeArgs(0x1234)); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0x8765)); + ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x3), encodeArgs()); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0x3)); } BOOST_AUTO_TEST_CASE(compound_assign) @@ -1321,21 +1321,21 @@ BOOST_AUTO_TEST_CASE(simple_mapping) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("get(uint8)", byte(0)), encodeArgs(byte(0x00))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0x00))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00))); - callContractFunction("set(uint8,uint8)", byte(0x01), byte(0xa1)); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(byte(0x00))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0xa1))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00))); - callContractFunction("set(uint8,uint8)", byte(0x00), byte(0xef)); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(byte(0xef))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0xa1))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00))); - callContractFunction("set(uint8,uint8)", byte(0x01), byte(0x05)); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(byte(0xef))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0x05))); - ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0)), encodeArgs(uint8_t(0x00))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x00))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); + callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0xa1)); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0x00))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); + callContractFunction("set(uint8,uint8)", uint8_t(0x00), uint8_t(0xef)); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); + callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0x05)); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x05))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); } BOOST_AUTO_TEST_CASE(mapping_state) @@ -1496,7 +1496,7 @@ BOOST_AUTO_TEST_CASE(mapping_local_assignment) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(byte(42), byte(0), byte(0), byte(21))); + ABI_CHECK(callContractFunction("f()"), encodeArgs(uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(21))); } BOOST_AUTO_TEST_CASE(mapping_local_tuple_assignment) @@ -1519,7 +1519,7 @@ BOOST_AUTO_TEST_CASE(mapping_local_tuple_assignment) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(byte(42), byte(0), byte(0), byte(21))); + ABI_CHECK(callContractFunction("f()"), encodeArgs(uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(21))); } BOOST_AUTO_TEST_CASE(mapping_local_compound_assignment) @@ -1540,7 +1540,7 @@ BOOST_AUTO_TEST_CASE(mapping_local_compound_assignment) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(byte(42), byte(0), byte(0), byte(21))); + ABI_CHECK(callContractFunction("f()"), encodeArgs(uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(21))); } BOOST_AUTO_TEST_CASE(mapping_internal_argument) @@ -1565,10 +1565,10 @@ BOOST_AUTO_TEST_CASE(mapping_internal_argument) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", byte(1), byte(21), byte(42)), encodeArgs(byte(0), byte(0))); - ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(21), byte(42))); - ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", byte(1), byte(10), byte(11)), encodeArgs(byte(21), byte(42))); - ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(10), byte(11))); + ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", uint8_t(1), uint8_t(21), uint8_t(42)), encodeArgs(uint8_t(0), uint8_t(0))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(21), uint8_t(42))); + ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", uint8_t(1), uint8_t(10), uint8_t(11)), encodeArgs(uint8_t(21), uint8_t(42))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(10), uint8_t(11))); } BOOST_AUTO_TEST_CASE(mapping_array_internal_argument) @@ -1595,10 +1595,10 @@ BOOST_AUTO_TEST_CASE(mapping_array_internal_argument) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", byte(1), byte(21), byte(22), byte(42), byte(43)), encodeArgs(byte(0), byte(0), byte(0), byte(0))); - ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(21), byte(22), byte(42), byte(43))); - ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", byte(1), byte(10), byte(30), byte(11), byte(31)), encodeArgs(byte(21), byte(22), byte(42), byte(43))); - ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(10), byte(30), byte(11), byte(31))); + ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", uint8_t(1), uint8_t(21), uint8_t(22), uint8_t(42), uint8_t(43)), encodeArgs(uint8_t(0), uint8_t(0), uint8_t(0), uint8_t(0))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(21), uint8_t(22), uint8_t(42), uint8_t(43))); + ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", uint8_t(1), uint8_t(10), uint8_t(30), uint8_t(11), uint8_t(31)), encodeArgs(uint8_t(21), uint8_t(22), uint8_t(42), uint8_t(43))); + ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(10), uint8_t(30), uint8_t(11), uint8_t(31))); } BOOST_AUTO_TEST_CASE(mapping_internal_return) @@ -1626,8 +1626,8 @@ BOOST_AUTO_TEST_CASE(mapping_internal_return) )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(byte(0), byte(42), byte(0), byte(0), byte(84), byte (21))); - ABI_CHECK(callContractFunction("h()"), encodeArgs(byte(0), byte(42), byte(0), byte(0), byte(84), byte (17))); + ABI_CHECK(callContractFunction("g()"), encodeArgs(uint8_t(0), uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(84), uint8_t (21))); + ABI_CHECK(callContractFunction("h()"), encodeArgs(uint8_t(0), uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(84), uint8_t (17))); } BOOST_AUTO_TEST_CASE(structs) @@ -1819,7 +1819,7 @@ BOOST_AUTO_TEST_CASE(constructor) } )"; compileAndRun(sourceCode); - map<u256, byte> data; + map<u256, uint8_t> data; data[7] = 8; auto get = [&](u256 const& _x) -> u256 { @@ -2624,7 +2624,7 @@ BOOST_AUTO_TEST_CASE(ecrecover) )"; compileAndRun(sourceCode); u256 h("0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c"); - byte v = 28; + uint8_t v = 28; u256 r("0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f"); u256 s("0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"); u160 addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 26b7914f..309cbf0b 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -180,7 +180,7 @@ BOOST_AUTO_TEST_CASE(literal_true) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH1), 0x1}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x1}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(literal_false) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH1), 0x0}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x0}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(int_literal) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, + bytes expectation({uint8_t(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH1), 0x1}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x1}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00}); + bytes expectation({uint8_t(Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(int_with_finney_ether_subdenomination) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00}); + bytes expectation({uint8_t(Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -268,7 +268,7 @@ BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00}); + bytes expectation({uint8_t(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -281,12 +281,12 @@ BOOST_AUTO_TEST_CASE(comparison) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH1), 0x1, byte(Instruction::ISZERO), byte(Instruction::ISZERO), - byte(Instruction::PUSH2), 0x11, 0xaa, - byte(Instruction::PUSH2), 0x10, 0xaa, - byte(Instruction::LT), byte(Instruction::ISZERO), byte(Instruction::ISZERO), - byte(Instruction::EQ), - byte(Instruction::ISZERO)}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO), + uint8_t(Instruction::PUSH2), 0x11, 0xaa, + uint8_t(Instruction::PUSH2), 0x10, 0xaa, + uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO), + uint8_t(Instruction::EQ), + uint8_t(Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -299,23 +299,23 @@ BOOST_AUTO_TEST_CASE(short_circuiting) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(Instruction::PUSH1), 0x12, // 8 + 10 - byte(Instruction::PUSH1), 0x4, - byte(Instruction::GT), - byte(Instruction::ISZERO), // after this we have 4 <= 8 + 10 - byte(Instruction::DUP1), - byte(Instruction::PUSH1), 0x11, - byte(Instruction::JUMPI), // short-circuit if it is true - byte(Instruction::POP), - byte(Instruction::PUSH1), 0x2, - byte(Instruction::PUSH1), 0x9, - byte(Instruction::EQ), - byte(Instruction::ISZERO), // after this we have 9 != 2 - byte(Instruction::JUMPDEST), - byte(Instruction::ISZERO), byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x1, byte(Instruction::ISZERO), byte(Instruction::ISZERO), - byte(Instruction::EQ), - byte(Instruction::ISZERO)}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x12, // 8 + 10 + uint8_t(Instruction::PUSH1), 0x4, + uint8_t(Instruction::GT), + uint8_t(Instruction::ISZERO), // after this we have 4 <= 8 + 10 + uint8_t(Instruction::DUP1), + uint8_t(Instruction::PUSH1), 0x11, + uint8_t(Instruction::JUMPI), // short-circuit if it is true + uint8_t(Instruction::POP), + uint8_t(Instruction::PUSH1), 0x2, + uint8_t(Instruction::PUSH1), 0x9, + uint8_t(Instruction::EQ), + uint8_t(Instruction::ISZERO), // after this we have 9 != 2 + uint8_t(Instruction::JUMPDEST), + uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO), + uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO), + uint8_t(Instruction::EQ), + uint8_t(Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -327,37 +327,37 @@ BOOST_AUTO_TEST_CASE(arithmetic) } )"; bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}}); - bytes expectation({byte(Instruction::PUSH1), 0x1, - byte(Instruction::PUSH1), 0x2, - byte(Instruction::PUSH1), 0x3, - byte(Instruction::PUSH1), 0x4, - byte(Instruction::PUSH1), 0x5, - byte(Instruction::PUSH1), 0x6, - byte(Instruction::PUSH1), 0x7, - byte(Instruction::PUSH1), 0x8, - byte(Instruction::DUP9), - byte(Instruction::XOR), - byte(Instruction::AND), - byte(Instruction::OR), - byte(Instruction::SUB), - byte(Instruction::ADD), - byte(Instruction::DUP2), - byte(Instruction::ISZERO), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x1d, - byte(Instruction::JUMPI), - byte(Instruction::INVALID), - byte(Instruction::JUMPDEST), - byte(Instruction::MOD), - byte(Instruction::DUP2), - byte(Instruction::ISZERO), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x26, - byte(Instruction::JUMPI), - byte(Instruction::INVALID), - byte(Instruction::JUMPDEST), - byte(Instruction::DIV), - byte(Instruction::MUL)}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x1, + uint8_t(Instruction::PUSH1), 0x2, + uint8_t(Instruction::PUSH1), 0x3, + uint8_t(Instruction::PUSH1), 0x4, + uint8_t(Instruction::PUSH1), 0x5, + uint8_t(Instruction::PUSH1), 0x6, + uint8_t(Instruction::PUSH1), 0x7, + uint8_t(Instruction::PUSH1), 0x8, + uint8_t(Instruction::DUP9), + uint8_t(Instruction::XOR), + uint8_t(Instruction::AND), + uint8_t(Instruction::OR), + uint8_t(Instruction::SUB), + uint8_t(Instruction::ADD), + uint8_t(Instruction::DUP2), + uint8_t(Instruction::ISZERO), + uint8_t(Instruction::ISZERO), + uint8_t(Instruction::PUSH1), 0x1d, + uint8_t(Instruction::JUMPI), + uint8_t(Instruction::INVALID), + uint8_t(Instruction::JUMPDEST), + uint8_t(Instruction::MOD), + uint8_t(Instruction::DUP2), + uint8_t(Instruction::ISZERO), + uint8_t(Instruction::ISZERO), + uint8_t(Instruction::PUSH1), 0x26, + uint8_t(Instruction::JUMPI), + uint8_t(Instruction::INVALID), + uint8_t(Instruction::JUMPDEST), + uint8_t(Instruction::DIV), + uint8_t(Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -370,13 +370,13 @@ BOOST_AUTO_TEST_CASE(unary_operators) )"; bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}}); - bytes expectation({byte(Instruction::PUSH1), 0x2, - byte(Instruction::DUP2), - byte(Instruction::PUSH1), 0x0, - byte(Instruction::SUB), - byte(Instruction::NOT), - byte(Instruction::EQ), - byte(Instruction::ISZERO)}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x2, + uint8_t(Instruction::DUP2), + uint8_t(Instruction::PUSH1), 0x0, + uint8_t(Instruction::SUB), + uint8_t(Instruction::NOT), + uint8_t(Instruction::EQ), + uint8_t(Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -390,47 +390,47 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec) bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); // Stack: a, x - bytes expectation({byte(Instruction::DUP2), - byte(Instruction::DUP1), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::ADD), + bytes expectation({uint8_t(Instruction::DUP2), + uint8_t(Instruction::DUP1), + uint8_t(Instruction::PUSH1), 0x1, + uint8_t(Instruction::ADD), // Stack here: a x a (a+1) - byte(Instruction::SWAP3), - byte(Instruction::POP), // first ++ + uint8_t(Instruction::SWAP3), + uint8_t(Instruction::POP), // first ++ // Stack here: (a+1) x a - byte(Instruction::DUP3), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::ADD), + uint8_t(Instruction::DUP3), + uint8_t(Instruction::PUSH1), 0x1, + uint8_t(Instruction::ADD), // Stack here: (a+1) x a (a+2) - byte(Instruction::SWAP3), - byte(Instruction::POP), + uint8_t(Instruction::SWAP3), + uint8_t(Instruction::POP), // Stack here: (a+2) x a - byte(Instruction::DUP3), // second ++ - byte(Instruction::XOR), + uint8_t(Instruction::DUP3), // second ++ + uint8_t(Instruction::XOR), // Stack here: (a+2) x a^(a+2) - byte(Instruction::DUP3), - byte(Instruction::DUP1), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::SWAP1), - byte(Instruction::SUB), + uint8_t(Instruction::DUP3), + uint8_t(Instruction::DUP1), + uint8_t(Instruction::PUSH1), 0x1, + uint8_t(Instruction::SWAP1), + uint8_t(Instruction::SUB), // Stack here: (a+2) x a^(a+2) (a+2) (a+1) - byte(Instruction::SWAP4), - byte(Instruction::POP), // first -- - byte(Instruction::XOR), + uint8_t(Instruction::SWAP4), + uint8_t(Instruction::POP), // first -- + uint8_t(Instruction::XOR), // Stack here: (a+1) x a^(a+2)^(a+2) - byte(Instruction::DUP3), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::SWAP1), - byte(Instruction::SUB), + uint8_t(Instruction::DUP3), + uint8_t(Instruction::PUSH1), 0x1, + uint8_t(Instruction::SWAP1), + uint8_t(Instruction::SUB), // Stack here: (a+1) x a^(a+2)^(a+2) a - byte(Instruction::SWAP3), - byte(Instruction::POP), // second ++ + uint8_t(Instruction::SWAP3), + uint8_t(Instruction::POP), // second ++ // Stack here: a x a^(a+2)^(a+2) - byte(Instruction::DUP3), // will change - byte(Instruction::XOR), - byte(Instruction::SWAP1), - byte(Instruction::POP), - byte(Instruction::DUP1)}); + uint8_t(Instruction::DUP3), // will change + uint8_t(Instruction::XOR), + uint8_t(Instruction::SWAP1), + uint8_t(Instruction::POP), + uint8_t(Instruction::DUP1)}); // Stack here: a x a^(a+2)^(a+2)^a BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -445,16 +445,16 @@ BOOST_AUTO_TEST_CASE(assignment) bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); // Stack: a, b - bytes expectation({byte(Instruction::PUSH1), 0x2, - byte(Instruction::DUP2), - byte(Instruction::DUP4), - byte(Instruction::ADD), + bytes expectation({uint8_t(Instruction::PUSH1), 0x2, + uint8_t(Instruction::DUP2), + uint8_t(Instruction::DUP4), + uint8_t(Instruction::ADD), // Stack here: a b 2 a+b - byte(Instruction::SWAP3), - byte(Instruction::POP), - byte(Instruction::DUP3), + uint8_t(Instruction::SWAP3), + uint8_t(Instruction::POP), + uint8_t(Instruction::DUP3), // Stack here: a+b b 2 a+b - byte(Instruction::MUL)}); + uint8_t(Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -467,7 +467,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80)); + bytes expectation(bytes({uint8_t(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80)); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -480,7 +480,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43}); + bytes expectation(bytes({uint8_t(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -495,7 +495,7 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals) )"; bytes code = compileFirstExpression(sourceCode); - bytes expectation(bytes({byte(Instruction::PUSH1), 0xbf})); + bytes expectation(bytes({uint8_t(Instruction::PUSH1), 0xbf})); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -514,8 +514,8 @@ BOOST_AUTO_TEST_CASE(blockhash) bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)}); - bytes expectation({byte(Instruction::PUSH1), 0x03, - byte(Instruction::BLOCKHASH)}); + bytes expectation({uint8_t(Instruction::PUSH1), 0x03, + uint8_t(Instruction::BLOCKHASH)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -533,7 +533,7 @@ BOOST_AUTO_TEST_CASE(gas_left) {make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))} ); - bytes expectation = bytes({byte(Instruction::GAS)}); + bytes expectation = bytes({uint8_t(Instruction::GAS)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } diff --git a/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_payable.sol b/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_payable.sol new file mode 100644 index 00000000..75f7a953 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_payable.sol @@ -0,0 +1,10 @@ +contract C { + function h() external { + } + function f() view external returns (bytes4) { + function () payable external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (105-144): Type function () external is not implicitly convertible to expected type function () payable external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_pure.sol b/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_pure.sol new file mode 100644 index 00000000..8d1b08aa --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_pure.sol @@ -0,0 +1,10 @@ +contract C { + function h() external { + } + function f() view external returns (bytes4) { + function () pure external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (105-141): Type function () external is not implicitly convertible to expected type function () pure external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_view.sol b/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_view.sol new file mode 100644 index 00000000..535d6c77 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_nonpayable_view.sol @@ -0,0 +1,10 @@ +contract C { + function h() external { + } + function f() view external returns (bytes4) { + function () view external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (105-141): Type function () external is not implicitly convertible to expected type function () view external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_payable_nonpayable.sol b/test/libsolidity/syntaxTests/conversion/function_type_payable_nonpayable.sol new file mode 100644 index 00000000..299d7e30 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_payable_nonpayable.sol @@ -0,0 +1,8 @@ +contract C { + function h() payable external { + } + function f() view external returns (bytes4) { + function () external g = this.h; + return g.selector; + } +} diff --git a/test/libsolidity/syntaxTests/conversion/function_type_payable_pure.sol b/test/libsolidity/syntaxTests/conversion/function_type_payable_pure.sol new file mode 100644 index 00000000..78bada51 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_payable_pure.sol @@ -0,0 +1,10 @@ +contract C { + function h() payable external { + } + function f() view external returns (bytes4) { + function () pure external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (113-149): Type function () payable external is not implicitly convertible to expected type function () pure external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_payable_view.sol b/test/libsolidity/syntaxTests/conversion/function_type_payable_view.sol new file mode 100644 index 00000000..f12cb301 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_payable_view.sol @@ -0,0 +1,10 @@ +contract C { + function h() payable external { + } + function f() view external returns (bytes4) { + function () view external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (113-149): Type function () payable external is not implicitly convertible to expected type function () view external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_pure_nonpayable.sol b/test/libsolidity/syntaxTests/conversion/function_type_pure_nonpayable.sol new file mode 100644 index 00000000..7742e0c1 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_pure_nonpayable.sol @@ -0,0 +1,8 @@ +contract C { + function h() pure external { + } + function f() view external returns (bytes4) { + function () external g = this.h; + return g.selector; + } +} diff --git a/test/libsolidity/syntaxTests/conversion/function_type_pure_payable.sol b/test/libsolidity/syntaxTests/conversion/function_type_pure_payable.sol new file mode 100644 index 00000000..cd4e9b4e --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_pure_payable.sol @@ -0,0 +1,10 @@ +contract C { + function h() pure external { + } + function f() view external returns (bytes4) { + function () payable external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (110-149): Type function () pure external is not implicitly convertible to expected type function () payable external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_pure_view.sol b/test/libsolidity/syntaxTests/conversion/function_type_pure_view.sol new file mode 100644 index 00000000..578ecdbd --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_pure_view.sol @@ -0,0 +1,8 @@ +contract C { + function h() pure external { + } + function f() view external returns (bytes4) { + function () view external g = this.h; + return g.selector; + } +} diff --git a/test/libsolidity/syntaxTests/conversion/function_type_same.sol b/test/libsolidity/syntaxTests/conversion/function_type_same.sol new file mode 100644 index 00000000..c5ebe1ca --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_same.sol @@ -0,0 +1,14 @@ +contract C { + int dummy; + function h_nonpayable() external { dummy = 1; } + function h_payable() payable external {} + function h_view() view external { dummy; } + function h_pure() pure external {} + function f() view external { + function () external g_nonpayable = this.h_nonpayable; g_nonpayable; + function () payable external g_payable = this.h_payable; g_payable; + function () view external g_view = this.h_view; g_view; + function () pure external g_pure = this.h_pure; g_pure; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/conversion/function_type_view_nonpayable.sol b/test/libsolidity/syntaxTests/conversion/function_type_view_nonpayable.sol new file mode 100644 index 00000000..f52aece0 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_view_nonpayable.sol @@ -0,0 +1,10 @@ +contract C { + int dummy; + function h() view external { + dummy; + } + function f() view external returns (bytes4) { + function () external g = this.h; + return g.selector; + } +} diff --git a/test/libsolidity/syntaxTests/conversion/function_type_view_payable.sol b/test/libsolidity/syntaxTests/conversion/function_type_view_payable.sol new file mode 100644 index 00000000..3bf4bac2 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_view_payable.sol @@ -0,0 +1,10 @@ +contract C { + function h() view external { + } + function f() view external returns (bytes4) { + function () payable external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (110-149): Type function () view external is not implicitly convertible to expected type function () payable external. diff --git a/test/libsolidity/syntaxTests/conversion/function_type_view_pure.sol b/test/libsolidity/syntaxTests/conversion/function_type_view_pure.sol new file mode 100644 index 00000000..c567a2c8 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_type_view_pure.sol @@ -0,0 +1,10 @@ +contract C { + function h() view external { + } + function f() view external returns (bytes4) { + function () pure external g = this.h; + return g.selector; + } +} +// ---- +// TypeError: (110-146): Type function () view external is not implicitly convertible to expected type function () pure external. diff --git a/test/libsolidity/syntaxTests/types/rational_negative_numerator_negative_exp.sol b/test/libsolidity/syntaxTests/types/rational_negative_numerator_negative_exp.sol new file mode 100644 index 00000000..b694992c --- /dev/null +++ b/test/libsolidity/syntaxTests/types/rational_negative_numerator_negative_exp.sol @@ -0,0 +1,5 @@ +contract C { + function f() public pure returns (int) { + return (-1 / 2) ** -1; + } +} diff --git a/test/libyul/Inliner.cpp b/test/libyul/Inliner.cpp index 44c6411a..4ed52b47 100644 --- a/test/libyul/Inliner.cpp +++ b/test/libyul/Inliner.cpp @@ -49,10 +49,10 @@ string inlinableFunctions(string const& _source) InlinableExpressionFunctionFinder funFinder; funFinder(ast); - return boost::algorithm::join( - funFinder.inlinableFunctions() | boost::adaptors::map_keys, - "," - ); + vector<string> functionNames; + for (auto const& f: funFinder.inlinableFunctions()) + functionNames.emplace_back(f.first.str()); + return boost::algorithm::join(functionNames, ","); } } diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index 83c54959..68fc9f4f 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -121,7 +121,8 @@ public: disambiguated = true; } cout << "(q)quit/(f)flatten/(c)se/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl; - cout << " (e)xpr inline/(i)nline/(s)implify/(u)nusedprune/ss(a) transform/(r)edundant assign elim.? "; + cout << " (e)xpr inline/(i)nline/(s)implify/(u)nusedprune/ss(a) transform/" << endl; + cout << " (r)edundant assign elim./re(m)aterializer? "; cout.flush(); int option = readStandardInputChar(); cout << ' ' << char(option) << endl; @@ -165,6 +166,9 @@ public: case 'r': RedundantAssignEliminator::run(*m_ast); break; + case 'm': + Rematerialiser{}(*m_ast); + break; default: cout << "Unknown option." << endl; } |