diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/ContractLevelChecker.cpp | 10 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 3 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 80 | ||||
-rw-r--r-- | libsolidity/ast/AST.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 12 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 107 | ||||
-rw-r--r-- | libsolidity/codegen/ABIFunctions.cpp | 4 | ||||
-rw-r--r-- | libsolidity/codegen/AsmCodeGen.cpp | 7 | ||||
-rw-r--r-- | libsolidity/codegen/AsmCodeGen.h | 3 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 5 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 12 | ||||
-rw-r--r-- | libsolidity/formal/SMTChecker.cpp | 151 | ||||
-rw-r--r-- | libsolidity/formal/SMTChecker.h | 24 | ||||
-rw-r--r-- | libsolidity/formal/SymbolicTypes.cpp | 37 | ||||
-rw-r--r-- | libsolidity/formal/SymbolicTypes.h | 6 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.cpp | 29 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.h | 9 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 7 |
19 files changed, 299 insertions, 211 deletions
diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 6dc564de..526caff9 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -227,7 +227,7 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con return _type->hasEqualParameterTypes(*_funAndFlag.first); }); if (it == overloads.end()) - overloads.push_back(make_pair(_type, _implemented)); + overloads.emplace_back(_type, _implemented); else if (it->second) { if (!_implemented) @@ -409,8 +409,8 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c auto functionType = make_shared<FunctionType>(*f); // under non error circumstances this should be true if (functionType->interfaceFunctionType()) - externalDeclarations[functionType->externalSignature()].push_back( - make_pair(f, functionType->asCallableFunction(false)) + externalDeclarations[functionType->externalSignature()].emplace_back( + f, functionType->asCallableFunction(false) ); } for (VariableDeclaration const* v: contract->stateVariables()) @@ -419,8 +419,8 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c auto functionType = make_shared<FunctionType>(*v); // under non error circumstances this should be true if (functionType->interfaceFunctionType()) - externalDeclarations[functionType->externalSignature()].push_back( - make_pair(v, functionType->asCallableFunction(false)) + externalDeclarations[functionType->externalSignature()].emplace_back( + v, functionType->asCallableFunction(false) ); } } diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index ac88a052..76641c04 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -27,6 +27,7 @@ #include <libyul/AsmAnalysis.h> #include <libyul/AsmAnalysisInfo.h> #include <libyul/AsmData.h> +#include <libyul/backends/evm/EVMDialect.h> #include <liblangutil/ErrorReporter.h> #include <liblangutil/Exceptions.h> @@ -321,7 +322,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) errorsIgnored, EVMVersion(), errorTypeForLoose, - yul::Dialect::looseAssemblyForEVM(), + yul::EVMDialect::looseAssemblyForEVM(), resolver ).analyze(_inlineAssembly.operations()); return false; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1c9f1956..5bd96f8d 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -27,6 +27,8 @@ #include <libyul/AsmAnalysisInfo.h> #include <libyul/AsmData.h> +#include <libyul/backends/evm/EVMDialect.h> + #include <liblangutil/ErrorReporter.h> #include <libdevcore/Algorithms.h> @@ -658,7 +660,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) m_errorReporter, m_evmVersion, Error::Type::SyntaxError, - yul::Dialect::looseAssemblyForEVM(), + yul::EVMDialect::looseAssemblyForEVM(), identifierAccess ); if (!analyzer.analyze(_inlineAssembly.operations())) @@ -935,30 +937,32 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) var.accept(*this); if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type)) { + auto errorMsg = "Type " + + valueComponentType->toString() + + " is not implicitly convertible to expected type " + + var.annotation().type->toString(); if ( valueComponentType->category() == Type::Category::RationalNumber && dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() && valueComponentType->mobileType() ) - m_errorReporter.typeError( - _statement.location(), - "Type " + - valueComponentType->toString() + - " is not implicitly convertible to expected type " + - var.annotation().type->toString() + - ". Try converting to type " + - valueComponentType->mobileType()->toString() + - " or use an explicit conversion." - ); + { + if (var.annotation().type->operator==(*valueComponentType->mobileType())) + m_errorReporter.typeError( + _statement.location(), + errorMsg + ", but it can be explicitly converted." + ); + else + m_errorReporter.typeError( + _statement.location(), + errorMsg + + ". Try converting to type " + + valueComponentType->mobileType()->toString() + + " or use an explicit conversion." + ); + } else - m_errorReporter.typeError( - _statement.location(), - "Type " + - valueComponentType->toString() + - " is not implicitly convertible to expected type " + - var.annotation().type->toString() + - "." - ); + m_errorReporter.typeError(_statement.location(), errorMsg + "."); } } } @@ -2331,30 +2335,32 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte _expression.accept(*this); if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType)) { + auto errorMsg = "Type " + + type(_expression)->toString() + + " is not implicitly convertible to expected type " + + _expectedType.toString(); if ( type(_expression)->category() == Type::Category::RationalNumber && dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() && type(_expression)->mobileType() ) - m_errorReporter.typeError( - _expression.location(), - "Type " + - type(_expression)->toString() + - " is not implicitly convertible to expected type " + - _expectedType.toString() + - ". Try converting to type " + - type(_expression)->mobileType()->toString() + - " or use an explicit conversion." - ); + { + if (_expectedType.operator==(*type(_expression)->mobileType())) + m_errorReporter.typeError( + _expression.location(), + errorMsg + ", but it can be explicitly converted." + ); + else + m_errorReporter.typeError( + _expression.location(), + errorMsg + + ". Try converting to type " + + type(_expression)->mobileType()->toString() + + " or use an explicit conversion." + ); + } else - m_errorReporter.typeError( - _expression.location(), - "Type " + - type(_expression)->toString() + - " is not implicitly convertible to expected type " + - _expectedType.toString() + - "." - ); + m_errorReporter.typeError(_expression.location(), errorMsg + "."); return false; } return true; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 3ae6bd6d..5779e4ad 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -198,7 +198,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter { signaturesSeen.insert(functionSignature); FixedHash<4> hash(dev::keccak256(functionSignature)); - m_interfaceFunctionList->push_back(make_pair(hash, fun)); + m_interfaceFunctionList->emplace_back(hash, fun); } } } diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index e92134a8..1a2b3345 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -234,7 +234,7 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)), make_pair("scope", idOrNull(_node.scope())) }; - attributes.push_back(make_pair("unitAlias", _node.name())); + attributes.emplace_back("unitAlias", _node.name()); Json::Value symbolAliases(Json::arrayValue); for (auto const& symbolAlias: _node.symbolAliases()) { @@ -244,7 +244,7 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) tuple["local"] = symbolAlias.second ? Json::Value(*symbolAlias.second) : Json::nullValue; symbolAliases.append(tuple); } - attributes.push_back(make_pair("symbolAliases", std::move(symbolAliases))); + attributes.emplace_back("symbolAliases", std::move(symbolAliases)); setJsonNode(_node, "ImportDirective", std::move(attributes)); return false; } @@ -357,7 +357,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }; if (m_inEvent) - attributes.push_back(make_pair("indexed", _node.isIndexed())); + attributes.emplace_back("indexed", _node.isIndexed()); setJsonNode(_node, "VariableDeclaration", std::move(attributes)); return false; } @@ -647,11 +647,11 @@ bool ASTJsonConverter::visit(FunctionCall const& _node) }; if (m_legacy) { - attributes.push_back(make_pair("isStructConstructorCall", _node.annotation().kind == FunctionCallKind::StructConstructorCall)); - attributes.push_back(make_pair("type_conversion", _node.annotation().kind == FunctionCallKind::TypeConversion)); + attributes.emplace_back("isStructConstructorCall", _node.annotation().kind == FunctionCallKind::StructConstructorCall); + attributes.emplace_back("type_conversion", _node.annotation().kind == FunctionCallKind::TypeConversion); } else - attributes.push_back(make_pair("kind", functionCallKind(_node.annotation().kind))); + attributes.emplace_back("kind", functionCallKind(_node.annotation().kind)); appendExpressionAttributes(attributes, _node.annotation()); setJsonNode(_node, "FunctionCall", std::move(attributes)); return false; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index f5a38747..c35dde3c 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -125,6 +125,22 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2) return fitsPrecisionBaseX(_mantissa, 1.0, _expBase2); } +/// Checks whether _value fits into IntegerType _type. +bool fitsIntegerType(bigint const& _value, IntegerType const& _type) +{ + return (_type.minValue() <= _value) && (_value <= _type.maxValue()); +} + +/// Checks whether _value fits into _bits bits when having 1 bit as the sign bit +/// if _signed is true. +bool fitsIntoBits(bigint const& _value, unsigned _bits, bool _signed) +{ + return fitsIntegerType(_value, IntegerType( + _bits, + _signed ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned + )); +} + } void StorageOffsets::computeOffsets(TypePointers const& _types) @@ -446,7 +462,7 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition continue; FunctionTypePointer fun = FunctionType(*function, false).asCallableFunction(true, true); if (_type.isImplicitlyConvertibleTo(*fun->selfType())) - members.push_back(MemberList::Member(function->name(), fun, function)); + members.emplace_back(function->name(), fun, function); } } return members; @@ -963,27 +979,21 @@ BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) if (isFractional()) return false; IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo); - if (m_value == rational(0)) - return true; - unsigned forSignBit = (targetType.isSigned() ? 1 : 0); - if (m_value > rational(0)) - { - if (m_value.numerator() <= (u256(-1) >> (256 - targetType.numBits() + forSignBit))) - return true; - return false; - } - if (targetType.isSigned()) - { - if (-m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit))) - return true; - } - return false; + return fitsIntegerType(m_value.numerator(), targetType); } case Category::FixedPoint: { - if (auto fixed = fixedPointType()) - return fixed->isImplicitlyConvertibleTo(_convertTo); - return false; + FixedPointType const& targetType = dynamic_cast<FixedPointType const&>(_convertTo); + // Store a negative number into an unsigned. + if (isNegative() && !targetType.isSigned()) + return false; + if (!isFractional()) + return (targetType.minIntegerValue() <= m_value) && (m_value <= targetType.maxIntegerValue()); + rational value = m_value * pow(bigint(10), targetType.fractionalDigits()); + // Need explicit conversion since truncation will occur. + if (value.denominator() != 1) + return false; + return fitsIntoBits(value.numerator(), targetType.numBits(), targetType.isSigned()); } case Category::FixedBytes: return (m_value == rational(0)) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo); @@ -1811,23 +1821,23 @@ MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const MemberList::MemberMap members; if (!isString()) { - members.push_back({"length", make_shared<IntegerType>(256)}); + members.emplace_back("length", make_shared<IntegerType>(256)); if (isDynamicallySized() && location() == DataLocation::Storage) { - members.push_back({"push", make_shared<FunctionType>( + members.emplace_back("push", make_shared<FunctionType>( TypePointers{baseType()}, TypePointers{make_shared<IntegerType>(256)}, strings{string()}, strings{string()}, isByteArray() ? FunctionType::Kind::ByteArrayPush : FunctionType::Kind::ArrayPush - )}); - members.push_back({"pop", make_shared<FunctionType>( + )); + members.emplace_back("pop", make_shared<FunctionType>( TypePointers{}, TypePointers{}, strings{string()}, strings{string()}, FunctionType::Kind::ArrayPop - )}); + )); } } return members; @@ -1956,21 +1966,17 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con break; } if (!functionWithEqualArgumentsFound) - members.push_back(MemberList::Member( - function->name(), - functionType, - function - )); + members.emplace_back(function->name(), functionType, function); } } else if (!m_contract.isLibrary()) { for (auto const& it: m_contract.interfaceFunctions()) - members.push_back(MemberList::Member( + members.emplace_back( it.second->declaration().name(), it.second->asCallableFunction(m_contract.isLibrary()), &it.second->declaration() - )); + ); } return members; } @@ -1998,7 +2004,7 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar vector<tuple<VariableDeclaration const*, u256, unsigned>> variablesAndOffsets; for (size_t index = 0; index < variables.size(); ++index) if (auto const* offset = offsets.offset(index)) - variablesAndOffsets.push_back(make_tuple(variables[index], offset->first, offset->second)); + variablesAndOffsets.emplace_back(variables[index], offset->first, offset->second); return variablesAndOffsets; } @@ -2088,10 +2094,10 @@ MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const // Skip all mapping members if we are not in storage. if (location() != DataLocation::Storage && !type->canLiveOutsideStorage()) continue; - members.push_back(MemberList::Member( + members.emplace_back( variable->name(), copyForLocationIfReference(type), - variable.get()) + variable.get() ); } return members; @@ -2428,7 +2434,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get())) { m_parameterTypes.push_back(mappingType->keyType()); - m_parameterNames.push_back(""); + m_parameterNames.emplace_back(""); returnType = mappingType->valueType(); } else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get())) @@ -2437,7 +2443,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): // Return byte arrays as whole. break; returnType = arrayType->baseType(); - m_parameterNames.push_back(""); + m_parameterNames.emplace_back(""); m_parameterTypes.push_back(make_shared<IntegerType>(256)); } else @@ -2468,7 +2474,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): DataLocation::Memory, returnType )); - m_returnParameterNames.push_back(""); + m_returnParameterNames.emplace_back(""); } } @@ -2837,14 +2843,11 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con { MemberList::MemberMap members; if (m_kind == Kind::External) - members.push_back(MemberList::Member( - "selector", - make_shared<FixedBytesType>(4) - )); + members.emplace_back("selector", make_shared<FixedBytesType>(4)); if (m_kind != Kind::BareDelegateCall) { if (isPayable()) - members.push_back(MemberList::Member( + members.emplace_back( "value", make_shared<FunctionType>( parseElementaryTypeVector({"uint"}), @@ -2858,10 +2861,10 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con m_gasSet, m_valueSet ) - )); + ); } if (m_kind != Kind::Creation) - members.push_back(MemberList::Member( + members.emplace_back( "gas", make_shared<FunctionType>( parseElementaryTypeVector({"uint"}), @@ -2875,7 +2878,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con m_gasSet, m_valueSet ) - )); + ); return members; } default: @@ -3203,24 +3206,24 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current if (contract.isLibrary()) for (FunctionDefinition const* function: contract.definedFunctions()) if (function->isVisibleAsLibraryMember()) - members.push_back(MemberList::Member( + members.emplace_back( function->name(), FunctionType(*function).asCallableFunction(true), function - )); + ); if (isBase) { // We are accessing the type of a base contract, so add all public and protected // members. Note that this does not add inherited functions on purpose. for (Declaration const* decl: contract.inheritableMembers()) - members.push_back(MemberList::Member(decl->name(), decl->type(), decl)); + members.emplace_back(decl->name(), decl->type(), decl); } else { for (auto const& stru: contract.definedStructs()) - members.push_back(MemberList::Member(stru->name(), stru->type(), stru)); + members.emplace_back(stru->name(), stru->type(), stru); for (auto const& enu: contract.definedEnums()) - members.push_back(MemberList::Member(enu->name(), enu->type(), enu)); + members.emplace_back(enu->name(), enu->type(), enu); } } else if (m_actualType->category() == Category::Enum) @@ -3228,7 +3231,7 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current EnumDefinition const& enumDef = dynamic_cast<EnumType const&>(*m_actualType).enumDefinition(); auto enumType = make_shared<EnumType>(enumDef); for (ASTPointer<EnumValue> const& enumValue: enumDef.members()) - members.push_back(MemberList::Member(enumValue->name(), enumType)); + members.emplace_back(enumValue->name(), enumType); } return members; } @@ -3293,7 +3296,7 @@ MemberList::MemberMap ModuleType::nativeMembers(ContractDefinition const*) const MemberList::MemberMap symbols; for (auto const& symbolName: m_sourceUnit.annotation().exportedSymbols) for (Declaration const* symbol: symbolName.second) - symbols.push_back(MemberList::Member(symbolName.first, symbol->type(), symbol)); + symbols.emplace_back(symbolName.first, symbol->type(), symbol); return symbols; } diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index b02623de..5000131c 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -141,8 +141,8 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) vector<string> valueNamesLocal; for (size_t j = 0; j < sizeOnStack; j++) { - valueNamesLocal.push_back("value" + to_string(stackPos)); - valueReturnParams.push_back("value" + to_string(stackPos)); + valueNamesLocal.emplace_back("value" + to_string(stackPos)); + valueReturnParams.emplace_back("value" + to_string(stackPos)); stackPos++; } bool dynamic = decodingTypes[i]->isDynamicallyEncoded(); diff --git a/libsolidity/codegen/AsmCodeGen.cpp b/libsolidity/codegen/AsmCodeGen.cpp index dfcc900b..c04c1c34 100644 --- a/libsolidity/codegen/AsmCodeGen.cpp +++ b/libsolidity/codegen/AsmCodeGen.cpp @@ -179,14 +179,17 @@ void CodeGenerator::assemble( AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly, ExternalIdentifierAccess const& _identifierAccess, - bool _useNamedLabelsForFunctions + bool _useNamedLabelsForFunctions, + bool _optimize ) { EthAssemblyAdapter assemblyAdapter(_assembly); CodeTransform( assemblyAdapter, _analysisInfo, - false, + _parsedData, + *EVMDialect::strictAssemblyForEVM(), + _optimize, false, _identifierAccess, _useNamedLabelsForFunctions diff --git a/libsolidity/codegen/AsmCodeGen.h b/libsolidity/codegen/AsmCodeGen.h index 4c6d97f4..303d32ee 100644 --- a/libsolidity/codegen/AsmCodeGen.h +++ b/libsolidity/codegen/AsmCodeGen.h @@ -85,7 +85,8 @@ public: yul::AsmAnalysisInfo& _analysisInfo, dev::eth::Assembly& _assembly, yul::ExternalIdentifierAccess const& _identifierAccess = yul::ExternalIdentifierAccess(), - bool _useNamedLabelsForFunctions = false + bool _useNamedLabelsForFunctions = false, + bool _optimize = false ); }; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index dac09c2e..0b018e1e 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -31,6 +31,7 @@ #include <libyul/AsmAnalysis.h> #include <libyul/AsmAnalysisInfo.h> #include <libyul/YulString.h> +#include <libyul/backends/evm/EVMDialect.h> #include <liblangutil/ErrorReporter.h> #include <liblangutil/Scanner.h> @@ -361,7 +362,7 @@ void CompilerContext::appendInlineAssembly( ErrorList errors; ErrorReporter errorReporter(errors); auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--")); - auto parserResult = yul::Parser(errorReporter, yul::Dialect::strictAssemblyForEVM()).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, yul::EVMDialect::strictAssemblyForEVM()).parse(scanner, false); #ifdef SOL_OUTPUT_ASM cout << yul::AsmPrinter()(*parserResult) << endl; #endif @@ -373,7 +374,7 @@ void CompilerContext::appendInlineAssembly( errorReporter, m_evmVersion, boost::none, - yul::Dialect::strictAssemblyForEVM(), + yul::EVMDialect::strictAssemblyForEVM(), identifierAccess.resolve ).analyze(*parserResult); if (!parserResult || !errorReporter.errors().empty() || !analyzerResult) diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 7d2ad9d2..259f1620 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1205,7 +1205,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data) { //@todo provide both alternatives to the optimiser // stack: mempos - if (_data.size() <= 128) + if (_data.size() <= 32) { for (unsigned i = 0; i < _data.size(); i += 32) { diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 79c53a1c..67876721 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -721,14 +721,14 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); - m_breakTags.push_back({loopEnd, m_context.stackHeight()}); + m_breakTags.emplace_back(loopEnd, m_context.stackHeight()); m_context << loopStart; if (_whileStatement.isDoWhile()) { eth::AssemblyItem condition = m_context.newTag(); - m_continueTags.push_back({condition, m_context.stackHeight()}); + m_continueTags.emplace_back(condition, m_context.stackHeight()); _whileStatement.body().accept(*this); @@ -739,7 +739,7 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) } else { - m_continueTags.push_back({loopStart, m_context.stackHeight()}); + m_continueTags.emplace_back(loopStart, m_context.stackHeight()); compileExpression(_whileStatement.condition()); m_context << Instruction::ISZERO; m_context.appendConditionalJumpTo(loopEnd); @@ -770,8 +770,8 @@ bool ContractCompiler::visit(ForStatement const& _forStatement) if (_forStatement.initializationExpression()) _forStatement.initializationExpression()->accept(*this); - m_breakTags.push_back({loopEnd, m_context.stackHeight()}); - m_continueTags.push_back({loopNext, m_context.stackHeight()}); + m_breakTags.emplace_back(loopEnd, m_context.stackHeight()); + m_continueTags.emplace_back(loopNext, m_context.stackHeight()); m_context << loopStart; // if there is no terminating condition in for, default is to always be true @@ -997,7 +997,7 @@ void ContractCompiler::appendModifierOrFunctionCode() if (codeBlock) { - m_returnTags.push_back({m_context.newTag(), m_context.stackHeight()}); + m_returnTags.emplace_back(m_context.newTag(), m_context.stackHeight()); codeBlock->accept(*this); solAssert(!m_returnTags.empty(), ""); diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp index 17dc11ac..dc14f4c2 100644 --- a/libsolidity/formal/SMTChecker.cpp +++ b/libsolidity/formal/SMTChecker.cpp @@ -90,8 +90,7 @@ bool SMTChecker::visit(FunctionDefinition const& _function) m_interface->reset(); m_pathConditions.clear(); m_expressions.clear(); - m_specialVariables.clear(); - m_uninterpretedFunctions.clear(); + m_globalContext.clear(); m_uninterpretedTerms.clear(); resetStateVariables(); initializeLocalVariables(_function); @@ -268,16 +267,9 @@ void SMTChecker::endVisit(Assignment const& _assignment) else if (Identifier const* identifier = dynamic_cast<Identifier const*>(&_assignment.leftHandSide())) { VariableDeclaration const& decl = dynamic_cast<VariableDeclaration const&>(*identifier->annotation().referencedDeclaration); - if (knownVariable(decl)) - { - assignment(decl, _assignment.rightHandSide(), _assignment.location()); - defineExpr(_assignment, expr(_assignment.rightHandSide())); - } - else - m_errorReporter.warning( - _assignment.location(), - "Assertion checker does not yet implement such assignments." - ); + solAssert(knownVariable(decl), ""); + assignment(decl, _assignment.rightHandSide(), _assignment.location()); + defineExpr(_assignment, expr(_assignment.rightHandSide())); } else m_errorReporter.warning( @@ -288,7 +280,11 @@ void SMTChecker::endVisit(Assignment const& _assignment) void SMTChecker::endVisit(TupleExpression const& _tuple) { - if (_tuple.isInlineArray() || _tuple.components().size() != 1) + if ( + _tuple.isInlineArray() || + _tuple.components().size() != 1 || + !isSupportedType(_tuple.components()[0]->annotation().type->category()) + ) m_errorReporter.warning( _tuple.location(), "Assertion checker does not yet implement tuples and inline arrays." @@ -399,18 +395,30 @@ void SMTChecker::endVisit(FunctionCall const& _funCall) FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type); std::vector<ASTPointer<Expression const>> const args = _funCall.arguments(); - if (funType.kind() == FunctionType::Kind::Assert) + switch (funType.kind()) + { + case FunctionType::Kind::Assert: visitAssert(_funCall); - else if (funType.kind() == FunctionType::Kind::Require) + break; + case FunctionType::Kind::Require: visitRequire(_funCall); - else if (funType.kind() == FunctionType::Kind::GasLeft) + break; + case FunctionType::Kind::GasLeft: visitGasLeft(_funCall); - else if (funType.kind() == FunctionType::Kind::BlockHash) - visitBlockHash(_funCall); - else if (funType.kind() == FunctionType::Kind::Internal) + break; + case FunctionType::Kind::Internal: inlineFunctionCall(_funCall); - else - { + break; + case FunctionType::Kind::KECCAK256: + case FunctionType::Kind::ECRecover: + case FunctionType::Kind::SHA256: + case FunctionType::Kind::RIPEMD160: + case FunctionType::Kind::BlockHash: + case FunctionType::Kind::AddMod: + case FunctionType::Kind::MulMod: + abstractFunctionCall(_funCall); + break; + default: m_errorReporter.warning( _funCall.location(), "Assertion checker does not yet implement this type of function call." @@ -442,8 +450,8 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall) string gasLeft = "gasleft()"; // We increase the variable index since gasleft changes // inside a tx. - defineSpecialVariable(gasLeft, _funCall, true); - auto const& symbolicVar = m_specialVariables.at(gasLeft); + defineGlobalVariable(gasLeft, _funCall, true); + auto const& symbolicVar = m_globalContext.at(gasLeft); unsigned index = symbolicVar->index(); // We set the current value to unknown anyway to add type constraints. setUnknownValue(*symbolicVar); @@ -451,21 +459,6 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall) m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1)); } -void SMTChecker::visitBlockHash(FunctionCall const& _funCall) -{ - string blockHash = "blockhash"; - auto const& arguments = _funCall.arguments(); - solAssert(arguments.size() == 1, ""); - smt::SortPointer paramSort = smtSort(*arguments.at(0)->annotation().type); - smt::SortPointer returnSort = smtSort(*_funCall.annotation().type); - defineUninterpretedFunction( - blockHash, - make_shared<smt::FunctionSort>(vector<smt::SortPointer>{paramSort}, returnSort) - ); - defineExpr(_funCall, m_uninterpretedFunctions.at(blockHash)({expr(*arguments.at(0))})); - m_uninterpretedTerms.push_back(&_funCall); -} - void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall) { FunctionDefinition const* _funDef = nullptr; @@ -533,29 +526,32 @@ void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall) } } +void SMTChecker::abstractFunctionCall(FunctionCall const& _funCall) +{ + vector<smt::Expression> smtArguments; + for (auto const& arg: _funCall.arguments()) + smtArguments.push_back(expr(*arg)); + defineExpr(_funCall, (*m_expressions.at(&_funCall.expression()))(smtArguments)); + m_uninterpretedTerms.push_back(&_funCall); + setSymbolicUnknownValue(expr(_funCall), _funCall.annotation().type, *m_interface); +} + void SMTChecker::endVisit(Identifier const& _identifier) { if (_identifier.annotation().lValueRequested) { // Will be translated as part of the node that requested the lvalue. } - else if (FunctionType const* fun = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get())) + else if (dynamic_cast<FunctionType const*>(_identifier.annotation().type.get())) { - if ( - fun->kind() == FunctionType::Kind::Assert || - fun->kind() == FunctionType::Kind::Require || - fun->kind() == FunctionType::Kind::GasLeft || - fun->kind() == FunctionType::Kind::BlockHash - ) - return; - createExpr(_identifier); + visitFunctionIdentifier(_identifier); } else if (isSupportedType(_identifier.annotation().type->category())) { if (VariableDeclaration const* decl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration)) defineExpr(_identifier, currentValue(*decl)); else if (_identifier.name() == "now") - defineSpecialVariable(_identifier.name(), _identifier); + defineGlobalVariable(_identifier.name(), _identifier); else // TODO: handle MagicVariableDeclaration here m_errorReporter.warning( @@ -565,6 +561,20 @@ void SMTChecker::endVisit(Identifier const& _identifier) } } +void SMTChecker::visitFunctionIdentifier(Identifier const& _identifier) +{ + auto const& fType = dynamic_cast<FunctionType const&>(*_identifier.annotation().type); + if (fType.returnParameterTypes().size() > 1) + { + m_errorReporter.warning( + _identifier.location(), + "Assertion checker does not yet support functions with more than one return parameter." + ); + } + defineGlobalFunction(fType.richIdentifier(), _identifier); + m_expressions.emplace(&_identifier, m_globalContext.at(fType.richIdentifier())); +} + void SMTChecker::endVisit(Literal const& _literal) { Type const& type = *_literal.annotation().type; @@ -616,7 +626,7 @@ bool SMTChecker::visit(MemberAccess const& _memberAccess) _memberAccess.location(), "Assertion checker does not yet support this expression." ); - defineSpecialVariable(accessedName + "." + _memberAccess.memberName(), _memberAccess); + defineGlobalVariable(accessedName + "." + _memberAccess.memberName(), _memberAccess); return false; } else @@ -628,30 +638,39 @@ bool SMTChecker::visit(MemberAccess const& _memberAccess) return true; } -void SMTChecker::defineSpecialVariable(string const& _name, Expression const& _expr, bool _increaseIndex) +void SMTChecker::defineGlobalVariable(string const& _name, Expression const& _expr, bool _increaseIndex) { - if (!knownSpecialVariable(_name)) + if (!knownGlobalSymbol(_name)) { auto result = newSymbolicVariable(*_expr.annotation().type, _name, *m_interface); - m_specialVariables.emplace(_name, result.second); + m_globalContext.emplace(_name, result.second); setUnknownValue(*result.second); if (result.first) m_errorReporter.warning( _expr.location(), - "Assertion checker does not yet support this special variable." + "Assertion checker does not yet support this global variable." ); } else if (_increaseIndex) - m_specialVariables.at(_name)->increaseIndex(); + m_globalContext.at(_name)->increaseIndex(); // The default behavior is not to increase the index since - // most of the special values stay the same throughout a tx. - defineExpr(_expr, m_specialVariables.at(_name)->currentValue()); + // most of the global values stay the same throughout a tx. + if (isSupportedType(_expr.annotation().type->category())) + defineExpr(_expr, m_globalContext.at(_name)->currentValue()); } -void SMTChecker::defineUninterpretedFunction(string const& _name, smt::SortPointer _sort) +void SMTChecker::defineGlobalFunction(string const& _name, Expression const& _expr) { - if (!m_uninterpretedFunctions.count(_name)) - m_uninterpretedFunctions.emplace(_name, m_interface->newVariable(_name, _sort)); + if (!knownGlobalSymbol(_name)) + { + auto result = newSymbolicVariable(*_expr.annotation().type, _name, *m_interface); + m_globalContext.emplace(_name, result.second); + if (result.first) + m_errorReporter.warning( + _expr.location(), + "Assertion checker does not yet support the type of this function." + ); + } } void SMTChecker::arithmeticOperation(BinaryOperation const& _op) @@ -831,10 +850,13 @@ void SMTChecker::checkCondition( expressionsToEvaluate.emplace_back(currentValue(*var.first)); expressionNames.push_back(var.first->name()); } - for (auto const& var: m_specialVariables) + for (auto const& var: m_globalContext) { - expressionsToEvaluate.emplace_back(var.second->currentValue()); - expressionNames.push_back(var.first); + if (smtKind(var.second->type()->category()) != smt::Kind::Function) + { + expressionsToEvaluate.emplace_back(var.second->currentValue()); + expressionNames.push_back(var.first); + } } for (auto const& uf: m_uninterpretedTerms) { @@ -1147,9 +1169,9 @@ bool SMTChecker::knownExpr(Expression const& _e) const return m_expressions.count(&_e); } -bool SMTChecker::knownSpecialVariable(string const& _var) const +bool SMTChecker::knownGlobalSymbol(string const& _var) const { - return m_specialVariables.count(_var); + return m_globalContext.count(_var); } void SMTChecker::createExpr(Expression const& _e) @@ -1172,6 +1194,7 @@ void SMTChecker::createExpr(Expression const& _e) void SMTChecker::defineExpr(Expression const& _e, smt::Expression _value) { createExpr(_e); + solAssert(isSupportedType(*_e.annotation().type), "Equality operator applied to type that is not fully supported"); m_interface->addAssertion(expr(_e) == _value); } diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h index 34724848..9f8c04ab 100644 --- a/libsolidity/formal/SMTChecker.h +++ b/libsolidity/formal/SMTChecker.h @@ -84,16 +84,18 @@ private: void compareOperation(BinaryOperation const& _op); void booleanOperation(BinaryOperation const& _op); - void visitAssert(FunctionCall const&); - void visitRequire(FunctionCall const&); - void visitGasLeft(FunctionCall const&); - void visitBlockHash(FunctionCall const&); + void visitAssert(FunctionCall const& _funCall); + void visitRequire(FunctionCall const& _funCall); + void visitGasLeft(FunctionCall const& _funCall); /// Visits the FunctionDefinition of the called function /// if available and inlines the return value. - void inlineFunctionCall(FunctionCall const&); + void inlineFunctionCall(FunctionCall const& _funCall); + /// Creates an uninterpreted function call. + void abstractFunctionCall(FunctionCall const& _funCall); + void visitFunctionIdentifier(Identifier const& _identifier); - void defineSpecialVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false); - void defineUninterpretedFunction(std::string const& _name, smt::SortPointer _sort); + void defineGlobalVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false); + void defineGlobalFunction(std::string const& _name, Expression const& _expr); /// Division expression in the given type. Requires special treatment because /// of rounding for signed division. @@ -176,8 +178,8 @@ private: /// Creates the expression and sets its value. void defineExpr(Expression const& _e, smt::Expression _value); - /// Checks if special variable was seen. - bool knownSpecialVariable(std::string const& _var) const; + /// Checks if special variable or function was seen. + bool knownGlobalSymbol(std::string const& _var) const; /// Adds a new path condition void pushPathCondition(smt::Expression const& _e); @@ -205,9 +207,7 @@ private: /// repeated calls to the same function. std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions; std::unordered_map<VariableDeclaration const*, std::shared_ptr<SymbolicVariable>> m_variables; - std::unordered_map<std::string, std::shared_ptr<SymbolicVariable>> m_specialVariables; - /// Stores the declaration of an Uninterpreted Function. - std::unordered_map<std::string, smt::Expression> m_uninterpretedFunctions; + std::unordered_map<std::string, std::shared_ptr<SymbolicVariable>> m_globalContext; /// Stores the instances of an Uninterpreted Function applied to arguments. /// Used to retrieve models. std::vector<Expression const*> m_uninterpretedTerms; diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index c297c807..3cfaa271 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -38,15 +38,25 @@ smt::SortPointer dev::solidity::smtSort(Type const& _type) solAssert(fType, ""); vector<smt::SortPointer> parameterSorts = smtSort(fType->parameterTypes()); auto returnTypes = fType->returnParameterTypes(); - // TODO remove this when we support tuples. - solAssert(returnTypes.size() == 1, ""); - smt::SortPointer returnSort = smtSort(*returnTypes.at(0)); + smt::SortPointer returnSort; + // TODO change this when we support tuples. + if (returnTypes.size() == 0) + // We cannot declare functions without a return sort, so we use the smallest. + returnSort = make_shared<smt::Sort>(smt::Kind::Bool); + else if (returnTypes.size() > 1) + // Abstract sort. + returnSort = make_shared<smt::Sort>(smt::Kind::Int); + else + returnSort = smtSort(*returnTypes.at(0)); return make_shared<smt::FunctionSort>(parameterSorts, returnSort); } case smt::Kind::Array: { solUnimplementedAssert(false, "Invalid type"); } + default: + // Abstract case. + return make_shared<smt::Sort>(smt::Kind::Int); } solAssert(false, "Invalid type"); } @@ -65,13 +75,21 @@ smt::Kind dev::solidity::smtKind(Type::Category _category) return smt::Kind::Int; else if (isBool(_category)) return smt::Kind::Bool; - solAssert(false, "Invalid type"); + else if (isFunction(_category)) + return smt::Kind::Function; + // Abstract case. + return smt::Kind::Int; } bool dev::solidity::isSupportedType(Type::Category _category) { return isNumber(_category) || - isBool(_category) || + isBool(_category); +} + +bool dev::solidity::isSupportedTypeDeclaration(Type::Category _category) +{ + return isSupportedType(_category) || isFunction(_category); } @@ -84,7 +102,7 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable( bool abstract = false; shared_ptr<SymbolicVariable> var; TypePointer type = _type.shared_from_this(); - if (!isSupportedType(_type)) + if (!isSupportedTypeDeclaration(_type)) { abstract = true; var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver); @@ -92,7 +110,7 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable( else if (isBool(_type.category())) var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _solver); else if (isFunction(_type.category())) - var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver); + var = make_shared<SymbolicFunctionVariable>(type, _uniqueName, _solver); else if (isInteger(_type.category())) var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver); else if (isFixedBytes(_type.category())) @@ -122,6 +140,11 @@ bool dev::solidity::isSupportedType(Type const& _type) return isSupportedType(_type.category()); } +bool dev::solidity::isSupportedTypeDeclaration(Type const& _type) +{ + return isSupportedTypeDeclaration(_type.category()); +} + bool dev::solidity::isInteger(Type::Category _category) { return _category == Type::Category::Integer; diff --git a/libsolidity/formal/SymbolicTypes.h b/libsolidity/formal/SymbolicTypes.h index 984653b3..2c568f5b 100644 --- a/libsolidity/formal/SymbolicTypes.h +++ b/libsolidity/formal/SymbolicTypes.h @@ -34,10 +34,12 @@ std::vector<smt::SortPointer> smtSort(std::vector<TypePointer> const& _types); /// Returns the SMT kind that models the Solidity type type category _category. smt::Kind smtKind(Type::Category _category); -/// So far int, bool and address are supported. -/// Returns true if type is supported. +/// Returns true if type is fully supported (declaration and operations). bool isSupportedType(Type::Category _category); bool isSupportedType(Type const& _type); +/// Returns true if type is partially supported (declaration). +bool isSupportedTypeDeclaration(Type::Category _category); +bool isSupportedTypeDeclaration(Type const& _type); bool isInteger(Type::Category _category); bool isRational(Type::Category _category); diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp index fbfb3472..b97e00ae 100644 --- a/libsolidity/interface/AssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -32,6 +32,7 @@ #include <libyul/backends/evm/EVMObjectCompiler.h> #include <libyul/backends/evm/EVMCodeTransform.h> #include <libyul/backends/evm/EVMAssembly.h> +#include <libyul/backends/evm/EVMDialect.h> #include <libyul/ObjectParser.h> #include <libevmasm/Assembly.h> @@ -45,14 +46,14 @@ using namespace dev::solidity; namespace { -yul::Dialect languageToDialect(AssemblyStack::Language _language) +shared_ptr<yul::Dialect> languageToDialect(AssemblyStack::Language _language) { switch (_language) { case AssemblyStack::Language::Assembly: - return yul::Dialect::looseAssemblyForEVM(); + return yul::EVMDialect::looseAssemblyForEVM(); case AssemblyStack::Language::StrictAssembly: - return yul::Dialect::strictAssemblyForEVMObjects(); + return yul::EVMDialect::strictAssemblyForEVMObjects(); case AssemblyStack::Language::Yul: return yul::Dialect::yul(); } @@ -112,6 +113,22 @@ bool AssemblyStack::analyzeParsed(yul::Object& _object) return success; } +void AssemblyStack::compileEVM(yul::AbstractAssembly& _assembly, bool _evm15, bool _optimize) const +{ + shared_ptr<yul::EVMDialect> dialect; + + if (m_language == Language::Assembly) + dialect = yul::EVMDialect::looseAssemblyForEVM(); + else if (m_language == AssemblyStack::Language::StrictAssembly) + dialect = yul::EVMDialect::strictAssemblyForEVMObjects(); + else if (m_language == AssemblyStack::Language::Yul) + dialect = yul::EVMDialect::yulForEVM(); + else + solAssert(false, "Invalid language."); + + yul::EVMObjectCompiler::compile(*m_parserResult, _assembly, *dialect, _evm15, _optimize); +} + void AssemblyStack::optimize(yul::Object& _object) { solAssert(_object.code, ""); @@ -122,7 +139,7 @@ void AssemblyStack::optimize(yul::Object& _object) yul::OptimiserSuite::run(*_object.code, *_object.analysisInfo); } -MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const +MachineAssemblyObject AssemblyStack::assemble(Machine _machine, bool _optimize) const { solAssert(m_analysisSuccessful, ""); solAssert(m_parserResult, ""); @@ -136,7 +153,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const MachineAssemblyObject object; eth::Assembly assembly; EthAssemblyAdapter adapter(assembly); - yul::EVMObjectCompiler::compile(*m_parserResult, adapter, m_language == Language::Yul, false); + compileEVM(adapter, false, _optimize); object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble()); object.assembly = assembly.assemblyString(); return object; @@ -145,7 +162,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const { MachineAssemblyObject object; yul::EVMAssembly assembly(true); - yul::EVMObjectCompiler::compile(*m_parserResult, assembly, m_language == Language::Yul, true); + compileEVM(assembly, true, _optimize); object.bytecode = make_shared<eth::LinkerObject>(assembly.finalize()); /// TODO: fill out text representation return object; diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h index 485ec1e7..c8e3d35a 100644 --- a/libsolidity/interface/AssemblyStack.h +++ b/libsolidity/interface/AssemblyStack.h @@ -36,6 +36,10 @@ namespace langutil { class Scanner; } +namespace yul +{ +class AbstractAssembly; +} namespace dev { @@ -73,7 +77,8 @@ public: void optimize(); /// Run the assembly step (should only be called after parseAndAnalyze). - MachineAssemblyObject assemble(Machine _machine) const; + /// @param _optimize does not run the optimizer but performs optimized code generation. + MachineAssemblyObject assemble(Machine _machine, bool _optimize = false) const; /// @returns the errors generated during parsing, analysis (and potentially assembly). langutil::ErrorList const& errors() const { return m_errors; } @@ -85,6 +90,8 @@ private: bool analyzeParsed(); bool analyzeParsed(yul::Object& _object); + void compileEVM(yul::AbstractAssembly& _assembly, bool _evm15, bool _optimize) const; + void optimize(yul::Object& _object); Language m_language = Language::Assembly; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 6cab7be3..26f13f93 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -24,6 +24,7 @@ #include <vector> #include <libsolidity/parsing/Parser.h> #include <libyul/AsmParser.h> +#include <libyul/backends/evm/EVMDialect.h> #include <liblangutil/SourceLocation.h> #include <liblangutil/ErrorReporter.h> #include <liblangutil/Scanner.h> @@ -170,7 +171,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective() expectToken(Token::As); alias = expectIdentifierToken(); } - symbolAliases.push_back(make_pair(move(id), move(alias))); + symbolAliases.emplace_back(move(id), move(alias)); if (m_scanner->currentToken() != Token::Comma) break; m_scanner->next(); @@ -1012,7 +1013,7 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con m_scanner->next(); } - yul::Parser asmParser(m_errorReporter); + yul::Parser asmParser(m_errorReporter, yul::EVMDialect::looseAssemblyForEVM()); shared_ptr<yul::Block> block = asmParser.parse(m_scanner, true); nodeFactory.markEndPosition(); return nodeFactory.createNode<InlineAssembly>(_docString, block); @@ -1690,7 +1691,7 @@ Parser::IndexAccessedPath Parser::parseIndexAccessedPath() index = parseExpression(); SourceLocation indexLocation = iap.path.front()->location(); indexLocation.end = endPosition(); - iap.indices.push_back(make_pair(index, indexLocation)); + iap.indices.emplace_back(index, indexLocation); expectToken(Token::RBrack); } |