aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/analysis/ContractLevelChecker.cpp10
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp3
-rw-r--r--libsolidity/analysis/TypeChecker.cpp80
-rw-r--r--libsolidity/ast/AST.cpp2
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp12
-rw-r--r--libsolidity/ast/Types.cpp107
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp4
-rw-r--r--libsolidity/codegen/AsmCodeGen.cpp7
-rw-r--r--libsolidity/codegen/AsmCodeGen.h3
-rw-r--r--libsolidity/codegen/CompilerContext.cpp5
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp12
-rw-r--r--libsolidity/formal/SMTChecker.cpp151
-rw-r--r--libsolidity/formal/SMTChecker.h24
-rw-r--r--libsolidity/formal/SymbolicTypes.cpp37
-rw-r--r--libsolidity/formal/SymbolicTypes.h6
-rw-r--r--libsolidity/interface/AssemblyStack.cpp29
-rw-r--r--libsolidity/interface/AssemblyStack.h9
-rw-r--r--libsolidity/parsing/Parser.cpp7
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);
}