mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9208 from ethereum/develop
Merge develop into breaking.
This commit is contained in:
commit
71cb7551f4
@ -28,11 +28,11 @@ Language Features:
|
||||
|
||||
Compiler Features:
|
||||
* NatSpec: Add fields "kind" and "version" to the JSON output.
|
||||
* Commandline Interface: Prevent some incompatible commandline options from being used together.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
||||
|
||||
* NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments.
|
||||
|
||||
|
||||
### 0.6.10 (2020-06-11)
|
||||
|
@ -314,6 +314,16 @@ you should fork Solidity and add your personal fork as a second remote:
|
||||
|
||||
git remote add personal git@github.com:[username]/solidity.git
|
||||
|
||||
.. note::
|
||||
This method will result in a prerelease build leading to e.g. a flag
|
||||
being set in each bytecode produced by such a compiler.
|
||||
If you want to re-build a released Solidity compiler, then
|
||||
please use the source tarball on the github release page:
|
||||
|
||||
https://github.com/ethereum/solidity/releases/download/v0.X.Y/solidity_0.X.Y.tar.gz
|
||||
|
||||
(not the "Source code" provided by github).
|
||||
|
||||
Command-Line Build
|
||||
------------------
|
||||
|
||||
|
@ -313,7 +313,6 @@ size_t Scanner::scanSingleLineDocComment()
|
||||
{
|
||||
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
|
||||
size_t endPosition = m_source->position();
|
||||
advance(); //consume the last '/' at ///
|
||||
|
||||
skipWhitespaceExceptUnicodeLinebreak();
|
||||
|
||||
@ -332,6 +331,8 @@ size_t Scanner::scanSingleLineDocComment()
|
||||
m_source->get(1) == '/' &&
|
||||
m_source->get(2) == '/')
|
||||
{
|
||||
if (!m_source->isPastEndOfInput(4) && m_source->get(3) == '/')
|
||||
break; // "////" is not a documentation comment
|
||||
m_char = m_source->advanceAndGet(3);
|
||||
if (atEndOfLine())
|
||||
continue;
|
||||
@ -353,7 +354,6 @@ size_t Scanner::scanSingleLineDocComment()
|
||||
|
||||
Token Scanner::skipMultiLineComment()
|
||||
{
|
||||
advance();
|
||||
while (!isSourcePastEndOfInput())
|
||||
{
|
||||
char ch = m_char;
|
||||
@ -437,6 +437,11 @@ Token Scanner::scanSlash()
|
||||
return Token::Whitespace;
|
||||
else if (m_char == '/')
|
||||
{
|
||||
advance(); //consume the last '/' at ///
|
||||
|
||||
// "////"
|
||||
if (m_char == '/')
|
||||
return skipSingleLineComment();
|
||||
// doxygen style /// comment
|
||||
m_skippedComments[NextNext].location.start = firstSlashPosition;
|
||||
m_skippedComments[NextNext].location.source = m_source;
|
||||
@ -462,11 +467,14 @@ Token Scanner::scanSlash()
|
||||
advance(); //skip the closing slash
|
||||
return Token::Whitespace;
|
||||
}
|
||||
// "/***"
|
||||
if (m_char == '*')
|
||||
// "/***/" may be interpreted as empty natspec or skipped; skipping is simpler
|
||||
return skipMultiLineComment();
|
||||
// we actually have a multiline documentation comment
|
||||
Token comment;
|
||||
m_skippedComments[NextNext].location.start = firstSlashPosition;
|
||||
m_skippedComments[NextNext].location.source = m_source;
|
||||
comment = scanMultiLineDocComment();
|
||||
Token comment = scanMultiLineDocComment();
|
||||
m_skippedComments[NextNext].location.end = static_cast<int>(sourcePos());
|
||||
m_skippedComments[NextNext].token = comment;
|
||||
if (comment == Token::Illegal)
|
||||
@ -754,17 +762,16 @@ bool Scanner::isUnicodeLinebreak()
|
||||
if (0x0a <= m_char && m_char <= 0x0d)
|
||||
// line feed, vertical tab, form feed, carriage return
|
||||
return true;
|
||||
else if (!m_source->isPastEndOfInput(1) && uint8_t(m_source->get(0)) == 0xc2 && uint8_t(m_source->get(1)) == 0x85)
|
||||
if (!m_source->isPastEndOfInput(1) && uint8_t(m_source->get(0)) == 0xc2 && uint8_t(m_source->get(1)) == 0x85)
|
||||
// NEL - U+0085, C2 85 in utf8
|
||||
return true;
|
||||
else if (!m_source->isPastEndOfInput(2) && uint8_t(m_source->get(0)) == 0xe2 && uint8_t(m_source->get(1)) == 0x80 && (
|
||||
if (!m_source->isPastEndOfInput(2) && uint8_t(m_source->get(0)) == 0xe2 && uint8_t(m_source->get(1)) == 0x80 && (
|
||||
uint8_t(m_source->get(2)) == 0xa8 || uint8_t(m_source->get(2)) == 0xa9
|
||||
))
|
||||
// LS - U+2028, E2 80 A8 in utf8
|
||||
// PS - U+2029, E2 80 A9 in utf8
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Token Scanner::scanString()
|
||||
|
@ -123,11 +123,13 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
|
||||
return !error;
|
||||
}
|
||||
|
||||
bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode)
|
||||
bool NameAndTypeResolver::resolveNamesAndTypes(SourceUnit& _source)
|
||||
{
|
||||
try
|
||||
{
|
||||
return resolveNamesAndTypesInternal(_node, _resolveInsideCode);
|
||||
for (shared_ptr<ASTNode> const& node: _source.nodes())
|
||||
if (!resolveNamesAndTypesInternal(*node, true))
|
||||
return false;
|
||||
}
|
||||
catch (langutil::FatalError const&)
|
||||
{
|
||||
@ -135,6 +137,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsi
|
||||
throw; // Something is weird here, rather throw again.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
||||
@ -227,13 +230,14 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res
|
||||
bool success = true;
|
||||
setScope(contract->scope());
|
||||
solAssert(!!m_currentScope, "");
|
||||
solAssert(_resolveInsideCode, "");
|
||||
|
||||
m_globalContext.setCurrentContract(*contract);
|
||||
updateDeclaration(*m_globalContext.currentSuper());
|
||||
updateDeclaration(*m_globalContext.currentThis());
|
||||
|
||||
for (ASTPointer<InheritanceSpecifier> const& baseContract: contract->baseContracts())
|
||||
if (!resolveNamesAndTypes(*baseContract, true))
|
||||
if (!resolveNamesAndTypesInternal(*baseContract, true))
|
||||
success = false;
|
||||
|
||||
setScope(contract);
|
||||
@ -254,23 +258,20 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res
|
||||
for (ASTPointer<ASTNode> const& node: contract->subNodes())
|
||||
{
|
||||
setScope(contract);
|
||||
if (!resolveNamesAndTypes(*node, false))
|
||||
if (!resolveNamesAndTypesInternal(*node, false))
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
if (!_resolveInsideCode)
|
||||
return success;
|
||||
|
||||
setScope(contract);
|
||||
|
||||
// now resolve references inside the code
|
||||
for (ASTPointer<ASTNode> const& node: contract->subNodes())
|
||||
{
|
||||
setScope(contract);
|
||||
if (!resolveNamesAndTypes(*node, true))
|
||||
if (!resolveNamesAndTypesInternal(*node, true))
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
|
@ -65,12 +65,9 @@ public:
|
||||
bool registerDeclarations(SourceUnit& _sourceUnit, ASTNode const* _currentScope = nullptr);
|
||||
/// Applies the effect of import directives.
|
||||
bool performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits);
|
||||
/// Resolves all names and types referenced from the given AST Node.
|
||||
/// This is usually only called at the contract level, but with a bit of care, it can also
|
||||
/// be called at deeper levels.
|
||||
/// @param _resolveInsideCode if false, does not descend into nodes that contain code.
|
||||
/// Resolves all names and types referenced from the given Source Node.
|
||||
/// @returns false in case of error.
|
||||
bool resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode = true);
|
||||
bool resolveNamesAndTypes(SourceUnit& _source);
|
||||
/// Updates the given global declaration (used for "this"). Not to be used with declarations
|
||||
/// that create their own scope.
|
||||
/// @returns false in case of error.
|
||||
|
@ -62,9 +62,11 @@ bool TypeChecker::typeSupportedByOldABIEncoder(Type const& _type, bool _isLibrar
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeChecker::checkTypeRequirements(ASTNode const& _contract)
|
||||
bool TypeChecker::checkTypeRequirements(SourceUnit const& _source)
|
||||
{
|
||||
_contract.accept(*this);
|
||||
m_currentSourceUnit = &_source;
|
||||
_source.accept(*this);
|
||||
m_currentSourceUnit = nullptr;
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
@ -375,7 +377,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
}
|
||||
if (
|
||||
_function.isPublic() &&
|
||||
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!typeSupportedByOldABIEncoder(*type(var), _function.libraryFunction())
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
@ -513,7 +515,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
else if (_variable.visibility() >= Visibility::Public)
|
||||
{
|
||||
FunctionType getter(_variable);
|
||||
if (!_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
|
||||
if (!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2))
|
||||
{
|
||||
vector<string> unsupportedTypes;
|
||||
for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
|
||||
@ -624,7 +626,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
||||
if (!type(*var)->interfaceType(false))
|
||||
m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
||||
if (
|
||||
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!typeSupportedByOldABIEncoder(*type(*var), false /* isLibrary */)
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
@ -668,17 +670,18 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||
return numeric_limits<size_t>::max();
|
||||
Declaration const* declaration = ref->second.declaration;
|
||||
return false;
|
||||
InlineAssemblyAnnotation::ExternalIdentifierInfo& identifierInfo = ref->second;
|
||||
Declaration const* declaration = identifierInfo.declaration;
|
||||
solAssert(!!declaration, "");
|
||||
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
|
||||
bool requiresStorage = identifierInfo.isSlot || identifierInfo.isOffset;
|
||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
{
|
||||
solAssert(var->type(), "Expected variable type!");
|
||||
if (var->immutable())
|
||||
{
|
||||
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
if (var->isConstant())
|
||||
{
|
||||
@ -687,17 +690,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (var && !var->value())
|
||||
{
|
||||
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (requiresStorage)
|
||||
{
|
||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||
{
|
||||
@ -706,7 +709,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
_identifier.location,
|
||||
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
|
||||
);
|
||||
return size_t(-1);
|
||||
return false;
|
||||
}
|
||||
else if (!var || !type(*var)->isValueType() || (
|
||||
!dynamic_cast<Literal const*>(var->value().get()) &&
|
||||
@ -714,7 +717,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
))
|
||||
{
|
||||
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
|
||||
return size_t(-1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -725,33 +728,33 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
if (var->isStateVariable())
|
||||
{
|
||||
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (ref->second.isOffset)
|
||||
else if (identifierInfo.isOffset)
|
||||
{
|
||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
solAssert(ref->second.isSlot, "");
|
||||
solAssert(identifierInfo.isSlot, "");
|
||||
}
|
||||
}
|
||||
else if (!var->isConstant() && var->isStateVariable())
|
||||
{
|
||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (var->type()->sizeOnStack() != 1)
|
||||
{
|
||||
@ -759,21 +762,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
|
||||
else
|
||||
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (requiresStorage)
|
||||
{
|
||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
|
||||
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_context == yul::IdentifierContext::RValue)
|
||||
@ -782,7 +785,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
||||
{
|
||||
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
{
|
||||
@ -792,14 +795,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (!contract->isLibrary())
|
||||
{
|
||||
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
return numeric_limits<size_t>::max();
|
||||
return false;
|
||||
}
|
||||
ref->second.valueSize = 1;
|
||||
return size_t(1);
|
||||
identifierInfo.valueSize = 1;
|
||||
return true;
|
||||
};
|
||||
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
|
||||
_inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
|
||||
@ -1914,9 +1917,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
|
||||
bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked;
|
||||
solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding");
|
||||
|
||||
bool const abiEncoderV2 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
|
||||
ExperimentalFeature::ABIEncoderV2
|
||||
);
|
||||
bool const abiEncoderV2 = experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2);
|
||||
|
||||
// Check for named arguments
|
||||
if (!_functionCall.names().empty())
|
||||
@ -2313,11 +2314,10 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
case FunctionType::Kind::ABIDecode:
|
||||
{
|
||||
bool const abiEncoderV2 =
|
||||
m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
|
||||
ExperimentalFeature::ABIEncoderV2
|
||||
);
|
||||
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
|
||||
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(
|
||||
_functionCall,
|
||||
experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::ABIEncode:
|
||||
@ -3272,3 +3272,11 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
|
||||
|
||||
m_errorReporter.typeError(errorId, _expression.location(), description);
|
||||
}
|
||||
|
||||
bool TypeChecker::experimentalFeatureActive(ExperimentalFeature _feature) const
|
||||
{
|
||||
solAssert(m_currentSourceUnit, "");
|
||||
if (m_currentContract)
|
||||
solAssert(m_currentSourceUnit == &m_currentContract->sourceUnit(), "");
|
||||
return m_currentSourceUnit->annotation().experimentalFeatures.count(_feature);
|
||||
}
|
||||
|
@ -51,9 +51,9 @@ public:
|
||||
m_errorReporter(_errorReporter)
|
||||
{}
|
||||
|
||||
/// Performs type checking on the given contract and all of its sub-nodes.
|
||||
/// Performs type checking on the given source and all of its sub-nodes.
|
||||
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||
bool checkTypeRequirements(ASTNode const& _contract);
|
||||
bool checkTypeRequirements(SourceUnit const& _source);
|
||||
|
||||
/// @returns the type of an expression and asserts that it is present.
|
||||
TypePointer const& type(Expression const& _expression) const;
|
||||
@ -165,6 +165,9 @@ private:
|
||||
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
|
||||
void requireLValue(Expression const& _expression, bool _ordinaryAssignment);
|
||||
|
||||
bool experimentalFeatureActive(ExperimentalFeature _feature) const;
|
||||
|
||||
SourceUnit const* m_currentSourceUnit = nullptr;
|
||||
ContractDefinition const* m_currentContract = nullptr;
|
||||
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
|
@ -311,10 +311,15 @@ TypePointer Type::commonType(Type const* _a, Type const* _b)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MemberList const& Type::members(ContractDefinition const* _currentScope) const
|
||||
MemberList const& Type::members(ASTNode const* _currentScope) const
|
||||
{
|
||||
if (!m_members[_currentScope])
|
||||
{
|
||||
solAssert(
|
||||
_currentScope == nullptr ||
|
||||
dynamic_cast<SourceUnit const*>(_currentScope) ||
|
||||
dynamic_cast<ContractDefinition const*>(_currentScope),
|
||||
"");
|
||||
MemberList::MemberMap members = nativeMembers(_currentScope);
|
||||
if (_currentScope)
|
||||
members += boundFunctions(*this, *_currentScope);
|
||||
@ -344,8 +349,20 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
|
||||
return encodingType;
|
||||
}
|
||||
|
||||
MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope)
|
||||
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
|
||||
{
|
||||
vector<UsingForDirective const*> usingForDirectives;
|
||||
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope))
|
||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
||||
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
|
||||
{
|
||||
for (ContractDefinition const* contract: contract->annotation().linearizedBaseContracts)
|
||||
usingForDirectives += contract->usingForDirectives();
|
||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
// Normalise data location of type.
|
||||
DataLocation typeLocation = DataLocation::Storage;
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
||||
@ -353,38 +370,39 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
||||
|
||||
set<Declaration const*> seenFunctions;
|
||||
MemberList::MemberMap members;
|
||||
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
|
||||
for (UsingForDirective const* ufd: contract->usingForDirectives())
|
||||
{
|
||||
// Convert both types to pointers for comparison to see if the `using for`
|
||||
// directive applies.
|
||||
// Further down, we check more detailed for each function if `_type` is
|
||||
// convertible to the function parameter type.
|
||||
if (ufd->typeName() &&
|
||||
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
||||
*TypeProvider::withLocationIfReference(
|
||||
typeLocation,
|
||||
ufd->typeName()->annotation().type,
|
||||
true
|
||||
)
|
||||
|
||||
for (UsingForDirective const* ufd: usingForDirectives)
|
||||
{
|
||||
// Convert both types to pointers for comparison to see if the `using for`
|
||||
// directive applies.
|
||||
// Further down, we check more detailed for each function if `_type` is
|
||||
// convertible to the function parameter type.
|
||||
if (ufd->typeName() &&
|
||||
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
||||
*TypeProvider::withLocationIfReference(
|
||||
typeLocation,
|
||||
ufd->typeName()->annotation().type,
|
||||
true
|
||||
)
|
||||
)
|
||||
continue;
|
||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||
*ufd->libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
for (FunctionDefinition const* function: library.definedFunctions())
|
||||
{
|
||||
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
|
||||
continue;
|
||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||
*ufd->libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
for (FunctionDefinition const* function: library.definedFunctions())
|
||||
{
|
||||
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
|
||||
continue;
|
||||
seenFunctions.insert(function);
|
||||
if (function->parameters().empty())
|
||||
continue;
|
||||
FunctionTypePointer fun =
|
||||
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
|
||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
||||
members.emplace_back(function->name(), fun, function);
|
||||
}
|
||||
seenFunctions.insert(function);
|
||||
if (function->parameters().empty())
|
||||
continue;
|
||||
FunctionTypePointer fun =
|
||||
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
|
||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
||||
members.emplace_back(function->name(), fun, function);
|
||||
}
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
@ -464,7 +482,7 @@ bool AddressType::operator==(Type const& _other) const
|
||||
return other.m_stateMutability == m_stateMutability;
|
||||
}
|
||||
|
||||
MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const
|
||||
MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
MemberList::MemberMap members = {
|
||||
{"balance", TypeProvider::uint256()},
|
||||
@ -1428,7 +1446,7 @@ TypeResult FixedBytesType::binaryOperatorResult(Token _operator, Type const* _ot
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MemberList::MemberMap FixedBytesType::nativeMembers(ContractDefinition const*) const
|
||||
MemberList::MemberMap FixedBytesType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
return MemberList::MemberMap{MemberList::Member{"length", TypeProvider::uint(8)}};
|
||||
}
|
||||
@ -1884,7 +1902,7 @@ string ArrayType::signatureInExternalFunction(bool _structsByName) const
|
||||
}
|
||||
}
|
||||
|
||||
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
|
||||
MemberList::MemberMap ArrayType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
if (!isString())
|
||||
@ -2057,10 +2075,9 @@ string ContractType::canonicalName() const
|
||||
return m_contract.annotation().canonicalName;
|
||||
}
|
||||
|
||||
MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _contract) const
|
||||
MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
solAssert(_contract, "");
|
||||
if (m_super)
|
||||
{
|
||||
// add the most derived of all functions which are visible in derived contracts
|
||||
@ -2091,14 +2108,13 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con
|
||||
}
|
||||
}
|
||||
else if (!m_contract.isLibrary())
|
||||
{
|
||||
for (auto const& it: m_contract.interfaceFunctions())
|
||||
members.emplace_back(
|
||||
it.second->declaration().name(),
|
||||
it.second->asExternallyCallableFunction(m_contract.isLibrary()),
|
||||
&it.second->declaration()
|
||||
);
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
@ -2269,7 +2285,7 @@ string StructType::toString(bool _short) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
|
||||
MemberList::MemberMap StructType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
@ -3174,7 +3190,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
||||
);
|
||||
}
|
||||
|
||||
MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const* _scope) const
|
||||
MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
|
||||
{
|
||||
switch (m_kind)
|
||||
{
|
||||
@ -3193,7 +3209,8 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const* _sco
|
||||
functionDefinition->isPartOfExternalInterface()
|
||||
)
|
||||
{
|
||||
solAssert(_scope->derivesFrom(*functionDefinition->annotation().contract), "");
|
||||
auto const* contractScope = dynamic_cast<ContractDefinition const*>(_scope);
|
||||
solAssert(contractScope && contractScope->derivesFrom(*functionDefinition->annotation().contract), "");
|
||||
return {{"selector", TypeProvider::fixedBytes(4)}};
|
||||
}
|
||||
else
|
||||
@ -3668,13 +3685,14 @@ vector<tuple<string, TypePointer>> TypeType::makeStackItems() const
|
||||
return {};
|
||||
}
|
||||
|
||||
MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _currentScope) const
|
||||
MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) const
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
if (m_actualType->category() == Category::Contract)
|
||||
{
|
||||
auto const* contractScope = dynamic_cast<ContractDefinition const*>(_currentScope);
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
|
||||
bool inDerivingScope = _currentScope && _currentScope->derivesFrom(contract);
|
||||
bool inDerivingScope = contractScope && contractScope->derivesFrom(contract);
|
||||
|
||||
for (auto const* declaration: contract.declarations())
|
||||
{
|
||||
@ -3776,7 +3794,7 @@ bool ModuleType::operator==(Type const& _other) const
|
||||
return &m_sourceUnit == &dynamic_cast<ModuleType const&>(_other).m_sourceUnit;
|
||||
}
|
||||
|
||||
MemberList::MemberMap ModuleType::nativeMembers(ContractDefinition const*) const
|
||||
MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
MemberList::MemberMap symbols;
|
||||
for (auto const& symbolName: m_sourceUnit.annotation().exportedSymbols)
|
||||
@ -3817,7 +3835,7 @@ bool MagicType::operator==(Type const& _other) const
|
||||
return other.m_kind == m_kind;
|
||||
}
|
||||
|
||||
MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
||||
MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
switch (m_kind)
|
||||
{
|
||||
|
@ -315,9 +315,9 @@ public:
|
||||
|
||||
/// Returns the list of all members of this type. Default implementation: no members apart from bound.
|
||||
/// @param _currentScope scope in which the members are accessed.
|
||||
MemberList const& members(ContractDefinition const* _currentScope) const;
|
||||
MemberList const& members(ASTNode const* _currentScope) const;
|
||||
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
|
||||
TypePointer memberType(std::string const& _name, ContractDefinition const* _currentScope = nullptr) const
|
||||
TypePointer memberType(std::string const& _name, ASTNode const* _currentScope = nullptr) const
|
||||
{
|
||||
return members(_currentScope).memberType(_name);
|
||||
}
|
||||
@ -361,12 +361,12 @@ public:
|
||||
|
||||
private:
|
||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||
static MemberList::MemberMap boundFunctions(Type const& _type, ContractDefinition const& _scope);
|
||||
static MemberList::MemberMap boundFunctions(Type const& _type, ASTNode const& _scope);
|
||||
|
||||
protected:
|
||||
/// @returns the members native to this type depending on the given context. This function
|
||||
/// is used (in conjunction with boundFunctions to fill m_members below.
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* /*_currentScope*/) const
|
||||
virtual MemberList::MemberMap nativeMembers(ASTNode const* /*_currentScope*/) const
|
||||
{
|
||||
return MemberList::MemberMap();
|
||||
}
|
||||
@ -379,7 +379,7 @@ protected:
|
||||
|
||||
|
||||
/// List of member types (parameterised by scape), will be lazy-initialized.
|
||||
mutable std::map<ContractDefinition const*, std::unique_ptr<MemberList>> m_members;
|
||||
mutable std::map<ASTNode const*, std::unique_ptr<MemberList>> m_members;
|
||||
mutable std::optional<std::vector<std::tuple<std::string, TypePointer>>> m_stackItems;
|
||||
mutable std::optional<size_t> m_stackSize;
|
||||
};
|
||||
@ -408,7 +408,7 @@ public:
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
@ -649,7 +649,7 @@ public:
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
TypePointer encodingType() const override { return this; }
|
||||
TypeResult interfaceType(bool) const override { return this; }
|
||||
|
||||
@ -786,7 +786,7 @@ public:
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
TypePointer decodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
@ -889,7 +889,7 @@ public:
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
|
||||
Type const* encodingType() const override;
|
||||
|
||||
@ -949,7 +949,7 @@ public:
|
||||
bool nameable() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
|
||||
Type const* encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
@ -1220,7 +1220,7 @@ public:
|
||||
bool nameable() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
|
||||
@ -1389,7 +1389,7 @@ public:
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
protected:
|
||||
@ -1441,7 +1441,7 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
@ -1481,7 +1481,7 @@ public:
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
|
@ -384,12 +384,11 @@ void CompilerContext::appendInlineAssembly(
|
||||
yul::Identifier const& _identifier,
|
||||
yul::IdentifierContext,
|
||||
bool _insideFunction
|
||||
) -> size_t
|
||||
) -> bool
|
||||
{
|
||||
if (_insideFunction)
|
||||
return numeric_limits<size_t>::max();
|
||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||
return it == _localVariables.end() ? numeric_limits<size_t>::max() : 1;
|
||||
return false;
|
||||
return contains(_localVariables, _identifier.name.str());
|
||||
};
|
||||
identifierAccess.generateCode = [&](
|
||||
yul::Identifier const& _identifier,
|
||||
|
@ -326,28 +326,28 @@ bool CompilerStack::analyze()
|
||||
if (source->ast && !resolver.performImports(*source->ast, sourceUnitsByName))
|
||||
return false;
|
||||
|
||||
// This is the main name and type resolution loop. Needs to be run for every contract, because
|
||||
// the special variables "this" and "super" must be set appropriately.
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast && !resolver.resolveNamesAndTypes(*source->ast))
|
||||
return false;
|
||||
|
||||
// Store contract definitions.
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||
for (
|
||||
ContractDefinition const* contract:
|
||||
ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes())
|
||||
)
|
||||
{
|
||||
if (!resolver.resolveNamesAndTypes(*node))
|
||||
return false;
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
// Note that we now reference contracts by their fully qualified names, and
|
||||
// thus contracts can only conflict if declared in the same source file. This
|
||||
// should already cause a double-declaration error elsewhere.
|
||||
if (m_contracts.find(contract->fullyQualifiedName()) == m_contracts.end())
|
||||
m_contracts[contract->fullyQualifiedName()].contract = contract;
|
||||
else
|
||||
solAssert(
|
||||
m_errorReporter.hasErrors(),
|
||||
"Contract already present (name clash?), but no error was reported."
|
||||
);
|
||||
}
|
||||
|
||||
// Note that we now reference contracts by their fully qualified names, and
|
||||
// thus contracts can only conflict if declared in the same source file. This
|
||||
// should already cause a double-declaration error elsewhere.
|
||||
if (!m_contracts.count(contract->fullyQualifiedName()))
|
||||
m_contracts[contract->fullyQualifiedName()].contract = contract;
|
||||
else
|
||||
solAssert(
|
||||
m_errorReporter.hasErrors(),
|
||||
"Contract already present (name clash?), but no error was reported."
|
||||
);
|
||||
}
|
||||
|
||||
DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion);
|
||||
@ -376,11 +376,8 @@ bool CompilerStack::analyze()
|
||||
// which is only done one step later.
|
||||
TypeChecker typeChecker(m_evmVersion, m_errorReporter);
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
if (!typeChecker.checkTypeRequirements(*contract))
|
||||
noErrors = false;
|
||||
if (source->ast && !typeChecker.checkTypeRequirements(*source->ast))
|
||||
noErrors = false;
|
||||
|
||||
if (noErrors)
|
||||
{
|
||||
|
@ -132,17 +132,11 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found = false;
|
||||
if (m_resolver)
|
||||
{
|
||||
bool insideFunction = m_currentScope->insideFunction();
|
||||
size_t stackSize = m_resolver(_identifier, yul::IdentifierContext::RValue, insideFunction);
|
||||
if (stackSize != numeric_limits<size_t>::max())
|
||||
{
|
||||
found = true;
|
||||
yulAssert(stackSize == 1, "Invalid stack size of external reference.");
|
||||
}
|
||||
}
|
||||
bool found = m_resolver && m_resolver(
|
||||
_identifier,
|
||||
yul::IdentifierContext::RValue,
|
||||
m_currentScope->insideFunction()
|
||||
);
|
||||
if (!found && watcher.ok())
|
||||
// Only add an error message if the callback did not do it.
|
||||
m_errorReporter.declarationError(8198_error, _identifier.location, "Identifier not found.");
|
||||
@ -478,12 +472,10 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
|
||||
else if (m_resolver)
|
||||
{
|
||||
bool insideFunction = m_currentScope->insideFunction();
|
||||
size_t variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction);
|
||||
if (variableSize != numeric_limits<size_t>::max())
|
||||
if (m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction))
|
||||
{
|
||||
found = true;
|
||||
variableType = &m_dialect.defaultType;
|
||||
yulAssert(variableSize == 1, "Invalid stack size of external reference.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ enum class IdentifierContext { LValue, RValue, VariableDeclaration };
|
||||
/// to inline assembly (not used in standalone assembly mode).
|
||||
struct ExternalIdentifierAccess
|
||||
{
|
||||
using Resolver = std::function<size_t(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
|
||||
using Resolver = std::function<bool(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
|
||||
/// Resolve an external reference given by the identifier in the given context.
|
||||
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
|
||||
Resolver resolve;
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include <libyul/backends/wasm/WasmCodeTransform.h>
|
||||
|
||||
#include <libyul/backends/wasm/WasmDialect.h>
|
||||
|
||||
#include <libyul/optimiser/NameCollector.h>
|
||||
|
||||
#include <libyul/AsmData.h>
|
||||
@ -40,7 +42,8 @@ wasm::Module WasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _
|
||||
{
|
||||
wasm::Module module;
|
||||
|
||||
WasmCodeTransform transform(_dialect, _ast);
|
||||
TypeInfo typeInfo(_dialect, _ast);
|
||||
WasmCodeTransform transform(_dialect, _ast, typeInfo);
|
||||
|
||||
for (auto const& statement: _ast.statements)
|
||||
{
|
||||
@ -70,14 +73,18 @@ wasm::Expression WasmCodeTransform::generateMultiAssignment(
|
||||
if (_variableNames.size() == 1)
|
||||
return { std::move(assignment) };
|
||||
|
||||
allocateGlobals(_variableNames.size() - 1);
|
||||
vector<wasm::Type> typesForGlobals;
|
||||
for (size_t i = 1; i < _variableNames.size(); ++i)
|
||||
typesForGlobals.push_back(translatedType(m_typeInfo.typeOfVariable(YulString(_variableNames[i]))));
|
||||
vector<size_t> allocatedIndices = allocateGlobals(typesForGlobals);
|
||||
yulAssert(allocatedIndices.size() == _variableNames.size() - 1, "");
|
||||
|
||||
wasm::Block block;
|
||||
block.statements.emplace_back(move(assignment));
|
||||
for (size_t i = 1; i < _variableNames.size(); ++i)
|
||||
block.statements.emplace_back(wasm::LocalAssignment{
|
||||
move(_variableNames.at(i)),
|
||||
make_unique<wasm::Expression>(wasm::GlobalVariable{m_globalVariables.at(i - 1).variableName})
|
||||
make_unique<wasm::Expression>(wasm::GlobalVariable{m_globalVariables.at(allocatedIndices[i - 1]).variableName})
|
||||
});
|
||||
return { std::move(block) };
|
||||
}
|
||||
@ -88,7 +95,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe
|
||||
for (auto const& var: _varDecl.variables)
|
||||
{
|
||||
variableNames.emplace_back(var.name.str());
|
||||
m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), wasm::Type::i64});
|
||||
m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), translatedType(var.type)});
|
||||
}
|
||||
|
||||
if (_varDecl.value)
|
||||
@ -112,8 +119,6 @@ wasm::Expression WasmCodeTransform::operator()(ExpressionStatement const& _state
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
|
||||
{
|
||||
bool typeConversionNeeded = false;
|
||||
|
||||
if (BuiltinFunction const* builtin = m_dialect.builtin(_call.functionName.name))
|
||||
{
|
||||
if (_call.functionName.name.str().substr(0, 4) == "eth.")
|
||||
@ -133,7 +138,6 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
|
||||
imp.paramTypes.emplace_back(translatedType(param));
|
||||
m_functionsToImport[builtin->name] = std::move(imp);
|
||||
}
|
||||
typeConversionNeeded = true;
|
||||
}
|
||||
else if (builtin->literalArguments && contains(builtin->literalArguments.value(), true))
|
||||
{
|
||||
@ -147,18 +151,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
|
||||
return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)};
|
||||
}
|
||||
else
|
||||
{
|
||||
wasm::BuiltinCall call{
|
||||
return wasm::BuiltinCall{
|
||||
_call.functionName.name.str(),
|
||||
injectTypeConversionIfNeeded(visit(_call.arguments), builtin->parameters)
|
||||
visit(_call.arguments)
|
||||
};
|
||||
if (!builtin->returns.empty() && !builtin->returns.front().empty() && builtin->returns.front() != "i64"_yulstring)
|
||||
{
|
||||
yulAssert(builtin->returns.front() == "i32"_yulstring, "Invalid type " + builtin->returns.front().str());
|
||||
call = wasm::BuiltinCall{"i64.extend_i32_u", make_vector<wasm::Expression>(std::move(call))};
|
||||
}
|
||||
return {std::move(call)};
|
||||
}
|
||||
}
|
||||
|
||||
// If this function returns multiple values, then the first one will
|
||||
@ -166,13 +162,7 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
|
||||
// The values have to be used right away in an assignment or variable declaration,
|
||||
// so it is handled there.
|
||||
|
||||
wasm::FunctionCall funCall{_call.functionName.name.str(), visit(_call.arguments)};
|
||||
if (typeConversionNeeded)
|
||||
// Inject type conversion if needed on the fly. This is just a temporary measure
|
||||
// and can be removed once we have proper types in Yul.
|
||||
return injectTypeConversionIfNeeded(std::move(funCall));
|
||||
else
|
||||
return {std::move(funCall)};
|
||||
return wasm::FunctionCall{_call.functionName.name.str(), visit(_call.arguments)};
|
||||
}
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(Identifier const& _identifier)
|
||||
@ -182,30 +172,40 @@ wasm::Expression WasmCodeTransform::operator()(Identifier const& _identifier)
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(Literal const& _literal)
|
||||
{
|
||||
u256 value = valueOfLiteral(_literal);
|
||||
yulAssert(value <= numeric_limits<uint64_t>::max(), "Literal too large: " + value.str());
|
||||
return wasm::Literal{static_cast<uint64_t>(value)};
|
||||
return makeLiteral(translatedType(_literal.type), valueOfLiteral(_literal));
|
||||
}
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(If const& _if)
|
||||
{
|
||||
// TODO converting i64 to i32 might not always be needed.
|
||||
yul::Type conditionType = m_typeInfo.typeOf(*_if.condition);
|
||||
|
||||
vector<wasm::Expression> args;
|
||||
args.emplace_back(visitReturnByValue(*_if.condition));
|
||||
args.emplace_back(wasm::Literal{static_cast<uint64_t>(0)});
|
||||
return wasm::If{
|
||||
make_unique<wasm::Expression>(wasm::BuiltinCall{"i64.ne", std::move(args)}),
|
||||
visit(_if.body.statements),
|
||||
{}
|
||||
};
|
||||
wasm::Expression condition;
|
||||
if (conditionType == "i32"_yulstring)
|
||||
condition = visitReturnByValue(*_if.condition);
|
||||
else if (conditionType == "i64"_yulstring)
|
||||
{
|
||||
vector<wasm::Expression> args;
|
||||
args.emplace_back(visitReturnByValue(*_if.condition));
|
||||
args.emplace_back(makeLiteral(translatedType("i64"_yulstring), 0));
|
||||
|
||||
// NOTE: `if` in wasm requires an i32 argument
|
||||
condition = wasm::BuiltinCall{"i64.ne", std::move(args)};
|
||||
}
|
||||
else
|
||||
yulAssert(false, "Invalid condition type");
|
||||
|
||||
return wasm::If{make_unique<wasm::Expression>(move(condition)), visit(_if.body.statements), {}};
|
||||
}
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
|
||||
{
|
||||
yul::Type expressionType = m_typeInfo.typeOf(*_switch.expression);
|
||||
YulString eq_instruction = YulString(expressionType.str() + ".eq");
|
||||
yulAssert(WasmDialect::instance().builtin(eq_instruction), "");
|
||||
|
||||
wasm::Block block;
|
||||
string condition = m_nameDispenser.newName("condition"_yulstring).str();
|
||||
m_localVariables.emplace_back(wasm::VariableDeclaration{condition, wasm::Type::i64});
|
||||
m_localVariables.emplace_back(wasm::VariableDeclaration{condition, translatedType(expressionType)});
|
||||
block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)});
|
||||
|
||||
vector<wasm::Expression>* currentBlock = &block.statements;
|
||||
@ -214,7 +214,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch)
|
||||
Case const& c = _switch.cases.at(i);
|
||||
if (c.value)
|
||||
{
|
||||
wasm::BuiltinCall comparison{"i64.eq", make_vector<wasm::Expression>(
|
||||
wasm::BuiltinCall comparison{eq_instruction.str(), make_vector<wasm::Expression>(
|
||||
wasm::LocalVariable{condition},
|
||||
visitReturnByValue(*c.value)
|
||||
)};
|
||||
@ -253,11 +253,15 @@ wasm::Expression WasmCodeTransform::operator()(ForLoop const& _for)
|
||||
string continueLabel = newLabel();
|
||||
m_breakContinueLabelNames.push({breakLabel, continueLabel});
|
||||
|
||||
yul::Type conditionType = m_typeInfo.typeOf(*_for.condition);
|
||||
YulString eqz_instruction = YulString(conditionType.str() + ".eqz");
|
||||
yulAssert(WasmDialect::instance().builtin(eqz_instruction), "");
|
||||
|
||||
wasm::Loop loop;
|
||||
loop.labelName = newLabel();
|
||||
loop.statements = visit(_for.pre.statements);
|
||||
loop.statements.emplace_back(wasm::BranchIf{wasm::Label{breakLabel}, make_unique<wasm::Expression>(
|
||||
wasm::BuiltinCall{"i64.eqz", make_vector<wasm::Expression>(
|
||||
wasm::BuiltinCall{eqz_instruction.str(), make_vector<wasm::Expression>(
|
||||
visitReturnByValue(*_for.condition)
|
||||
)}
|
||||
)});
|
||||
@ -325,11 +329,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
|
||||
wasm::FunctionDefinition fun;
|
||||
fun.name = _fun.name.str();
|
||||
for (auto const& param: _fun.parameters)
|
||||
fun.parameters.push_back({param.name.str(), wasm::Type::i64});
|
||||
fun.parameters.push_back({param.name.str(), translatedType(param.type)});
|
||||
for (auto const& retParam: _fun.returnVariables)
|
||||
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64});
|
||||
fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), translatedType(retParam.type)});
|
||||
if (!_fun.returnVariables.empty())
|
||||
fun.returnType = wasm::Type::i64;
|
||||
fun.returnType = translatedType(_fun.returnVariables[0].type);
|
||||
|
||||
yulAssert(m_localVariables.empty(), "");
|
||||
yulAssert(m_functionBodyLabel.empty(), "");
|
||||
@ -347,10 +351,15 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
|
||||
{
|
||||
// First return variable is returned directly, the others are stored
|
||||
// in globals.
|
||||
allocateGlobals(_fun.returnVariables.size() - 1);
|
||||
vector<wasm::Type> typesForGlobals;
|
||||
for (size_t i = 1; i < _fun.returnVariables.size(); ++i)
|
||||
typesForGlobals.push_back(translatedType(_fun.returnVariables[i].type));
|
||||
vector<size_t> allocatedIndices = allocateGlobals(typesForGlobals);
|
||||
yulAssert(allocatedIndices.size() == _fun.returnVariables.size() - 1, "");
|
||||
|
||||
for (size_t i = 1; i < _fun.returnVariables.size(); ++i)
|
||||
fun.body.emplace_back(wasm::GlobalAssignment{
|
||||
m_globalVariables.at(i - 1).variableName,
|
||||
m_globalVariables.at(allocatedIndices[i - 1]).variableName,
|
||||
make_unique<wasm::Expression>(wasm::LocalVariable{_fun.returnVariables.at(i).name.str()})
|
||||
});
|
||||
fun.body.emplace_back(wasm::LocalVariable{_fun.returnVariables.front().name.str()});
|
||||
@ -358,52 +367,50 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
|
||||
return fun;
|
||||
}
|
||||
|
||||
wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionCall _call) const
|
||||
{
|
||||
wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName});
|
||||
for (size_t i = 0; i < _call.arguments.size(); ++i)
|
||||
if (import.paramTypes.at(i) == wasm::Type::i32)
|
||||
_call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector<wasm::Expression>(std::move(_call.arguments[i]))};
|
||||
else
|
||||
yulAssert(import.paramTypes.at(i) == wasm::Type::i64, "Invalid Wasm type");
|
||||
|
||||
if (import.returnType && *import.returnType != wasm::Type::i64)
|
||||
{
|
||||
yulAssert(*import.returnType == wasm::Type::i32, "Invalid Wasm type");
|
||||
return wasm::BuiltinCall{"i64.extend_i32_u", make_vector<wasm::Expression>(std::move(_call))};
|
||||
}
|
||||
return {std::move(_call)};
|
||||
}
|
||||
|
||||
vector<wasm::Expression> WasmCodeTransform::injectTypeConversionIfNeeded(
|
||||
vector<wasm::Expression> _arguments,
|
||||
vector<Type> const& _parameterTypes
|
||||
) const
|
||||
{
|
||||
for (size_t i = 0; i < _arguments.size(); ++i)
|
||||
if (_parameterTypes.at(i) == "i32"_yulstring)
|
||||
_arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector<wasm::Expression>(std::move(_arguments[i]))};
|
||||
else
|
||||
yulAssert(
|
||||
_parameterTypes.at(i).empty() || _parameterTypes.at(i) == "i64"_yulstring,
|
||||
"Unknown type " + _parameterTypes.at(i).str()
|
||||
);
|
||||
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
string WasmCodeTransform::newLabel()
|
||||
{
|
||||
return m_nameDispenser.newName("label_"_yulstring).str();
|
||||
}
|
||||
|
||||
void WasmCodeTransform::allocateGlobals(size_t _amount)
|
||||
vector<size_t> WasmCodeTransform::allocateGlobals(vector<wasm::Type> const& _typesForGlobals)
|
||||
{
|
||||
while (m_globalVariables.size() < _amount)
|
||||
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{
|
||||
m_nameDispenser.newName("global_"_yulstring).str(),
|
||||
wasm::Type::i64
|
||||
});
|
||||
map<wasm::Type, size_t> availableGlobals;
|
||||
for (wasm::GlobalVariableDeclaration const& global: m_globalVariables)
|
||||
++availableGlobals[global.type];
|
||||
|
||||
map<wasm::Type, size_t> neededGlobals;
|
||||
for (wasm::Type const& type: _typesForGlobals)
|
||||
++neededGlobals[type];
|
||||
|
||||
for (auto [type, neededGlobalCount]: neededGlobals)
|
||||
while (availableGlobals[type] < neededGlobalCount)
|
||||
{
|
||||
m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{
|
||||
m_nameDispenser.newName("global_"_yulstring).str(),
|
||||
type,
|
||||
});
|
||||
|
||||
++availableGlobals[type];
|
||||
}
|
||||
|
||||
vector<size_t> allocatedIndices;
|
||||
map<wasm::Type, size_t> nextGlobal;
|
||||
for (wasm::Type const& type: _typesForGlobals)
|
||||
{
|
||||
while (m_globalVariables[nextGlobal[type]].type != type)
|
||||
++nextGlobal[type];
|
||||
|
||||
allocatedIndices.push_back(nextGlobal[type]++);
|
||||
}
|
||||
|
||||
yulAssert(all_of(
|
||||
allocatedIndices.begin(),
|
||||
allocatedIndices.end(),
|
||||
[this](size_t index){ return index < m_globalVariables.size(); }
|
||||
), "");
|
||||
yulAssert(allocatedIndices.size() == set<size_t>(allocatedIndices.begin(), allocatedIndices.end()).size(), "Indices not unique");
|
||||
yulAssert(allocatedIndices.size() == _typesForGlobals.size(), "");
|
||||
return allocatedIndices;
|
||||
}
|
||||
|
||||
wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType)
|
||||
@ -415,3 +422,19 @@ wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType)
|
||||
else
|
||||
yulAssert(false, "This Yul type does not have a corresponding type in Wasm.");
|
||||
}
|
||||
|
||||
wasm::Literal WasmCodeTransform::makeLiteral(wasm::Type _type, u256 _value)
|
||||
{
|
||||
if (_type == wasm::Type::i32)
|
||||
{
|
||||
yulAssert(_value <= numeric_limits<uint32_t>::max(), "Literal too large: " + _value.str());
|
||||
return wasm::Literal{static_cast<uint32_t>(_value)};
|
||||
}
|
||||
else if (_type == wasm::Type::i64)
|
||||
{
|
||||
yulAssert(_value <= numeric_limits<uint64_t>::max(), "Literal too large: " + _value.str());
|
||||
return wasm::Literal{static_cast<uint64_t>(_value)};
|
||||
}
|
||||
else
|
||||
yulAssert(false, "Invalid Wasm literal type");
|
||||
}
|
||||
|
@ -24,6 +24,9 @@
|
||||
#include <libyul/AsmDataForward.h>
|
||||
#include <libyul/Dialect.h>
|
||||
#include <libyul/optimiser/NameDispenser.h>
|
||||
#include <libyul/optimiser/TypeInfo.h>
|
||||
|
||||
#include <libsolutil/Common.h>
|
||||
|
||||
#include <stack>
|
||||
#include <map>
|
||||
@ -56,10 +59,12 @@ public:
|
||||
private:
|
||||
WasmCodeTransform(
|
||||
Dialect const& _dialect,
|
||||
Block const& _ast
|
||||
Block const& _ast,
|
||||
TypeInfo& _typeInfo
|
||||
):
|
||||
m_dialect(_dialect),
|
||||
m_nameDispenser(_dialect, _ast)
|
||||
m_nameDispenser(_dialect, _ast),
|
||||
m_typeInfo(_typeInfo)
|
||||
{}
|
||||
|
||||
std::unique_ptr<wasm::Expression> visit(yul::Expression const& _expression);
|
||||
@ -79,17 +84,13 @@ private:
|
||||
|
||||
wasm::FunctionDefinition translateFunction(yul::FunctionDefinition const& _funDef);
|
||||
|
||||
wasm::Expression injectTypeConversionIfNeeded(wasm::FunctionCall _call) const;
|
||||
std::vector<wasm::Expression> injectTypeConversionIfNeeded(
|
||||
std::vector<wasm::Expression> _arguments,
|
||||
std::vector<yul::Type> const& _parameterTypes
|
||||
) const;
|
||||
|
||||
std::string newLabel();
|
||||
/// Makes sure that there are at least @a _amount global variables.
|
||||
void allocateGlobals(size_t _amount);
|
||||
/// Selects a subset of global variables matching specified sequence of variable types.
|
||||
/// Defines more global variables of a given type if there's not enough.
|
||||
std::vector<size_t> allocateGlobals(std::vector<wasm::Type> const& _typesForGlobals);
|
||||
|
||||
static wasm::Type translatedType(yul::Type _yulType);
|
||||
static wasm::Literal makeLiteral(wasm::Type _type, u256 _value);
|
||||
|
||||
Dialect const& m_dialect;
|
||||
NameDispenser m_nameDispenser;
|
||||
@ -99,6 +100,7 @@ private:
|
||||
std::map<YulString, wasm::FunctionImport> m_functionsToImport;
|
||||
std::string m_functionBodyLabel;
|
||||
std::stack<std::pair<std::string, std::string>> m_breakContinueLabelNames;
|
||||
TypeInfo& m_typeInfo;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#ifdef _WIN32 // windows
|
||||
@ -1131,6 +1132,21 @@ bool CommandLineInterface::processInput()
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> const exclusiveModes = {
|
||||
g_argStandardJSON,
|
||||
g_argLink,
|
||||
g_argAssemble,
|
||||
g_argStrictAssembly,
|
||||
g_argYul,
|
||||
g_argImportAst,
|
||||
};
|
||||
if (countEnabledOptions(exclusiveModes) > 1)
|
||||
{
|
||||
serr() << "The following options are mutually exclusive: " << joinOptionNames(exclusiveModes) << ". ";
|
||||
serr() << "Select at most one." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argStandardJSON))
|
||||
{
|
||||
vector<string> inputFiles;
|
||||
@ -1176,6 +1192,22 @@ bool CommandLineInterface::processInput()
|
||||
|
||||
if (m_args.count(g_argAssemble) || m_args.count(g_argStrictAssembly) || m_args.count(g_argYul))
|
||||
{
|
||||
vector<string> const nonAssemblyModeOptions = {
|
||||
// TODO: The list is not complete. Add more.
|
||||
g_argOutputDir,
|
||||
g_argGas,
|
||||
g_argCombinedJson,
|
||||
g_strOptimizeYul,
|
||||
g_strNoOptimizeYul,
|
||||
};
|
||||
if (countEnabledOptions(nonAssemblyModeOptions) >= 1)
|
||||
{
|
||||
serr() << "The following options are invalid in assembly mode: ";
|
||||
serr() << joinOptionNames(nonAssemblyModeOptions) << ". ";
|
||||
serr() << "Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// switch to assembly mode
|
||||
m_onlyAssemble = true;
|
||||
using Input = yul::AssemblyStack::Language;
|
||||
@ -1183,16 +1215,6 @@ bool CommandLineInterface::processInput()
|
||||
Input inputLanguage = m_args.count(g_argYul) ? Input::Yul : (m_args.count(g_argStrictAssembly) ? Input::StrictAssembly : Input::Assembly);
|
||||
Machine targetMachine = Machine::EVM;
|
||||
bool optimize = m_args.count(g_argOptimize);
|
||||
if (m_args.count(g_strOptimizeYul))
|
||||
{
|
||||
serr() << "--" << g_strOptimizeYul << " is invalid in assembly mode. Use --" << g_argOptimize << " instead." << endl;
|
||||
return false;
|
||||
}
|
||||
if (m_args.count(g_strNoOptimizeYul))
|
||||
{
|
||||
serr() << "--" << g_strNoOptimizeYul << " is invalid in assembly mode. Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
optional<string> yulOptimiserSteps;
|
||||
if (m_args.count(g_strYulOptimizations))
|
||||
@ -1275,6 +1297,13 @@ bool CommandLineInterface::processInput()
|
||||
|
||||
return assemble(inputLanguage, targetMachine, optimize, yulOptimiserSteps);
|
||||
}
|
||||
else if (countEnabledOptions({g_strYulDialect, g_argMachine}) >= 1)
|
||||
{
|
||||
serr() << "--" << g_strYulDialect << " and --" << g_argMachine << " ";
|
||||
serr() << "are only valid in assembly mode." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argLink))
|
||||
{
|
||||
// switch to linker mode
|
||||
@ -1882,4 +1911,21 @@ void CommandLineInterface::outputCompilationResults()
|
||||
}
|
||||
}
|
||||
|
||||
size_t CommandLineInterface::countEnabledOptions(vector<string> const& _optionNames) const
|
||||
{
|
||||
size_t count = 0;
|
||||
for (string const& _option: _optionNames)
|
||||
count += m_args.count(_option);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
string CommandLineInterface::joinOptionNames(vector<string> const& _optionNames, string _separator)
|
||||
{
|
||||
return boost::algorithm::join(
|
||||
_optionNames | boost::adaptors::transformed([](string const& _option){ return "--" + _option; }),
|
||||
_separator
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -103,6 +103,9 @@ private:
|
||||
/// @arg _json json string to be written
|
||||
void createJson(std::string const& _fileName, std::string const& _json);
|
||||
|
||||
size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const;
|
||||
static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", ");
|
||||
|
||||
bool m_error = false; ///< If true, some error occurred.
|
||||
|
||||
bool m_onlyAssemble = false;
|
||||
|
@ -45,7 +45,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acb01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b3f0002402000a7200110043700002000a74208a76aada7200210043700002000a74210a76aada7200310043700002000a74218a76aada7200410043700000b0b
|
||||
0061736d0100000001160460000060017e017e60057f7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010abc01052901017e0240420021004100200020002000200010054120200020002000420110054100412010000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b32000240200020011004370000200041086a20021004370000200041106a20031004370000200041186a200410043700000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
@ -57,9 +57,9 @@ Text representation:
|
||||
(local $_1 i64)
|
||||
(block $label_
|
||||
(local.set $_1 (i64.const 0))
|
||||
(call $mstore_internal (i64.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
||||
(call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
|
||||
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
|
||||
(call $mstore_internal (i32.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
||||
(call $mstore_internal (i32.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
|
||||
(call $eth.storageStore (i32.const 0) (i32.const 32))
|
||||
)
|
||||
)
|
||||
|
||||
@ -101,16 +101,16 @@ Text representation:
|
||||
)
|
||||
|
||||
(func $mstore_internal
|
||||
(param $pos i64)
|
||||
(param $pos i32)
|
||||
(param $y1 i64)
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(block $label__4
|
||||
(i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 8))))) (call $endian_swap (local.get $y2)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 16))))) (call $endian_swap (local.get $y3)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4)))
|
||||
(i64.store (local.get $pos) (call $endian_swap (local.get $y1)))
|
||||
(i64.store (i32.add (local.get $pos) (i32.const 8)) (call $endian_swap (local.get $y2)))
|
||||
(i64.store (i32.add (local.get $pos) (i32.const 16)) (call $endian_swap (local.get $y3)))
|
||||
(i64.store (i32.add (local.get $pos) (i32.const 24)) (call $endian_swap (local.get $y4)))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -154,7 +154,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa5090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290000100c21084200a74208a76aada7290000100c21094200a74210a76aada7290000100c210a4200a74218a76aada7290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3f0002402000a72001100c3700002000a74208a76aada72002100c3700002000a74210a76aada72003100c3700002000a74218a76aada72004100c3700000b0b2500024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b
|
||||
0061736d0100000001480a60000060017e017e60027e7e017f60037e7e7e017e60047e7e7e7e017e60087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60057f7e7e7e7e0060027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003060406020604010101070505030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020ac3080dde02030a7e017f147e02404200210002402000200020002000100921012300210223012103230221040b20012105200221062003210720042108420121092000200084200020098484504545210a02400340200a45450d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f201084201120128484504504400c030b024020052006200720082000200020004202100621132300211423012115230221160b2013201484201520168484504504400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a8484504504400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2901037e0240200020017c2105200520027c21032005200054200320055472ad21040b2004240020030b6c010b7e0240200320077c210c200c42007c210b024020022006200c200354200b200c5472ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2401047e0240200020018420022003848450ad21070b20052400200624012007240220040b3901047e0240200020045104402001200551044020022006510440200320075104404201210b0b0b0b0b0b20092400200a2401200b240220080b2701027f024002402000200154210320034101460440417f210205200020015221020b0b0b20020b960102047e047f02404100210c0240200020041007210d200d41004604400240200120051007210e200e41004604400240200220061007210f200f41004604402003200754210c05200f41014604404100210c054101210c0b0b0b05200e41014604404100210c054101210c0b0b0b05200d41014604404100210c054101210c0b0b0b200cad210b0b20092400200a2401200b240220080b7601087e024042002000200184200284520440000b42002003422088520440000b41002003a7412010014100290000100c2108410041086a290000100c2109410041106a290000100c210a410041186a290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3200024020002001100c370000200041086a2002100c370000200041106a2003100c370000200041186a2004100c3700000b0b2300024041002000200120022003100d41202004200520062007100d4100412010000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
@ -177,7 +177,7 @@ Text representation:
|
||||
(local $x_6 i64)
|
||||
(local $x_7 i64)
|
||||
(local $_2 i64)
|
||||
(local $_3 i64)
|
||||
(local $_3 i32)
|
||||
(local $_4 i64)
|
||||
(local $_5 i64)
|
||||
(local $_6 i64)
|
||||
@ -212,10 +212,10 @@ Text representation:
|
||||
(local.set $x_6 (local.get $x_2))
|
||||
(local.set $x_7 (local.get $x_3))
|
||||
(local.set $_2 (i64.const 1))
|
||||
(local.set $_3 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_1) (local.get $_1)) (i64.or (local.get $_1) (local.get $_2))))))))))))
|
||||
(local.set $_3 (i32.eqz (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_1) (local.get $_1)) (i64.or (local.get $_1) (local.get $_2)))))))
|
||||
(block $label__3
|
||||
(loop $label__5
|
||||
(br_if $label__3 (i64.eqz (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (local.get $_3))))))
|
||||
(br_if $label__3 (i32.eqz (i32.eqz (local.get $_3))))
|
||||
(block $label__4
|
||||
(block
|
||||
(local.set $_4 (call $lt (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 10)))
|
||||
@ -231,7 +231,7 @@ Text representation:
|
||||
(local.set $_11 (global.get $global__2))
|
||||
|
||||
)
|
||||
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_8) (local.get $_9)) (i64.or (local.get $_10) (local.get $_11)))))))) (i64.const 0)) (then
|
||||
(if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_8) (local.get $_9)) (i64.or (local.get $_10) (local.get $_11))))) (then
|
||||
(br $label__3)
|
||||
))
|
||||
(block
|
||||
@ -241,7 +241,7 @@ Text representation:
|
||||
(local.set $_15 (global.get $global__2))
|
||||
|
||||
)
|
||||
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_12) (local.get $_13)) (i64.or (local.get $_14) (local.get $_15)))))))) (i64.const 0)) (then
|
||||
(if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_12) (local.get $_13)) (i64.or (local.get $_14) (local.get $_15))))) (then
|
||||
(br $label__3)
|
||||
))
|
||||
(block
|
||||
@ -251,7 +251,7 @@ Text representation:
|
||||
(local.set $_19 (global.get $global__2))
|
||||
|
||||
)
|
||||
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_16) (local.get $_17)) (i64.or (local.get $_18) (local.get $_19)))))))) (i64.const 0)) (then
|
||||
(if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_16) (local.get $_17)) (i64.or (local.get $_18) (local.get $_19))))) (then
|
||||
(br $label__4)
|
||||
))
|
||||
|
||||
@ -286,7 +286,7 @@ Text representation:
|
||||
(block $label__6
|
||||
(local.set $t (i64.add (local.get $x) (local.get $y)))
|
||||
(local.set $r (i64.add (local.get $t) (local.get $c)))
|
||||
(local.set $r_c (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $t)))))))))
|
||||
(local.set $r_c (i64.extend_i32_u (i32.or (i64.lt_u (local.get $t) (local.get $x)) (i64.lt_u (local.get $r) (local.get $t)))))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $r_c))
|
||||
@ -318,7 +318,7 @@ Text representation:
|
||||
(local.set $t (i64.add (local.get $x4) (local.get $y4)))
|
||||
(local.set $r4 (i64.add (local.get $t) (i64.const 0)))
|
||||
(block
|
||||
(local.set $r3_1 (call $add_carry (local.get $x3) (local.get $y3) (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x4)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r4) (local.get $t))))))))))
|
||||
(local.set $r3_1 (call $add_carry (local.get $x3) (local.get $y3) (i64.extend_i32_u (i32.or (i64.lt_u (local.get $t) (local.get $x4)) (i64.lt_u (local.get $r4) (local.get $t))))))
|
||||
(local.set $carry (global.get $global_))
|
||||
|
||||
)
|
||||
@ -354,7 +354,7 @@ Text representation:
|
||||
(local $r3 i64)
|
||||
(local $r4 i64)
|
||||
(block $label__8
|
||||
(local.set $r4 (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $x1) (local.get $x2)) (i64.or (local.get $x3) (local.get $x4))))))))
|
||||
(local.set $r4 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $x1) (local.get $x2)) (i64.or (local.get $x3) (local.get $x4))))))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $r2))
|
||||
@ -378,10 +378,10 @@ Text representation:
|
||||
(local $r3 i64)
|
||||
(local $r4 i64)
|
||||
(block $label__9
|
||||
(if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x1) (local.get $y1))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x2) (local.get $y2))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x3) (local.get $y3))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x4) (local.get $y4))) (i64.const 0)) (then
|
||||
(if (i64.eq (local.get $x1) (local.get $y1)) (then
|
||||
(if (i64.eq (local.get $x2) (local.get $y2)) (then
|
||||
(if (i64.eq (local.get $x3) (local.get $y3)) (then
|
||||
(if (i64.eq (local.get $x4) (local.get $y4)) (then
|
||||
(local.set $r4 (i64.const 1))
|
||||
))
|
||||
))
|
||||
@ -398,16 +398,16 @@ Text representation:
|
||||
(func $cmp
|
||||
(param $a i64)
|
||||
(param $b i64)
|
||||
(result i64)
|
||||
(local $r i64)
|
||||
(local $condition i64)
|
||||
(result i32)
|
||||
(local $r i32)
|
||||
(local $condition i32)
|
||||
(block $label__10
|
||||
(block
|
||||
(local.set $condition (i64.extend_i32_u (i64.lt_u (local.get $a) (local.get $b))))
|
||||
(if (i64.eq (local.get $condition) (i64.const 1)) (then
|
||||
(local.set $r (i64.const 4294967295))
|
||||
(local.set $condition (i64.lt_u (local.get $a) (local.get $b)))
|
||||
(if (i32.eq (local.get $condition) (i32.const 1)) (then
|
||||
(local.set $r (i32.const 4294967295))
|
||||
)(else
|
||||
(local.set $r (i64.extend_i32_u (i64.ne (local.get $a) (local.get $b))))
|
||||
(local.set $r (i64.ne (local.get $a) (local.get $b)))
|
||||
))
|
||||
|
||||
)
|
||||
@ -430,50 +430,50 @@ Text representation:
|
||||
(local $z2 i64)
|
||||
(local $z3 i64)
|
||||
(local $z4 i64)
|
||||
(local $z i64)
|
||||
(local $condition_12 i64)
|
||||
(local $condition_13 i64)
|
||||
(local $condition_14 i64)
|
||||
(local $z i32)
|
||||
(local $condition_12 i32)
|
||||
(local $condition_13 i32)
|
||||
(local $condition_14 i32)
|
||||
(block $label__11
|
||||
(local.set $z (i64.const 0))
|
||||
(local.set $z (i32.const 0))
|
||||
(block
|
||||
(local.set $condition_12 (call $cmp (local.get $x1) (local.get $y1)))
|
||||
(if (i64.eq (local.get $condition_12) (i64.const 0)) (then
|
||||
(if (i32.eq (local.get $condition_12) (i32.const 0)) (then
|
||||
(block
|
||||
(local.set $condition_13 (call $cmp (local.get $x2) (local.get $y2)))
|
||||
(if (i64.eq (local.get $condition_13) (i64.const 0)) (then
|
||||
(if (i32.eq (local.get $condition_13) (i32.const 0)) (then
|
||||
(block
|
||||
(local.set $condition_14 (call $cmp (local.get $x3) (local.get $y3)))
|
||||
(if (i64.eq (local.get $condition_14) (i64.const 0)) (then
|
||||
(local.set $z (i64.extend_i32_u (i64.lt_u (local.get $x4) (local.get $y4))))
|
||||
(if (i32.eq (local.get $condition_14) (i32.const 0)) (then
|
||||
(local.set $z (i64.lt_u (local.get $x4) (local.get $y4)))
|
||||
)(else
|
||||
(if (i64.eq (local.get $condition_14) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
(if (i32.eq (local.get $condition_14) (i32.const 1)) (then
|
||||
(local.set $z (i32.const 0))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
(local.set $z (i32.const 1))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
)(else
|
||||
(if (i64.eq (local.get $condition_13) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
(if (i32.eq (local.get $condition_13) (i32.const 1)) (then
|
||||
(local.set $z (i32.const 0))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
(local.set $z (i32.const 1))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
)(else
|
||||
(if (i64.eq (local.get $condition_12) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
(if (i32.eq (local.get $condition_12) (i32.const 1)) (then
|
||||
(local.set $z (i32.const 0))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
(local.set $z (i32.const 1))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
(local.set $z4 (i64.extend_i32_u (i32.wrap_i64 (local.get $z))))
|
||||
(local.set $z4 (i64.extend_i32_u (local.get $z)))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $z2))
|
||||
@ -497,15 +497,15 @@ Text representation:
|
||||
(local $z3_1 i64)
|
||||
(local $z4_1 i64)
|
||||
(block $label__15
|
||||
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3))) (then
|
||||
(unreachable)))
|
||||
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32))) (then
|
||||
(unreachable)))
|
||||
(call $eth.callDataCopy (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.extend_i32_u (i32.wrap_i64 (local.get $x4)))) (i32.wrap_i64 (i64.const 32)))
|
||||
(local.set $z1_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0)))))
|
||||
(local.set $z2_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8))))))))
|
||||
(local.set $z3_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16))))))))
|
||||
(local.set $z4_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24))))))))
|
||||
(call $eth.callDataCopy (i32.const 0) (i32.wrap_i64 (local.get $x4)) (i32.const 32))
|
||||
(local.set $z1_1 (call $endian_swap (i64.load (i32.const 0))))
|
||||
(local.set $z2_1 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 8)))))
|
||||
(local.set $z3_1 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 16)))))
|
||||
(local.set $z4_1 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 24)))))
|
||||
(local.set $z1 (local.get $z1_1))
|
||||
(local.set $z2 (local.get $z2_1))
|
||||
(local.set $z3 (local.get $z3_1))
|
||||
@ -556,16 +556,16 @@ Text representation:
|
||||
)
|
||||
|
||||
(func $mstore_internal
|
||||
(param $pos i64)
|
||||
(param $pos i32)
|
||||
(param $y1 i64)
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(block $label__19
|
||||
(i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 8))))) (call $endian_swap (local.get $y2)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 16))))) (call $endian_swap (local.get $y3)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4)))
|
||||
(i64.store (local.get $pos) (call $endian_swap (local.get $y1)))
|
||||
(i64.store (i32.add (local.get $pos) (i32.const 8)) (call $endian_swap (local.get $y2)))
|
||||
(i64.store (i32.add (local.get $pos) (i32.const 16)) (call $endian_swap (local.get $y3)))
|
||||
(i64.store (i32.add (local.get $pos) (i32.const 24)) (call $endian_swap (local.get $y4)))
|
||||
)
|
||||
)
|
||||
|
||||
@ -579,9 +579,9 @@ Text representation:
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(block $label__20
|
||||
(call $mstore_internal (i64.const 0) (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))
|
||||
(call $mstore_internal (i64.const 32) (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))
|
||||
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
|
||||
(call $mstore_internal (i32.const 0) (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))
|
||||
(call $mstore_internal (i32.const 32) (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))
|
||||
(call $eth.storageStore (i32.const 0) (i32.const 32))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
(func $main
|
||||
(local $_1 i64)
|
||||
(local $p i64)
|
||||
(local $r i64)
|
||||
(local $p i32)
|
||||
(local $r i32)
|
||||
(local $_2 i64)
|
||||
(local $z1 i64)
|
||||
(local $z2 i64)
|
||||
@ -19,19 +19,19 @@
|
||||
(block $label_
|
||||
(local.set $_1 (i64.const 0))
|
||||
(local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64)))
|
||||
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
|
||||
(local.set $r (i32.add (local.get $p) (i32.const 64)))
|
||||
(if (i32.lt_u (local.get $r) (local.get $p)) (then
|
||||
(unreachable)))
|
||||
(local.set $_2 (call $endian_swap (local.get $_1)))
|
||||
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $_2))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $_2))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $_2))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (i64.const 128)))
|
||||
(call $eth.getCallValue (i32.wrap_i64 (i64.const 0)))
|
||||
(local.set $z1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0)))))
|
||||
(local.set $z2 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8))))))))
|
||||
(local.set $z3 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16))))))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24)))))))))))))) (i64.const 0)) (then
|
||||
(i64.store (local.get $r) (local.get $_2))
|
||||
(i64.store (i32.add (local.get $r) (i32.const 8)) (local.get $_2))
|
||||
(i64.store (i32.add (local.get $r) (i32.const 16)) (local.get $_2))
|
||||
(i64.store (i32.add (local.get $r) (i32.const 24)) (call $endian_swap (i64.const 128)))
|
||||
(call $eth.getCallValue (i32.const 0))
|
||||
(local.set $z1 (call $endian_swap (i64.load (i32.const 0))))
|
||||
(local.set $z2 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 8)))))
|
||||
(local.set $z3 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 16)))))
|
||||
(if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 24)))))))) (then
|
||||
(call $revert (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))))
|
||||
(local.set $_3 (datasize \"C_2_deployed\"))
|
||||
(call $codecopy (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\") (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||
@ -44,14 +44,14 @@
|
||||
(param $x2 i64)
|
||||
(param $x3 i64)
|
||||
(param $x4 i64)
|
||||
(result i64)
|
||||
(local $v i64)
|
||||
(result i32)
|
||||
(local $v i32)
|
||||
(block $label__1
|
||||
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3))) (then
|
||||
(unreachable)))
|
||||
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then
|
||||
(if (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32))) (then
|
||||
(unreachable)))
|
||||
(local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4))))
|
||||
(local.set $v (i32.wrap_i64 (local.get $x4)))
|
||||
|
||||
)
|
||||
(local.get $v)
|
||||
@ -62,13 +62,13 @@
|
||||
(param $x2 i64)
|
||||
(param $x3 i64)
|
||||
(param $x4 i64)
|
||||
(result i64)
|
||||
(local $r i64)
|
||||
(local $p i64)
|
||||
(result i32)
|
||||
(local $r i32)
|
||||
(local $p i32)
|
||||
(block $label__2
|
||||
(local.set $p (call $u256_to_i32 (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)))
|
||||
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
|
||||
(local.set $r (i32.add (local.get $p) (i32.const 64)))
|
||||
(if (i32.lt_u (local.get $r) (local.get $p)) (then
|
||||
(unreachable)))
|
||||
|
||||
)
|
||||
@ -89,7 +89,7 @@
|
||||
(param $z3 i64)
|
||||
(param $z4 i64)
|
||||
(block $label__3
|
||||
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4))))
|
||||
(call $eth.codeCopy (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)) (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4)))
|
||||
)
|
||||
)
|
||||
|
||||
@ -140,7 +140,7 @@
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(block $label__7
|
||||
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))))
|
||||
(call $eth.finish (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))
|
||||
)
|
||||
)
|
||||
|
||||
@ -154,7 +154,7 @@
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(block $label__8
|
||||
(call $eth.revert (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))))
|
||||
(call $eth.revert (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
--strict-assembly --output-dir /tmp/
|
@ -0,0 +1 @@
|
||||
The following options are invalid in assembly mode: --output-dir, --gas, --combined-json, --optimize-yul, --no-optimize-yul. Optimization is disabled by default and can be enabled with --optimize.
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
sstore(0, 1)
|
||||
}
|
@ -0,0 +1 @@
|
||||
--yul-dialect evm --machine ewasm
|
1
test/cmdlineTests/strict_asm_options_in_non_asm_mode/err
Normal file
1
test/cmdlineTests/strict_asm_options_in_non_asm_mode/err
Normal file
@ -0,0 +1 @@
|
||||
--yul-dialect and --machine are only valid in assembly mode.
|
@ -0,0 +1 @@
|
||||
1
|
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
function f() public pure {}
|
||||
}
|
@ -20,24 +20,24 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d01000000010c0260000060047e7e7e7e017e020100030302000105030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00000a4a022201047e024002404201420242034204100121002300210123012102230221030b0b0b2501047e0240200121042002210720002105200321060b20052400200624012007240220040b
|
||||
0061736d01000000010c0260000060047f7e7e7f017e020100030302000105030100010610037f0141000b7f0141000b7e0142000b071102066d656d6f72790200046d61696e00000a52022603017e027f017e024002404101420242034104100121002300210123012102230221030b0b0b2903017e027f017e0240200121042002210720002105200321060b20052400200624012007240220040b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
(memory $memory (export "memory") 1)
|
||||
(export "main" (func $main))
|
||||
(global $global_ (mut i64) (i64.const 0))
|
||||
(global $global__1 (mut i64) (i64.const 0))
|
||||
(global $global_ (mut i32) (i32.const 0))
|
||||
(global $global__1 (mut i32) (i32.const 0))
|
||||
(global $global__2 (mut i64) (i64.const 0))
|
||||
|
||||
(func $main
|
||||
(local $m i64)
|
||||
(local $n i64)
|
||||
(local $p i64)
|
||||
(local $n i32)
|
||||
(local $p i32)
|
||||
(local $q i64)
|
||||
(block $label_
|
||||
(block
|
||||
(local.set $m (call $multireturn (i64.const 1) (i64.const 2) (i64.const 3) (i64.const 4)))
|
||||
(local.set $m (call $multireturn (i32.const 1) (i64.const 2) (i64.const 3) (i32.const 4)))
|
||||
(local.set $n (global.get $global_))
|
||||
(local.set $p (global.get $global__1))
|
||||
(local.set $q (global.get $global__2))
|
||||
@ -48,14 +48,14 @@ Text representation:
|
||||
)
|
||||
|
||||
(func $multireturn
|
||||
(param $a i64)
|
||||
(param $a i32)
|
||||
(param $b i64)
|
||||
(param $c i64)
|
||||
(param $d i64)
|
||||
(param $d i32)
|
||||
(result i64)
|
||||
(local $x i64)
|
||||
(local $y i64)
|
||||
(local $z i64)
|
||||
(local $y i32)
|
||||
(local $z i32)
|
||||
(local $w i64)
|
||||
(block $label__3
|
||||
(local.set $x (local.get $b))
|
||||
|
@ -11,7 +11,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0f010d0002404201a7422a3c00000b0b
|
||||
0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0e010c0002404101422a3c00000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
@ -20,7 +20,7 @@ Text representation:
|
||||
|
||||
(func $main
|
||||
(block $label_
|
||||
(i64.store8 (i32.wrap_i64 (i64.const 1)) (i64.const 42))
|
||||
(i64.store8 (i32.const 1) (i64.const 42))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -63,27 +63,19 @@ evmasm::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
|
||||
DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion());
|
||||
solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "");
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
|
||||
if (!Error::containsOnlyWarnings(errorReporter.errors()))
|
||||
return AssemblyItems();
|
||||
}
|
||||
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*sourceUnit));
|
||||
if (!Error::containsOnlyWarnings(errorReporter.errors()))
|
||||
return AssemblyItems();
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
{
|
||||
BOOST_REQUIRE_NO_THROW(declarationTypeChecker.check(*node));
|
||||
if (!Error::containsOnlyWarnings(errorReporter.errors()))
|
||||
return AssemblyItems();
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
TypeChecker checker(solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||
BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*contract));
|
||||
if (!Error::containsOnlyWarnings(errorReporter.errors()))
|
||||
return AssemblyItems();
|
||||
}
|
||||
TypeChecker checker(solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||
BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*sourceUnit));
|
||||
if (!Error::containsOnlyWarnings(errorReporter.errors()))
|
||||
return AssemblyItems();
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
|
@ -118,19 +118,12 @@ bytes compileFirstExpression(
|
||||
GlobalContext globalContext;
|
||||
NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*contract), "Resolving names failed");
|
||||
BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed");
|
||||
DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion());
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
BOOST_REQUIRE(declarationTypeChecker.check(*node));
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
ErrorReporter errorReporter(errors);
|
||||
TypeChecker typeChecker(solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||
BOOST_REQUIRE(typeChecker.checkTypeRequirements(*contract));
|
||||
}
|
||||
TypeChecker typeChecker(solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||
BOOST_REQUIRE(typeChecker.checkTypeRequirements(*sourceUnit));
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
|
@ -1150,6 +1150,74 @@ BOOST_AUTO_TEST_CASE(dev_constructor_and_function)
|
||||
checkNatspec(sourceCode, "test", natspec, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(slash4)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
//// @notice lorem ipsum
|
||||
function f() public { }
|
||||
}
|
||||
)";
|
||||
|
||||
char const* natspec = R"( { "methods": {} } )";
|
||||
|
||||
checkNatspec(sourceCode, "test", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(star3)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
/***
|
||||
* @notice lorem ipsum
|
||||
*/
|
||||
function f() public { }
|
||||
}
|
||||
)";
|
||||
|
||||
char const* natspec = R"( { "methods": {} } )";
|
||||
|
||||
checkNatspec(sourceCode, "test", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(slash3_slash3)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
/// @notice lorem
|
||||
/// ipsum
|
||||
function f() public { }
|
||||
}
|
||||
)";
|
||||
|
||||
char const* natspec = R"ABCDEF({
|
||||
"methods": {
|
||||
"f()": { "notice": "lorem ipsum" }
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "test", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(slash3_slash4)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
/// @notice lorem
|
||||
//// ipsum
|
||||
function f() public { }
|
||||
}
|
||||
)";
|
||||
|
||||
char const* natspec = R"ABCDEF({
|
||||
"methods": {
|
||||
"f()": { "notice": "lorem" }
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "test", natspec, true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
12
test/libsolidity/semanticTests/dirty_calldata_bytes.sol
Normal file
12
test/libsolidity/semanticTests/dirty_calldata_bytes.sol
Normal file
@ -0,0 +1,12 @@
|
||||
contract C {
|
||||
function f(bytes calldata b) public returns (bool correct) {
|
||||
byte a = b[3];
|
||||
uint r;
|
||||
assembly {
|
||||
r := a
|
||||
}
|
||||
correct = r == (0x64 << 248);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f(bytes): 0x20, 0x04, "dead" -> true
|
@ -0,0 +1,12 @@
|
||||
contract C {
|
||||
function f(int16[] calldata a) external returns (bool correct) {
|
||||
uint32 x = uint32(a[1]);
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = r == 0x7fff;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f(int16[]): 0x20, 0x02, 0x7fff, 0x7fff -> true
|
@ -0,0 +1,16 @@
|
||||
contract C {
|
||||
bytes x;
|
||||
function f() public returns (uint r) {
|
||||
bytes memory m = "tmp";
|
||||
assembly {
|
||||
mstore(m, 8)
|
||||
mstore(add(m, 32), "deadbeef15dead")
|
||||
}
|
||||
x = m;
|
||||
assembly {
|
||||
r := sload(x_slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> 0x6465616462656566313564656164000000000000000000000000000000000010
|
@ -0,0 +1,18 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
struct S {
|
||||
uint16[] m;
|
||||
}
|
||||
function f(S calldata s) public pure returns (bool correct) {
|
||||
int8 x = int8(s.m[0]);
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = r == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f((uint16[])): 0x20, 0x20, 0x01, 0x0180 -> true
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
function f() public pure returns (bool correct) {
|
||||
uint8[] memory m = new uint8[](1);
|
||||
assembly {
|
||||
mstore(add(m, 32), 258)
|
||||
}
|
||||
uint8 x = m[0];
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = (m[0] == 0x02) && (r == 0x02);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> true
|
18
test/libsolidity/semanticTests/viaYul/dirty_memory_int32.sol
Normal file
18
test/libsolidity/semanticTests/viaYul/dirty_memory_int32.sol
Normal file
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
function f() public pure returns (bool correct) {
|
||||
uint256[1] memory m;
|
||||
assembly {
|
||||
mstore(m, 0xdeadbeef15dead)
|
||||
}
|
||||
int32 x = int32(m[0]);
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = (m[0] == 0xdeadbeef15dead) && (r == (((2 ** 224 - 1) << 32) | 0xef15dead));
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> true
|
@ -1,15 +0,0 @@
|
||||
contract C {
|
||||
function f() public pure returns (uint8 x, bool a, bool b) {
|
||||
uint8[1] memory m;
|
||||
assembly {
|
||||
mstore(m, 257)
|
||||
}
|
||||
x = m[0];
|
||||
a = (m[0] == 0x01);
|
||||
b = (m[0] == 0x0101);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1, true, false
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
function f() public pure returns (bool correct) {
|
||||
uint8[1] memory m;
|
||||
assembly {
|
||||
mstore(m, 257)
|
||||
}
|
||||
uint8 x = m[0];
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = (m[0] == 0x01) && (r == 0x01);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,22 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint8[] m;
|
||||
}
|
||||
function f() public pure returns (bool correct) {
|
||||
S memory s;
|
||||
s.m = new uint8[](1);
|
||||
assembly {
|
||||
mstore(add(s, 64), 257)
|
||||
}
|
||||
uint8 x = s.m[0];
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = r == 0x01;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
function f() public pure returns (bool correct) {
|
||||
uint256[1] memory m;
|
||||
assembly {
|
||||
mstore(m, 0xdeadbeef15dead)
|
||||
}
|
||||
uint32 x = uint32(m[0]);
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = (r == 0xef15dead) && (m[0] == 0xdeadbeef15dead);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
bytes b;
|
||||
function f() public returns (bool correct) {
|
||||
assembly {
|
||||
sstore(b_slot, or("deadbeef", 0x08))
|
||||
}
|
||||
byte s = b[3];
|
||||
uint r;
|
||||
assembly {
|
||||
r := s
|
||||
}
|
||||
correct = r == (0x64 << 248);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,20 @@
|
||||
contract C {
|
||||
bytes b;
|
||||
function f() public returns (bool correct) {
|
||||
assembly {
|
||||
sstore(b_slot, 0x41)
|
||||
mstore(0, b_slot)
|
||||
sstore(keccak256(0, 0x20), "deadbeefdeadbeefdeadbeefdeadbeef")
|
||||
}
|
||||
byte s = b[31];
|
||||
uint r;
|
||||
assembly {
|
||||
r := s
|
||||
}
|
||||
correct = r == (0x66 << 248);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,20 @@
|
||||
contract C {
|
||||
uint8[] s;
|
||||
function f() public returns (bool correct) {
|
||||
s.push();
|
||||
assembly {
|
||||
mstore(0, s_slot)
|
||||
sstore(keccak256(0, 0x20), 257)
|
||||
}
|
||||
uint8 x = s[0];
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = (s[0] == 0x01) && (r == 0x01);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
uint8[1] s;
|
||||
function f() public returns (bool correct) {
|
||||
assembly {
|
||||
sstore(s_slot, 257)
|
||||
}
|
||||
uint8 x = s[0];
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = (s[0] == 0x01) && (r == 0x01);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
@ -0,0 +1,23 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint8[] m;
|
||||
}
|
||||
S s;
|
||||
function f() public returns (bool correct) {
|
||||
s.m.push();
|
||||
assembly {
|
||||
mstore(0, s_slot)
|
||||
sstore(keccak256(0, 0x20), 257)
|
||||
}
|
||||
uint8 x = s.m[0];
|
||||
uint r;
|
||||
assembly {
|
||||
r := x
|
||||
}
|
||||
correct = r == 0x01;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
Loading…
Reference in New Issue
Block a user