mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9038 from ethereum/develop
Merge develop into breaking.
This commit is contained in:
commit
894478ff8c
@ -20,6 +20,8 @@ Bugfixes:
|
||||
### 0.6.9 (unreleased)
|
||||
|
||||
Language Features:
|
||||
* Permit calldata location for all variables.
|
||||
* Yul: EVM instruction `pc()` is marked deprecated and will be removed in the next breaking release.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
@ -31,6 +33,9 @@ Compiler Features:
|
||||
Bugfixes:
|
||||
* Optimizer: Fixed a bug in BlockDeDuplicator.
|
||||
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
|
||||
* Type Checker: Disallow inline arrays of non-nameable types.
|
||||
* Type Checker: Fix internal compiler error when accessing members of array slices.
|
||||
* Type Checker: Fix internal compiler error when trying to decode too large static arrays.
|
||||
* NatSpec: DocString block is terminated when encountering an empty line.
|
||||
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
|
||||
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
|
||||
|
@ -13,8 +13,7 @@ arrays and mappings. If you use a reference type, you always have to explicitly
|
||||
provide the data area where the type is stored: ``memory`` (whose lifetime is limited
|
||||
to an external function call), ``storage`` (the location where the state variables
|
||||
are stored, where the lifetime is limited to the lifetime of a contract)
|
||||
or ``calldata`` (special data location that contains the function arguments,
|
||||
only available for external function call parameters).
|
||||
or ``calldata`` (special data location that contains the function arguments).
|
||||
|
||||
An assignment or type conversion that changes the data location will always incur an automatic copy operation,
|
||||
while assignments inside the same data location only copy in some cases for storage types.
|
||||
@ -26,9 +25,9 @@ Data location
|
||||
|
||||
Every reference type has an additional
|
||||
annotation, the "data location", about where it is stored. There are three data locations:
|
||||
``memory``, ``storage`` and ``calldata``. Calldata is only valid for parameters of external contract
|
||||
functions and is required for this type of parameter. Calldata is a non-modifiable,
|
||||
``memory``, ``storage`` and ``calldata``. Calldata is a non-modifiable,
|
||||
non-persistent area where function arguments are stored, and behaves mostly like memory.
|
||||
It is required for parameters of external functions but can also be used for other variables.
|
||||
|
||||
|
||||
.. note::
|
||||
@ -36,6 +35,12 @@ non-persistent area where function arguments are stored, and behaves mostly like
|
||||
depending on the kind of variable, function type, etc., but all complex types must now give an explicit
|
||||
data location.
|
||||
|
||||
.. note::
|
||||
If you can, try to use ``calldata`` as data location because it will avoid copies and
|
||||
also makes sure that the data cannot be modified. Arrays and structs with ``calldata``
|
||||
data location can also be returned from functions, but it is not possible to
|
||||
allocate such types.
|
||||
|
||||
.. _data-location-assignment:
|
||||
|
||||
Data location and assignment behaviour
|
||||
|
@ -29,6 +29,10 @@
|
||||
|
||||
#include <boost/multiprecision/detail/min_max.hpp>
|
||||
|
||||
#include <libyul/Dialect.h>
|
||||
#include <libyul/backends/evm/EVMDialect.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
@ -657,12 +661,37 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
|
||||
return rules;
|
||||
}
|
||||
|
||||
template<class Pattern>
|
||||
std::vector<SimplificationRule<Pattern>> evmRuleList(
|
||||
langutil::EVMVersion _evmVersion,
|
||||
Pattern,
|
||||
Pattern,
|
||||
Pattern,
|
||||
Pattern,
|
||||
Pattern,
|
||||
Pattern,
|
||||
Pattern
|
||||
)
|
||||
{
|
||||
using Builtins = typename Pattern::Builtins;
|
||||
std::vector<SimplificationRule<Pattern>> rules;
|
||||
|
||||
if (_evmVersion.hasSelfBalance())
|
||||
rules.push_back({
|
||||
Builtins::BALANCE(Instruction::ADDRESS),
|
||||
[]() -> Pattern { return Instruction::SELFBALANCE; }, false
|
||||
});
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/// @returns a list of simplification rules given certain match placeholders.
|
||||
/// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions.
|
||||
/// The simplifications should never change the order of evaluation of
|
||||
/// arbitrary operations.
|
||||
template <class Pattern>
|
||||
std::vector<SimplificationRule<Pattern>> simplificationRuleList(
|
||||
std::optional<langutil::EVMVersion> _evmVersion,
|
||||
Pattern A,
|
||||
Pattern B,
|
||||
Pattern C,
|
||||
@ -691,6 +720,10 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
|
||||
rules += simplificationRuleListPart7(A, B, C, W, X);
|
||||
rules += simplificationRuleListPart8(A, B, C, W, X);
|
||||
rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z);
|
||||
|
||||
if (_evmVersion.has_value())
|
||||
rules += evmRuleList(*_evmVersion, A, B, C, W, X, Y, Z);
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ Rules::Rules()
|
||||
Y.setMatchGroup(6, m_matchGroups);
|
||||
Z.setMatchGroup(7, m_matchGroups);
|
||||
|
||||
addRules(simplificationRuleList(A, B, C, W, X, Y, Z));
|
||||
addRules(simplificationRuleList(nullopt, A, B, C, W, X, Y, Z));
|
||||
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,8 @@ bool hasEqualNameAndParameters(T const& _a, B const& _b)
|
||||
{
|
||||
return
|
||||
_a.name() == _b.name() &&
|
||||
FunctionType(_a).asCallableFunction(false)->hasEqualParameterTypes(
|
||||
*FunctionType(_b).asCallableFunction(false)
|
||||
FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
|
||||
*FunctionType(_b).asExternallyCallableFunction(false)
|
||||
);
|
||||
}
|
||||
|
||||
@ -345,7 +345,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
|
||||
// under non error circumstances this should be true
|
||||
if (functionType->interfaceFunctionType())
|
||||
externalDeclarations[functionType->externalSignature()].emplace_back(
|
||||
f, functionType->asCallableFunction(false)
|
||||
f, functionType->asExternallyCallableFunction(false)
|
||||
);
|
||||
}
|
||||
for (VariableDeclaration const* v: contract->stateVariables())
|
||||
@ -355,7 +355,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
|
||||
// under non error circumstances this should be true
|
||||
if (functionType->interfaceFunctionType())
|
||||
externalDeclarations[functionType->externalSignature()].emplace_back(
|
||||
v, functionType->asCallableFunction(false)
|
||||
v, functionType->asExternallyCallableFunction(false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,10 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
|
||||
case VariableOccurrence::Kind::Return:
|
||||
if (unassignedVariables.count(&variableOccurrence.declaration()))
|
||||
{
|
||||
if (variableOccurrence.declaration().type()->dataStoredIn(DataLocation::Storage))
|
||||
if (
|
||||
variableOccurrence.declaration().type()->dataStoredIn(DataLocation::Storage) ||
|
||||
variableOccurrence.declaration().type()->dataStoredIn(DataLocation::CallData)
|
||||
)
|
||||
// Merely store the unassigned access. We do not generate an error right away, since this
|
||||
// path might still always revert. It is only an error if this is propagated to the exit
|
||||
// node of the function (i.e. there is a path with an uninitialized access).
|
||||
@ -135,13 +138,16 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
|
||||
if (variableOccurrence->occurrence())
|
||||
ssl.append("The variable was declared here.", variableOccurrence->declaration().location());
|
||||
|
||||
bool isStorage = variableOccurrence->declaration().type()->dataStoredIn(DataLocation::Storage);
|
||||
m_errorReporter.typeError(
|
||||
3464_error,
|
||||
variableOccurrence->occurrence() ?
|
||||
*variableOccurrence->occurrence() :
|
||||
variableOccurrence->declaration().location(),
|
||||
ssl,
|
||||
string("This variable is of storage pointer type and can be ") +
|
||||
"This variable is of " +
|
||||
string(isStorage ? "storage" : "calldata") +
|
||||
" pointer type and can be " +
|
||||
(variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") +
|
||||
" without prior assignment, which would lead to undefined behaviour."
|
||||
);
|
||||
|
@ -151,7 +151,7 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
|
||||
{
|
||||
_typeName.annotation().type = TypeProvider::emptyTuple();
|
||||
m_errorReporter.fatalTypeError(
|
||||
9755_error,
|
||||
5172_error,
|
||||
_typeName.location(),
|
||||
"Name has to refer to a struct, enum or contract."
|
||||
);
|
||||
@ -176,7 +176,7 @@ bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
|
||||
break;
|
||||
default:
|
||||
m_errorReporter.fatalTypeError(
|
||||
7653_error,
|
||||
6012_error,
|
||||
_typeName.location(),
|
||||
"Invalid visibility, can only be \"external\" or \"internal\"."
|
||||
);
|
||||
@ -186,7 +186,7 @@ bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
|
||||
if (_typeName.isPayable() && _typeName.visibility() != Visibility::External)
|
||||
{
|
||||
m_errorReporter.fatalTypeError(
|
||||
6138_error,
|
||||
7415_error,
|
||||
_typeName.location(),
|
||||
"Only external function types can be payable."
|
||||
);
|
||||
@ -246,7 +246,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
||||
}
|
||||
if (baseType->storageBytes() == 0)
|
||||
m_errorReporter.fatalTypeError(
|
||||
9390_error,
|
||||
6493_error,
|
||||
_typeName.baseType().location(),
|
||||
"Illegal base type of storage size zero for array."
|
||||
);
|
||||
@ -259,16 +259,16 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
||||
u256 lengthValue = 0;
|
||||
if (!lengthType || !lengthType->mobileType())
|
||||
m_errorReporter.typeError(
|
||||
8922_error,
|
||||
5462_error,
|
||||
length->location(),
|
||||
"Invalid array length, expected integer literal or constant expression."
|
||||
);
|
||||
else if (lengthType->isZero())
|
||||
m_errorReporter.typeError(1220_error, length->location(), "Array with zero length specified.");
|
||||
m_errorReporter.typeError(1406_error, length->location(), "Array with zero length specified.");
|
||||
else if (lengthType->isFractional())
|
||||
m_errorReporter.typeError(4323_error, length->location(), "Array with fractional length specified.");
|
||||
m_errorReporter.typeError(3208_error, length->location(), "Array with fractional length specified.");
|
||||
else if (lengthType->isNegative())
|
||||
m_errorReporter.typeError(9308_error, length->location(), "Array with negative length specified.");
|
||||
m_errorReporter.typeError(3658_error, length->location(), "Array with negative length specified.");
|
||||
else
|
||||
lengthValue = lengthType->literalValue(nullptr);
|
||||
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue);
|
||||
@ -345,7 +345,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||
errorString += " for variable";
|
||||
}
|
||||
errorString += ", but " + locationToString(varLoc) + " was given.";
|
||||
m_errorReporter.typeError(6160_error, _variable.location(), errorString);
|
||||
m_errorReporter.typeError(6651_error, _variable.location(), errorString);
|
||||
|
||||
solAssert(!allowedDataLocations.empty(), "");
|
||||
varLoc = *allowedDataLocations.begin();
|
||||
|
@ -311,8 +311,8 @@ Token OverrideProxy::functionKind() const
|
||||
FunctionType const* OverrideProxy::functionType() const
|
||||
{
|
||||
return std::visit(GenericVisitor{
|
||||
[&](FunctionDefinition const* _item) { return FunctionType(*_item).asCallableFunction(false); },
|
||||
[&](VariableDeclaration const* _item) { return FunctionType(*_item).asCallableFunction(false); },
|
||||
[&](FunctionDefinition const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
|
||||
[&](VariableDeclaration const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
|
||||
[&](ModifierDefinition const*) -> FunctionType const* { solAssert(false, "Requested function type of modifier."); return nullptr; }
|
||||
}, m_item);
|
||||
}
|
||||
@ -559,7 +559,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
2837_error,
|
||||
6959_error,
|
||||
"Overriding function changes state mutability from \"" +
|
||||
stateMutabilityToString(_super.stateMutability()) +
|
||||
"\" to \"" +
|
||||
|
@ -119,7 +119,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
||||
else
|
||||
errorMessage += " Did you mean " + std::move(suggestions) + "?";
|
||||
}
|
||||
m_errorReporter.declarationError(8051_error, _identifier.location(), errorMessage);
|
||||
m_errorReporter.declarationError(7576_error, _identifier.location(), errorMessage);
|
||||
}
|
||||
else if (declarations.size() == 1)
|
||||
_identifier.annotation().referencedDeclaration = declarations.front();
|
||||
@ -157,7 +157,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
||||
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
||||
if (!declaration)
|
||||
{
|
||||
m_errorReporter.fatalDeclarationError(7556_error, _typeName.location(), "Identifier not found or not unique.");
|
||||
m_errorReporter.fatalDeclarationError(7920_error, _typeName.location(), "Identifier not found or not unique.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
if (realName.empty())
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
9553_error,
|
||||
4794_error,
|
||||
_identifier.location,
|
||||
"In variable names _slot and _offset can only be used as a suffix."
|
||||
);
|
||||
@ -221,7 +221,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
if (declarations.size() > 1)
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
8827_error,
|
||||
4718_error,
|
||||
_identifier.location,
|
||||
"Multiple matching identifiers. Resolving overloaded identifiers is not supported."
|
||||
);
|
||||
@ -233,7 +233,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
if (var->isLocalVariable() && m_yulInsideFunction)
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
8477_error,
|
||||
6578_error,
|
||||
_identifier.location,
|
||||
"Cannot access local Solidity variables from inside an inline assembly function."
|
||||
);
|
||||
@ -255,7 +255,7 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
||||
string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
|
||||
if (isSlot || isOffset)
|
||||
m_errorReporter.declarationError(
|
||||
8820_error,
|
||||
9155_error,
|
||||
identifier.location,
|
||||
"In variable declarations _slot and _offset can not be used as a suffix."
|
||||
);
|
||||
@ -269,7 +269,7 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
||||
ssl.append("The shadowed declaration is here:", decl->location());
|
||||
if (!ssl.infos.empty())
|
||||
m_errorReporter.declarationError(
|
||||
6005_error,
|
||||
3859_error,
|
||||
identifier.location,
|
||||
ssl,
|
||||
namePrefix.size() < identifier.name.str().size() ?
|
||||
|
@ -273,6 +273,7 @@ bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
"The msize instruction cannot be used when the Yul optimizer is activated because "
|
||||
"it can change its semantics. Either disable the Yul optimizer or do not use the instruction."
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -193,6 +193,18 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
||||
typeArgument->location(),
|
||||
"Decoding type " + actualType->toString(false) + " not supported."
|
||||
);
|
||||
|
||||
if (auto referenceType = dynamic_cast<ReferenceType const*>(actualType))
|
||||
{
|
||||
auto result = referenceType->validForLocation(referenceType->location());
|
||||
if (!result)
|
||||
m_errorReporter.typeError(
|
||||
6118_error,
|
||||
typeArgument->location(),
|
||||
result.message()
|
||||
);
|
||||
}
|
||||
|
||||
components.push_back(actualType);
|
||||
}
|
||||
else
|
||||
@ -1511,6 +1523,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
if (!inlineArrayType)
|
||||
m_errorReporter.fatalTypeError(6378_error, _tuple.location(), "Unable to deduce common type for array elements.");
|
||||
else if (!inlineArrayType->nameable())
|
||||
m_errorReporter.fatalTypeError(
|
||||
9656_error,
|
||||
_tuple.location(),
|
||||
"Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element."
|
||||
);
|
||||
else if (!inlineArrayType->canLiveOutsideStorage())
|
||||
m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
|
||||
|
||||
@ -1996,19 +2014,16 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
|
||||
bool const isStructConstructorCall =
|
||||
_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall;
|
||||
|
||||
string msg;
|
||||
|
||||
if (isVariadic)
|
||||
msg +=
|
||||
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
|
||||
string msg = isVariadic ?
|
||||
"Need at least " +
|
||||
toString(parameterTypes.size()) +
|
||||
" arguments for " +
|
||||
string(isStructConstructorCall ? "struct constructor" : "function call") +
|
||||
", but provided only " +
|
||||
toString(arguments.size()) +
|
||||
".";
|
||||
else
|
||||
msg +=
|
||||
"."
|
||||
:
|
||||
"Wrong argument count for " +
|
||||
string(isStructConstructorCall ? "struct constructor" : "function call") +
|
||||
": " +
|
||||
@ -2018,49 +2033,64 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
|
||||
toString(parameterTypes.size()) +
|
||||
".";
|
||||
|
||||
// Extend error message in case we try to construct a struct with mapping member.
|
||||
if (isStructConstructorCall)
|
||||
{
|
||||
/// For error message: Struct members that were removed during conversion to memory.
|
||||
TypePointer const expressionType = type(_functionCall.expression());
|
||||
TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
|
||||
auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
|
||||
set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
|
||||
|
||||
if (!membersRemovedForStructConstructor.empty())
|
||||
// Extend error message in case we try to construct a struct with mapping member.
|
||||
if (isStructConstructorCall)
|
||||
{
|
||||
msg += " Members that have to be skipped in memory:";
|
||||
for (auto const& member: membersRemovedForStructConstructor)
|
||||
msg += " " + member;
|
||||
/// For error message: Struct members that were removed during conversion to memory.
|
||||
TypePointer const expressionType = type(_functionCall.expression());
|
||||
auto const& t = dynamic_cast<TypeType const&>(*expressionType);
|
||||
auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
|
||||
set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
|
||||
|
||||
if (!membersRemovedForStructConstructor.empty())
|
||||
{
|
||||
msg += " Members that have to be skipped in memory:";
|
||||
for (auto const& member: membersRemovedForStructConstructor)
|
||||
msg += " " + member;
|
||||
}
|
||||
|
||||
return { isVariadic ? 1123_error : 9755_error, msg };
|
||||
}
|
||||
}
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::BareCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
|
||||
_functionType->kind() == FunctionType::Kind::BareDelegateCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareStaticCall
|
||||
)
|
||||
{
|
||||
if (arguments.empty())
|
||||
msg +=
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::BareCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
|
||||
_functionType->kind() == FunctionType::Kind::BareDelegateCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareStaticCall
|
||||
)
|
||||
{
|
||||
if (arguments.empty())
|
||||
return {
|
||||
isVariadic ? 7653_error : 6138_error,
|
||||
msg +
|
||||
" This function requires a single bytes argument."
|
||||
" Use \"\" as argument to provide empty calldata."
|
||||
};
|
||||
else
|
||||
return {
|
||||
isVariadic ? 9390_error : 8922_error,
|
||||
msg +
|
||||
" This function requires a single bytes argument."
|
||||
" If all your arguments are value types, you can use"
|
||||
" abi.encode(...) to properly generate it."
|
||||
};
|
||||
}
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::KECCAK256 ||
|
||||
_functionType->kind() == FunctionType::Kind::SHA256 ||
|
||||
_functionType->kind() == FunctionType::Kind::RIPEMD160
|
||||
)
|
||||
return {
|
||||
isVariadic ? 1220_error : 4323_error,
|
||||
msg +
|
||||
" This function requires a single bytes argument."
|
||||
" Use \"\" as argument to provide empty calldata.";
|
||||
" Use abi.encodePacked(...) to obtain the pre-0.5.0"
|
||||
" behaviour or abi.encode(...) to use ABI encoding."
|
||||
};
|
||||
else
|
||||
msg +=
|
||||
" This function requires a single bytes argument."
|
||||
" If all your arguments are value types, you can use"
|
||||
" abi.encode(...) to properly generate it.";
|
||||
}
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::KECCAK256 ||
|
||||
_functionType->kind() == FunctionType::Kind::SHA256 ||
|
||||
_functionType->kind() == FunctionType::Kind::RIPEMD160
|
||||
)
|
||||
msg +=
|
||||
" This function requires a single bytes argument."
|
||||
" Use abi.encodePacked(...) to obtain the pre-0.5.0"
|
||||
" behaviour or abi.encode(...) to use ABI encoding.";
|
||||
m_errorReporter.typeError(1093_error, _functionCall.location(), msg);
|
||||
return { isVariadic ? 9308_error : 6160_error, msg };
|
||||
}();
|
||||
|
||||
m_errorReporter.typeError(errorId, _functionCall.location(), description);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2136,33 +2166,43 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
|
||||
solAssert(!!paramArgMap[i], "unmapped parameter");
|
||||
if (!type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
||||
{
|
||||
string msg =
|
||||
"Invalid type for argument in function call. "
|
||||
"Invalid implicit conversion from " +
|
||||
type(*paramArgMap[i])->toString() +
|
||||
" to " +
|
||||
parameterTypes[i]->toString() +
|
||||
" requested.";
|
||||
if (
|
||||
_functionType->kind() == FunctionType::Kind::BareCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
|
||||
_functionType->kind() == FunctionType::Kind::BareDelegateCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareStaticCall
|
||||
)
|
||||
msg +=
|
||||
" This function requires a single bytes argument."
|
||||
" If all your arguments are value types, you can"
|
||||
" use abi.encode(...) to properly generate it.";
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::KECCAK256 ||
|
||||
_functionType->kind() == FunctionType::Kind::SHA256 ||
|
||||
_functionType->kind() == FunctionType::Kind::RIPEMD160
|
||||
)
|
||||
msg +=
|
||||
" This function requires a single bytes argument."
|
||||
" Use abi.encodePacked(...) to obtain the pre-0.5.0"
|
||||
" behaviour or abi.encode(...) to use ABI encoding.";
|
||||
m_errorReporter.typeError(6706_error, paramArgMap[i]->location(), msg);
|
||||
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
|
||||
string msg =
|
||||
"Invalid type for argument in function call. "
|
||||
"Invalid implicit conversion from " +
|
||||
type(*paramArgMap[i])->toString() +
|
||||
" to " +
|
||||
parameterTypes[i]->toString() +
|
||||
" requested.";
|
||||
if (
|
||||
_functionType->kind() == FunctionType::Kind::BareCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
|
||||
_functionType->kind() == FunctionType::Kind::BareDelegateCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareStaticCall
|
||||
)
|
||||
return {
|
||||
8051_error,
|
||||
msg +
|
||||
" This function requires a single bytes argument."
|
||||
" If all your arguments are value types, you can"
|
||||
" use abi.encode(...) to properly generate it."
|
||||
};
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::KECCAK256 ||
|
||||
_functionType->kind() == FunctionType::Kind::SHA256 ||
|
||||
_functionType->kind() == FunctionType::Kind::RIPEMD160
|
||||
)
|
||||
return {
|
||||
7556_error,
|
||||
msg +
|
||||
" This function requires a single bytes argument."
|
||||
" Use abi.encodePacked(...) to obtain the pre-0.5.0"
|
||||
" behaviour or abi.encode(...) to use ABI encoding."
|
||||
};
|
||||
else
|
||||
return { 9553_error, msg };
|
||||
}();
|
||||
m_errorReporter.typeError(errorId, paramArgMap[i]->location(), description);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2535,7 +2575,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
|
||||
if (possibleMembers.empty())
|
||||
{
|
||||
if (initialMemberCount == 0)
|
||||
if (initialMemberCount == 0 && !dynamic_cast<ArraySliceType const*>(exprType))
|
||||
{
|
||||
// Try to see if the member was removed because it is only available for storage types.
|
||||
auto storageType = TypeProvider::withLocationIfReference(
|
||||
@ -2551,61 +2591,70 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
" outside of storage."
|
||||
);
|
||||
}
|
||||
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
|
||||
|
||||
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
|
||||
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
|
||||
"after argument-dependent lookup in " + exprType->toString() + ".";
|
||||
|
||||
if (auto const& funType = dynamic_cast<FunctionType const*>(exprType))
|
||||
{
|
||||
auto const& t = funType->returnParameterTypes();
|
||||
|
||||
if (memberName == "value")
|
||||
if (auto const* funType = dynamic_cast<FunctionType const*>(exprType))
|
||||
{
|
||||
if (funType->kind() == FunctionType::Kind::Creation)
|
||||
errorMsg = "Constructor for " + t.front()->toString() + " must be payable for member \"value\" to be available.";
|
||||
else if (
|
||||
funType->kind() == FunctionType::Kind::DelegateCall ||
|
||||
funType->kind() == FunctionType::Kind::BareDelegateCall
|
||||
)
|
||||
errorMsg = "Member \"value\" is not allowed in delegated calls due to \"msg.value\" persisting.";
|
||||
else
|
||||
errorMsg = "Member \"value\" is only available for payable functions.";
|
||||
}
|
||||
else if (
|
||||
t.size() == 1 &&
|
||||
(t.front()->category() == Type::Category::Struct ||
|
||||
t.front()->category() == Type::Category::Contract)
|
||||
)
|
||||
errorMsg += " Did you intend to call the function?";
|
||||
}
|
||||
else if (exprType->category() == Type::Category::Contract)
|
||||
{
|
||||
for (auto const& addressMember: TypeProvider::payableAddress()->nativeMembers(nullptr))
|
||||
if (addressMember.name == memberName)
|
||||
TypePointers const& t = funType->returnParameterTypes();
|
||||
|
||||
if (memberName == "value")
|
||||
{
|
||||
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
||||
string varName = var ? var->name() : "...";
|
||||
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
|
||||
break;
|
||||
if (funType->kind() == FunctionType::Kind::Creation)
|
||||
return {
|
||||
8827_error,
|
||||
"Constructor for " + t.front()->toString() + " must be payable for member \"value\" to be available."
|
||||
};
|
||||
else if (
|
||||
funType->kind() == FunctionType::Kind::DelegateCall ||
|
||||
funType->kind() == FunctionType::Kind::BareDelegateCall
|
||||
)
|
||||
return { 8477_error, "Member \"value\" is not allowed in delegated calls due to \"msg.value\" persisting." };
|
||||
else
|
||||
return { 8820_error, "Member \"value\" is only available for payable functions." };
|
||||
}
|
||||
}
|
||||
else if (auto addressType = dynamic_cast<AddressType const*>(exprType))
|
||||
{
|
||||
// Trigger error when using send or transfer with a non-payable fallback function.
|
||||
if (memberName == "send" || memberName == "transfer")
|
||||
{
|
||||
solAssert(
|
||||
addressType->stateMutability() != StateMutability::Payable,
|
||||
"Expected address not-payable as members were not found"
|
||||
);
|
||||
|
||||
errorMsg = "\"send\" and \"transfer\" are only available for objects of type \"address payable\", not \"" + exprType->toString() + "\".";
|
||||
else if (
|
||||
t.size() == 1 && (
|
||||
t.front()->category() == Type::Category::Struct ||
|
||||
t.front()->category() == Type::Category::Contract
|
||||
)
|
||||
)
|
||||
return { 6005_error, errorMsg + " Did you intend to call the function?" };
|
||||
}
|
||||
}
|
||||
else if (exprType->category() == Type::Category::Contract)
|
||||
{
|
||||
for (MemberList::Member const& addressMember: TypeProvider::payableAddress()->nativeMembers(nullptr))
|
||||
if (addressMember.name == memberName)
|
||||
{
|
||||
auto const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
||||
string varName = var ? var->name() : "...";
|
||||
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
|
||||
return { 3125_error, errorMsg };
|
||||
}
|
||||
}
|
||||
else if (auto const* addressType = dynamic_cast<AddressType const*>(exprType))
|
||||
{
|
||||
// Trigger error when using send or transfer with a non-payable fallback function.
|
||||
if (memberName == "send" || memberName == "transfer")
|
||||
{
|
||||
solAssert(
|
||||
addressType->stateMutability() != StateMutability::Payable,
|
||||
"Expected address not-payable as members were not found"
|
||||
);
|
||||
|
||||
return { 9862_error, "\"send\" and \"transfer\" are only available for objects of type \"address payable\", not \"" + exprType->toString() + "\"." };
|
||||
}
|
||||
}
|
||||
|
||||
return { 9582_error, errorMsg };
|
||||
}();
|
||||
|
||||
m_errorReporter.fatalTypeError(
|
||||
4035_error,
|
||||
errorId,
|
||||
_memberAccess.location(),
|
||||
errorMsg
|
||||
description
|
||||
);
|
||||
}
|
||||
else if (possibleMembers.size() > 1)
|
||||
@ -2875,7 +2924,7 @@ bool TypeChecker::visit(IndexRangeAccess const& _access)
|
||||
if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized())
|
||||
m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays.");
|
||||
else if (arrayType->baseType()->isDynamicallyEncoded())
|
||||
m_errorReporter.typeError(1878_error, _access.location(), "Index range access is not supported for arrays with dynamically encoded base types.");
|
||||
m_errorReporter.typeError(2148_error, _access.location(), "Index range access is not supported for arrays with dynamically encoded base types.");
|
||||
_access.annotation().type = TypeProvider::arraySlice(*arrayType);
|
||||
_access.annotation().isLValue = isLValue;
|
||||
_access.annotation().isPure = isPure;
|
||||
@ -3181,17 +3230,17 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
|
||||
if (_expression.annotation().isLValue)
|
||||
return;
|
||||
|
||||
return m_errorReporter.typeError(1123_error, _expression.location(), [&]() {
|
||||
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
|
||||
if (_expression.annotation().isConstant)
|
||||
return "Cannot assign to a constant variable.";
|
||||
return { 6520_error, "Cannot assign to a constant variable." };
|
||||
|
||||
if (auto indexAccess = dynamic_cast<IndexAccess const*>(&_expression))
|
||||
{
|
||||
if (type(indexAccess->baseExpression())->category() == Type::Category::FixedBytes)
|
||||
return "Single bytes in fixed bytes arrays cannot be modified.";
|
||||
return { 4360_error, "Single bytes in fixed bytes arrays cannot be modified." };
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(type(indexAccess->baseExpression())))
|
||||
if (arrayType->dataStoredIn(DataLocation::CallData))
|
||||
return "Calldata arrays are read-only.";
|
||||
return { 6182_error, "Calldata arrays are read-only." };
|
||||
}
|
||||
|
||||
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_expression))
|
||||
@ -3199,18 +3248,20 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
|
||||
if (auto structType = dynamic_cast<StructType const*>(type(memberAccess->expression())))
|
||||
{
|
||||
if (structType->dataStoredIn(DataLocation::CallData))
|
||||
return "Calldata structs are read-only.";
|
||||
return { 4156_error, "Calldata structs are read-only." };
|
||||
}
|
||||
else if (dynamic_cast<ArrayType const*>(type(memberAccess->expression())))
|
||||
if (memberAccess->memberName() == "length")
|
||||
return "Member \"length\" is read-only and cannot be used to resize arrays.";
|
||||
return { 7567_error, "Member \"length\" is read-only and cannot be used to resize arrays." };
|
||||
}
|
||||
|
||||
if (auto identifier = dynamic_cast<Identifier const*>(&_expression))
|
||||
if (auto varDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration))
|
||||
if (varDecl->isExternalCallableParameter() && dynamic_cast<ReferenceType const*>(identifier->annotation().type))
|
||||
return "External function arguments of reference type are read-only.";
|
||||
return { 7128_error, "External function arguments of reference type are read-only." };
|
||||
|
||||
return "Expression has to be an lvalue.";
|
||||
}());
|
||||
return { 4247_error, "Expression has to be an lvalue." };
|
||||
}();
|
||||
|
||||
m_errorReporter.typeError(errorId, _expression.location(), description);
|
||||
}
|
||||
|
@ -338,8 +338,14 @@ TypePointer FunctionDefinition::type() const
|
||||
TypePointer FunctionDefinition::typeViaContractName() const
|
||||
{
|
||||
if (annotation().contract->isLibrary())
|
||||
return FunctionType(*this).asCallableFunction(true);
|
||||
return TypeProvider::function(*this, FunctionType::Kind::Declaration);
|
||||
{
|
||||
if (isPublic())
|
||||
return FunctionType(*this).asExternallyCallableFunction(true);
|
||||
else
|
||||
return TypeProvider::function(*this, FunctionType::Kind::Internal);
|
||||
}
|
||||
else
|
||||
return TypeProvider::function(*this, FunctionType::Kind::Declaration);
|
||||
}
|
||||
|
||||
string FunctionDefinition::externalSignature() const
|
||||
@ -369,7 +375,7 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
|
||||
|
||||
solAssert(!dynamic_cast<ContractDefinition const&>(*scope()).isLibrary(), "");
|
||||
|
||||
FunctionType const* functionType = TypeProvider::function(*this)->asCallableFunction(false);
|
||||
FunctionType const* functionType = TypeProvider::function(*this)->asExternallyCallableFunction(false);
|
||||
|
||||
for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts)
|
||||
{
|
||||
@ -380,7 +386,7 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
|
||||
if (
|
||||
function->name() == name() &&
|
||||
!function->isConstructor() &&
|
||||
FunctionType(*function).asCallableFunction(false)->hasEqualParameterTypes(*functionType)
|
||||
FunctionType(*function).asExternallyCallableFunction(false)->hasEqualParameterTypes(*functionType)
|
||||
)
|
||||
return *function;
|
||||
}
|
||||
@ -616,18 +622,14 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
||||
|
||||
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
|
||||
return set<Location>{ Location::Unspecified };
|
||||
else if (isExternalCallableParameter())
|
||||
{
|
||||
set<Location> locations{ Location::CallData };
|
||||
if (isLibraryFunctionParameter())
|
||||
locations.insert(Location::Storage);
|
||||
return locations;
|
||||
}
|
||||
else if (isCallableOrCatchParameter())
|
||||
{
|
||||
set<Location> locations{ Location::Memory };
|
||||
if (isInternalCallableParameter() || isLibraryFunctionParameter() || isTryCatchParameter())
|
||||
locations.insert(Location::Storage);
|
||||
if (!isTryCatchParameter())
|
||||
locations.insert(Location::CallData);
|
||||
|
||||
return locations;
|
||||
}
|
||||
else if (isLocalVariable())
|
||||
@ -642,8 +644,7 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
||||
case Type::Category::Mapping:
|
||||
return set<Location>{ Location::Storage };
|
||||
default:
|
||||
// TODO: add Location::Calldata once implemented for local variables.
|
||||
return set<Location>{ Location::Memory, Location::Storage };
|
||||
return set<Location>{ Location::Memory, Location::Storage, Location::CallData };
|
||||
}
|
||||
};
|
||||
return dataLocations(typeName()->annotation().type, dataLocations);
|
||||
|
@ -349,14 +349,17 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
|
||||
MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope)
|
||||
{
|
||||
// Normalise data location of type.
|
||||
TypePointer type = TypeProvider::withLocationIfReference(DataLocation::Storage, &_type);
|
||||
DataLocation typeLocation = DataLocation::Storage;
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
||||
typeLocation = refType->location();
|
||||
|
||||
set<Declaration const*> seenFunctions;
|
||||
MemberList::MemberMap members;
|
||||
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
|
||||
for (UsingForDirective const* ufd: contract->usingForDirectives())
|
||||
{
|
||||
if (ufd->typeName() && *type != *TypeProvider::withLocationIfReference(
|
||||
DataLocation::Storage,
|
||||
if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference(
|
||||
typeLocation,
|
||||
ufd->typeName()->annotation().type
|
||||
))
|
||||
continue;
|
||||
@ -370,7 +373,7 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
||||
seenFunctions.insert(function);
|
||||
if (function->parameters().empty())
|
||||
continue;
|
||||
FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asCallableFunction(true, true);
|
||||
FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asExternallyCallableFunction(true, true);
|
||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
||||
members.emplace_back(function->name(), fun, function);
|
||||
}
|
||||
@ -2058,7 +2061,7 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con
|
||||
for (auto const& it: m_contract.interfaceFunctions())
|
||||
members.emplace_back(
|
||||
it.second->declaration().name(),
|
||||
it.second->asCallableFunction(m_contract.isLibrary()),
|
||||
it.second->asExternallyCallableFunction(m_contract.isLibrary()),
|
||||
&it.second->declaration()
|
||||
);
|
||||
}
|
||||
@ -3026,6 +3029,17 @@ unsigned FunctionType::storageBytes() const
|
||||
solAssert(false, "Storage size of non-storable function type requested.");
|
||||
}
|
||||
|
||||
bool FunctionType::nameable() const
|
||||
{
|
||||
return
|
||||
(m_kind == Kind::Internal || m_kind == Kind::External) &&
|
||||
!m_bound &&
|
||||
!m_arbitraryParameters &&
|
||||
!m_gasSet &&
|
||||
!m_valueSet &&
|
||||
!m_saltSet;
|
||||
}
|
||||
|
||||
vector<tuple<string, TypePointer>> FunctionType::makeStackItems() const
|
||||
{
|
||||
vector<tuple<string, TypePointer>> slots;
|
||||
@ -3427,7 +3441,7 @@ TypePointer FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionType::asCallableFunction(bool _inLibrary, bool _bound) const
|
||||
FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, bool _bound) const
|
||||
{
|
||||
if (_bound)
|
||||
solAssert(!m_parameterTypes.empty(), "");
|
||||
|
@ -263,6 +263,10 @@ public:
|
||||
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
||||
/// i.e. it behaves differently in lvalue context and in value context.
|
||||
virtual bool isValueType() const { return false; }
|
||||
/// @returns true if this type can be used for variables. It returns false for
|
||||
/// types like magic types, literals and function types with a kind that is not
|
||||
/// internal or external.
|
||||
virtual bool nameable() const { return false; }
|
||||
/// @returns a list of named and typed stack items that determine the layout of this type on the stack.
|
||||
/// A stack item either has an empty name and type ``nullptr`` referring to a single stack slot, or
|
||||
/// has a non-empty name and a valid type referring to the stack layout of that type.
|
||||
@ -402,6 +406,7 @@ public:
|
||||
unsigned storageBytes() const override { return 160 / 8; }
|
||||
bool leftAligned() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
|
||||
@ -446,6 +451,7 @@ public:
|
||||
unsigned storageBytes() const override { return m_bits / 8; }
|
||||
bool leftAligned() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
@ -492,6 +498,7 @@ public:
|
||||
unsigned storageBytes() const override { return m_totalBits / 8; }
|
||||
bool leftAligned() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
@ -639,6 +646,7 @@ public:
|
||||
unsigned storageBytes() const override { return m_bytes; }
|
||||
bool leftAligned() const override { return true; }
|
||||
bool isValueType() const override { return true; }
|
||||
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;
|
||||
@ -666,6 +674,7 @@ public:
|
||||
unsigned storageBytes() const override { return 1; }
|
||||
bool leftAligned() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
std::string toString(bool) const override { return "bool"; }
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
@ -773,6 +782,7 @@ public:
|
||||
bool isDynamicallyEncoded() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
||||
bool nameable() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||
@ -875,6 +885,7 @@ public:
|
||||
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
|
||||
bool canLiveOutsideStorage() const override { return !isSuper(); }
|
||||
bool isValueType() const override { return !isSuper(); }
|
||||
bool nameable() const override { return !isSuper(); }
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
|
||||
@ -935,6 +946,7 @@ public:
|
||||
u256 memoryDataSize() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
@ -997,6 +1009,7 @@ public:
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypePointer encodingType() const override;
|
||||
@ -1202,6 +1215,7 @@ public:
|
||||
bool leftAligned() const override;
|
||||
unsigned storageBytes() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
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;
|
||||
@ -1290,11 +1304,11 @@ public:
|
||||
|
||||
/// @returns a copy of this function type where the location of reference types is changed
|
||||
/// from CallData to Memory. This is the type that would be used when the function is
|
||||
/// called, as opposed to the parameter types that are available inside the function body.
|
||||
/// called externally, as opposed to the parameter types that are available inside the function body.
|
||||
/// Also supports variants to be used for library or bound calls.
|
||||
/// @param _inLibrary if true, uses DelegateCall as location.
|
||||
/// @param _bound if true, the function type is set to be bound.
|
||||
FunctionTypePointer asCallableFunction(bool _inLibrary, bool _bound = false) const;
|
||||
FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const;
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override;
|
||||
@ -1339,6 +1353,7 @@ public:
|
||||
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
|
||||
/// Cannot be stored in memory, but just in case.
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
Type const* keyType() const { return m_keyType; }
|
||||
Type const* valueType() const { return m_valueType; }
|
||||
|
@ -1022,6 +1022,10 @@ void CompilerUtils::convertType(
|
||||
case Type::Category::ArraySlice:
|
||||
{
|
||||
auto& typeOnStack = dynamic_cast<ArraySliceType const&>(_typeOnStack);
|
||||
solUnimplementedAssert(
|
||||
_targetType.dataStoredIn(DataLocation::CallData),
|
||||
"Conversion from calldata slices to memory not yet implemented."
|
||||
);
|
||||
solAssert(_targetType == typeOnStack.arrayType(), "");
|
||||
solUnimplementedAssert(
|
||||
typeOnStack.arrayType().location() == DataLocation::CallData &&
|
||||
@ -1218,6 +1222,15 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
m_context << u256(0);
|
||||
return;
|
||||
}
|
||||
if (referenceType->location() == DataLocation::CallData)
|
||||
{
|
||||
solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2, "");
|
||||
m_context << Instruction::CALLDATASIZE;
|
||||
if (referenceType->sizeOnStack() == 2)
|
||||
m_context << 0;
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(referenceType->location() == DataLocation::Memory, "");
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||
if (arrayType->isDynamicallySized())
|
||||
|
@ -1667,8 +1667,10 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co
|
||||
for (size_t i = 0; i < members.size(); ++i)
|
||||
{
|
||||
solAssert(members[i]->memoryHeadSize() == 32, "");
|
||||
solAssert(members[i]->dataStoredIn(DataLocation::Memory), "");
|
||||
memberParams[i]["zeroValue"] = zeroValueFunction(*members[i], false);
|
||||
memberParams[i]["zeroValue"] = zeroValueFunction(
|
||||
*TypeProvider::withLocationIfReference(DataLocation::Memory, members[i]),
|
||||
false
|
||||
);
|
||||
}
|
||||
templ("member", memberParams);
|
||||
return templ.render();
|
||||
@ -2238,6 +2240,27 @@ string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctio
|
||||
("functionName", functionName)
|
||||
.render();
|
||||
|
||||
if (_type.dataStoredIn(DataLocation::CallData))
|
||||
{
|
||||
solAssert(
|
||||
_type.category() == Type::Category::Struct ||
|
||||
_type.category() == Type::Category::Array,
|
||||
"");
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> offset<?hasLength>, length</hasLength> {
|
||||
offset := calldatasize()
|
||||
<?hasLength> length := 0 </hasLength>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
templ("hasLength",
|
||||
_type.category() == Type::Category::Array &&
|
||||
dynamic_cast<ArrayType const&>(_type).isDynamicallySized()
|
||||
);
|
||||
|
||||
return templ.render();
|
||||
}
|
||||
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> ret {
|
||||
ret := <zeroValue>
|
||||
@ -2622,4 +2645,3 @@ string YulUtilFunctions::copyConstructorArgumentsToMemoryFunction(
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <libsolutil/Whiskers.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
@ -121,52 +123,55 @@ string IRGenerationContext::newYulVariable()
|
||||
return "_" + to_string(++m_varCounter);
|
||||
}
|
||||
|
||||
string IRGenerationContext::generateInternalDispatchFunction(YulArity const& _arity)
|
||||
void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _internalDispatch)
|
||||
{
|
||||
string funName = IRNames::internalDispatch(_arity);
|
||||
return m_functions.createFunction(funName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(fun <comma> <in>) <arrow> <out> {
|
||||
switch fun
|
||||
<#cases>
|
||||
case <funID>
|
||||
{
|
||||
<out> <assignment_op> <name>(<in>)
|
||||
}
|
||||
</cases>
|
||||
default { invalid() }
|
||||
}
|
||||
)");
|
||||
templ("functionName", funName);
|
||||
templ("comma", _arity.in > 0 ? "," : "");
|
||||
templ("in", suffixedVariableNameList("in_", 0, _arity.in));
|
||||
templ("arrow", _arity.out > 0 ? "->" : "");
|
||||
templ("assignment_op", _arity.out > 0 ? ":=" : "");
|
||||
templ("out", suffixedVariableNameList("out_", 0, _arity.out));
|
||||
|
||||
vector<map<string, string>> cases;
|
||||
for (FunctionDefinition const* function: collectFunctionsOfArity(_arity))
|
||||
{
|
||||
solAssert(function, "");
|
||||
solAssert(
|
||||
YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity,
|
||||
"A single dispatch function can only handle functions of one arity"
|
||||
);
|
||||
solAssert(!function->isConstructor(), "");
|
||||
// 0 is reserved for uninitialized function pointers
|
||||
solAssert(function->id() != 0, "Unexpected function ID: 0");
|
||||
|
||||
cases.emplace_back(map<string, string>{
|
||||
{"funID", to_string(function->id())},
|
||||
{"name", IRNames::function(*function)}
|
||||
});
|
||||
solAssert(internalDispatchClean(), "");
|
||||
|
||||
for (set<FunctionDefinition const*> const& functions: _internalDispatch | boost::adaptors::map_values)
|
||||
for (auto function: functions)
|
||||
enqueueFunctionForCodeGeneration(*function);
|
||||
}
|
||||
|
||||
templ("cases", move(cases));
|
||||
return templ.render();
|
||||
});
|
||||
m_internalDispatchMap = move(_internalDispatch);
|
||||
}
|
||||
|
||||
InternalDispatchMap IRGenerationContext::consumeInternalDispatchMap()
|
||||
{
|
||||
m_directInternalFunctionCalls.clear();
|
||||
|
||||
InternalDispatchMap internalDispatch = move(m_internalDispatchMap);
|
||||
m_internalDispatchMap.clear();
|
||||
return internalDispatch;
|
||||
}
|
||||
|
||||
void IRGenerationContext::internalFunctionCalledDirectly(Expression const& _expression)
|
||||
{
|
||||
solAssert(m_directInternalFunctionCalls.count(&_expression) == 0, "");
|
||||
|
||||
m_directInternalFunctionCalls.insert(&_expression);
|
||||
}
|
||||
|
||||
void IRGenerationContext::internalFunctionAccessed(Expression const& _expression, FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(
|
||||
IRHelpers::referencedFunctionDeclaration(_expression) &&
|
||||
_function.resolveVirtual(mostDerivedContract()) ==
|
||||
IRHelpers::referencedFunctionDeclaration(_expression)->resolveVirtual(mostDerivedContract()),
|
||||
"Function definition does not match the expression"
|
||||
);
|
||||
|
||||
if (m_directInternalFunctionCalls.count(&_expression) == 0)
|
||||
{
|
||||
FunctionType const* functionType = TypeProvider::function(_function, FunctionType::Kind::Internal);
|
||||
solAssert(functionType, "");
|
||||
|
||||
m_internalDispatchMap[YulArity::fromType(*functionType)].insert(&_function);
|
||||
enqueueFunctionForCodeGeneration(_function);
|
||||
}
|
||||
}
|
||||
|
||||
void IRGenerationContext::internalFunctionCalledThroughDispatch(YulArity const& _arity)
|
||||
{
|
||||
m_internalDispatchMap.try_emplace(_arity);
|
||||
}
|
||||
|
||||
YulUtilFunctions IRGenerationContext::utils()
|
||||
@ -183,21 +188,3 @@ std::string IRGenerationContext::revertReasonIfDebug(std::string const& _message
|
||||
{
|
||||
return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _message);
|
||||
}
|
||||
|
||||
set<FunctionDefinition const*> IRGenerationContext::collectFunctionsOfArity(YulArity const& _arity)
|
||||
{
|
||||
// UNIMPLEMENTED: Internal library calls via pointers are not implemented yet.
|
||||
// We're not returning any internal library functions here even though it's possible
|
||||
// to call them via pointers. Right now such calls end will up triggering the `default` case in
|
||||
// the switch in the generated dispatch function.
|
||||
set<FunctionDefinition const*> functions;
|
||||
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||
if (
|
||||
!function->isConstructor() &&
|
||||
YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == _arity
|
||||
)
|
||||
functions.insert(function);
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ namespace solidity::frontend
|
||||
class YulUtilFunctions;
|
||||
class ABIFunctions;
|
||||
|
||||
using InternalDispatchMap = std::map<YulArity, std::set<FunctionDefinition const*>>;
|
||||
|
||||
/**
|
||||
* Class that contains contextual information during IR generation.
|
||||
*/
|
||||
@ -102,7 +104,26 @@ public:
|
||||
|
||||
std::string newYulVariable();
|
||||
|
||||
std::string generateInternalDispatchFunction(YulArity const& _arity);
|
||||
void initializeInternalDispatch(InternalDispatchMap _internalDispatchMap);
|
||||
InternalDispatchMap consumeInternalDispatchMap();
|
||||
bool internalDispatchClean() const { return m_internalDispatchMap.empty() && m_directInternalFunctionCalls.empty(); }
|
||||
|
||||
/// Notifies the context that a function call that needs to go through internal dispatch was
|
||||
/// encountered while visiting the AST. This ensures that the corresponding dispatch function
|
||||
/// gets added to the dispatch map even if there are no entries in it (which may happen if
|
||||
/// the code contains a call to an uninitialized function variable).
|
||||
void internalFunctionCalledThroughDispatch(YulArity const& _arity);
|
||||
|
||||
/// Notifies the context that a direct function call (i.e. not through internal dispatch) was
|
||||
/// encountered while visiting the AST. This lets the context know that the function should
|
||||
/// not be added to the dispatch (unless there are also indirect calls to it elsewhere else).
|
||||
void internalFunctionCalledDirectly(Expression const& _expression);
|
||||
|
||||
/// Notifies the context that a name representing an internal function has been found while
|
||||
/// visiting the AST. If the name has not been reported as a direct call using
|
||||
/// @a internalFunctionCalledDirectly(), it's assumed to represent function variable access
|
||||
/// and the function gets added to internal dispatch.
|
||||
void internalFunctionAccessed(Expression const& _expression, FunctionDefinition const& _function);
|
||||
|
||||
/// @returns a new copy of the utility function generator (but using the same function set).
|
||||
YulUtilFunctions utils();
|
||||
@ -120,8 +141,6 @@ public:
|
||||
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
|
||||
|
||||
private:
|
||||
std::set<FunctionDefinition const*> collectFunctionsOfArity(YulArity const& _arity);
|
||||
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
RevertStrings m_revertStrings;
|
||||
OptimiserSettings m_optimiserSettings;
|
||||
@ -147,6 +166,13 @@ private:
|
||||
/// all platforms - which is a property guaranteed by MultiUseYulFunctionCollector.
|
||||
std::set<FunctionDefinition const*> m_functionGenerationQueue;
|
||||
|
||||
/// Collection of functions that need to be callable via internal dispatch.
|
||||
/// Note that having a key with an empty set of functions is a valid situation. It means that
|
||||
/// the code contains a call via a pointer even though a specific function is never assigned to it.
|
||||
/// It will fail at runtime but the code must still compile.
|
||||
InternalDispatchMap m_internalDispatchMap;
|
||||
std::set<Expression const*> m_directInternalFunctionCalls;
|
||||
|
||||
std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,8 @@
|
||||
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
@ -137,14 +139,22 @@ string IRGenerator::generate(
|
||||
t("deploy", deployCode(_contract));
|
||||
generateImplicitConstructors(_contract);
|
||||
generateQueuedFunctions();
|
||||
InternalDispatchMap internalDispatchMap = generateInternalDispatchFunctions();
|
||||
t("functions", m_context.functionCollector().requestedFunctions());
|
||||
t("subObjects", subObjectSources(m_context.subObjectsCreated()));
|
||||
|
||||
resetContext(_contract);
|
||||
|
||||
// NOTE: Function pointers can be passed from creation code via storage variables. We need to
|
||||
// get all the functions they could point to into the dispatch functions even if they're never
|
||||
// referenced by name in the runtime code.
|
||||
m_context.initializeInternalDispatch(move(internalDispatchMap));
|
||||
|
||||
// Do not register immutables to avoid assignment.
|
||||
t("RuntimeObject", IRNames::runtimeObject(_contract));
|
||||
t("dispatch", dispatchRoutine(_contract));
|
||||
generateQueuedFunctions();
|
||||
generateInternalDispatchFunctions();
|
||||
t("runtimeFunctions", m_context.functionCollector().requestedFunctions());
|
||||
t("runtimeSubObjects", subObjectSources(m_context.subObjectsCreated()));
|
||||
return t.render();
|
||||
@ -164,6 +174,68 @@ void IRGenerator::generateQueuedFunctions()
|
||||
generateFunction(*m_context.dequeueFunctionForCodeGeneration());
|
||||
}
|
||||
|
||||
InternalDispatchMap IRGenerator::generateInternalDispatchFunctions()
|
||||
{
|
||||
solAssert(
|
||||
m_context.functionGenerationQueueEmpty(),
|
||||
"At this point all the enqueued functions should have been generated. "
|
||||
"Otherwise the dispatch may be incomplete."
|
||||
);
|
||||
|
||||
InternalDispatchMap internalDispatchMap = m_context.consumeInternalDispatchMap();
|
||||
for (YulArity const& arity: internalDispatchMap | boost::adaptors::map_keys)
|
||||
{
|
||||
string funName = IRNames::internalDispatch(arity);
|
||||
m_context.functionCollector().createFunction(funName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(fun<?+in>, <in></+in>) <?+out>-> <out></+out> {
|
||||
switch fun
|
||||
<#cases>
|
||||
case <funID>
|
||||
{
|
||||
<?+out> <out> :=</+out> <name>(<in>)
|
||||
}
|
||||
</cases>
|
||||
default { invalid() }
|
||||
}
|
||||
)");
|
||||
templ("functionName", funName);
|
||||
templ("in", suffixedVariableNameList("in_", 0, arity.in));
|
||||
templ("out", suffixedVariableNameList("out_", 0, arity.out));
|
||||
|
||||
vector<map<string, string>> cases;
|
||||
for (FunctionDefinition const* function: internalDispatchMap.at(arity))
|
||||
{
|
||||
solAssert(function, "");
|
||||
solAssert(
|
||||
YulArity::fromType(*TypeProvider::function(*function, FunctionType::Kind::Internal)) == arity,
|
||||
"A single dispatch function can only handle functions of one arity"
|
||||
);
|
||||
solAssert(!function->isConstructor(), "");
|
||||
// 0 is reserved for uninitialized function pointers
|
||||
solAssert(function->id() != 0, "Unexpected function ID: 0");
|
||||
solAssert(m_context.functionCollector().contains(IRNames::function(*function)), "");
|
||||
|
||||
cases.emplace_back(map<string, string>{
|
||||
{"funID", to_string(function->id())},
|
||||
{"name", IRNames::function(*function)}
|
||||
});
|
||||
}
|
||||
|
||||
templ("cases", move(cases));
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
solAssert(m_context.internalDispatchClean(), "");
|
||||
solAssert(
|
||||
m_context.functionGenerationQueueEmpty(),
|
||||
"Internal dispatch generation must not add new functions to generation queue because they won't be proeessed."
|
||||
);
|
||||
|
||||
return internalDispatchMap;
|
||||
}
|
||||
|
||||
string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
||||
{
|
||||
string functionName = IRNames::function(_function);
|
||||
@ -556,6 +628,10 @@ void IRGenerator::resetContext(ContractDefinition const& _contract)
|
||||
m_context.functionCollector().requestedFunctions().empty(),
|
||||
"Reset context while it still had functions."
|
||||
);
|
||||
solAssert(
|
||||
m_context.internalDispatchClean(),
|
||||
"Reset internal dispatch map without consuming it."
|
||||
);
|
||||
m_context = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings);
|
||||
|
||||
m_context.setMostDerivedContract(_contract);
|
||||
|
@ -65,6 +65,11 @@ private:
|
||||
/// Generates code for all the functions from the function generation queue.
|
||||
/// The resulting code is stored in the function collector in IRGenerationContext.
|
||||
void generateQueuedFunctions();
|
||||
/// Generates all the internal dispatch functions necessary to handle any function that could
|
||||
/// possibly be called via a pointer.
|
||||
/// @return The content of the dispatch for reuse in runtime code. Reuse is necessary because
|
||||
/// pointers to functions can be passed from the creation code in storage variables.
|
||||
InternalDispatchMap generateInternalDispatchFunctions();
|
||||
/// Generates code for and returns the name of the function.
|
||||
std::string generateFunction(FunctionDefinition const& _function);
|
||||
/// Generates a getter for the given declaration and returns its name
|
||||
|
@ -583,6 +583,20 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
FunctionTypePointer functionType = dynamic_cast<FunctionType const*>(&type(_functionCall.expression()));
|
||||
if (
|
||||
functionType &&
|
||||
functionType->kind() == FunctionType::Kind::Internal &&
|
||||
!functionType->bound() &&
|
||||
IRHelpers::referencedFunctionDeclaration(_functionCall.expression())
|
||||
)
|
||||
m_context.internalFunctionCalledDirectly(_functionCall.expression());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
solUnimplementedAssert(
|
||||
@ -661,8 +675,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
|
||||
solAssert(functionDef->isImplemented(), "");
|
||||
}
|
||||
else
|
||||
solAssert(!functionType->hasDeclaration(), "");
|
||||
|
||||
solAssert(!functionType->takesArbitraryParameters(), "");
|
||||
|
||||
@ -688,9 +700,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
else
|
||||
{
|
||||
YulArity arity = YulArity::fromType(*functionType);
|
||||
m_context.internalFunctionCalledThroughDispatch(arity);
|
||||
|
||||
define(_functionCall) <<
|
||||
// NOTE: generateInternalDispatchFunction() takes care of adding the function to function generation queue
|
||||
m_context.generateInternalDispatchFunction(arity) <<
|
||||
IRNames::internalDispatch(arity) <<
|
||||
"(" <<
|
||||
IRVariable(_functionCall.expression()).part("functionIdentifier").name() <<
|
||||
joinHumanReadablePrefixed(args) <<
|
||||
@ -869,6 +882,45 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
m_code << templ.render();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::ABIDecode:
|
||||
{
|
||||
Whiskers templ(R"(
|
||||
<?+retVars>let <retVars> := </+retVars> <abiDecode>(<offset>, add(<offset>, <length>))
|
||||
)");
|
||||
|
||||
TypePointer firstArgType = arguments.front()->annotation().type;
|
||||
TypePointers targetTypes;
|
||||
|
||||
if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type))
|
||||
targetTypes = targetTupleType->components();
|
||||
else
|
||||
targetTypes = TypePointers{_functionCall.annotation().type};
|
||||
|
||||
if (
|
||||
auto referenceType = dynamic_cast<ReferenceType const*>(firstArgType);
|
||||
referenceType && referenceType->dataStoredIn(DataLocation::CallData)
|
||||
)
|
||||
{
|
||||
solAssert(referenceType->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()), "");
|
||||
IRVariable var = convert(*arguments[0], *TypeProvider::bytesCalldata());
|
||||
templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, false));
|
||||
templ("offset", var.part("offset").name());
|
||||
templ("length", var.part("length").name());
|
||||
}
|
||||
else
|
||||
{
|
||||
IRVariable var = convert(*arguments[0], *TypeProvider::bytesMemory());
|
||||
templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, true));
|
||||
templ("offset", "add(" + var.part("mpos").name() + ", 32)");
|
||||
templ("length",
|
||||
m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()) + "(" + var.part("mpos").name() + ")"
|
||||
);
|
||||
}
|
||||
templ("retVars", IRVariable(_functionCall).commaSeparatedList());
|
||||
|
||||
m_code << templ.render();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Revert:
|
||||
{
|
||||
solAssert(arguments.size() == parameterTypes.size(), "");
|
||||
@ -1354,7 +1406,6 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
else if (member == "data")
|
||||
{
|
||||
IRVariable var(_memberAccess);
|
||||
declare(var);
|
||||
define(var.part("offset")) << "0\n";
|
||||
define(var.part("length")) << "calldatasize()\n";
|
||||
}
|
||||
@ -1492,7 +1543,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
break;
|
||||
case FunctionType::Kind::Internal:
|
||||
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
||||
{
|
||||
define(_memberAccess) << to_string(function->id()) << "\n";
|
||||
m_context.internalFunctionAccessed(_memberAccess, *function);
|
||||
}
|
||||
else
|
||||
solAssert(false, "Function not found in member access");
|
||||
break;
|
||||
@ -1756,7 +1810,14 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
||||
return;
|
||||
}
|
||||
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
||||
define(_identifier) << to_string(functionDef->resolveVirtual(m_context.mostDerivedContract()).id()) << "\n";
|
||||
{
|
||||
FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||
define(_identifier) << to_string(resolvedFunctionDef.id()) << "\n";
|
||||
|
||||
solAssert(resolvedFunctionDef.functionType(true), "");
|
||||
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
|
||||
m_context.internalFunctionAccessed(_identifier, resolvedFunctionDef);
|
||||
}
|
||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
handleVariableReference(*varDecl, _identifier);
|
||||
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
void endVisit(Return const& _return) override;
|
||||
void endVisit(UnaryOperation const& _unaryOperation) override;
|
||||
bool visit(BinaryOperation const& _binOp) override;
|
||||
bool visit(FunctionCall const& _funCall) override;
|
||||
void endVisit(FunctionCall const& _funCall) override;
|
||||
void endVisit(FunctionCallOptions const& _funCallOptions) override;
|
||||
void endVisit(MemberAccess const& _memberAccess) override;
|
||||
|
@ -74,8 +74,8 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
|
||||
if (
|
||||
function->name() == baseFunction->name() &&
|
||||
function->kind() == baseFunction->kind() &&
|
||||
FunctionType(*function).asCallableFunction(false)->
|
||||
hasEqualParameterTypes(*FunctionType(*baseFunction).asCallableFunction(false))
|
||||
FunctionType(*function).asExternallyCallableFunction(false)->
|
||||
hasEqualParameterTypes(*FunctionType(*baseFunction).asExternallyCallableFunction(false))
|
||||
)
|
||||
{
|
||||
overridden = true;
|
||||
|
@ -73,7 +73,7 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect,
|
||||
{},
|
||||
_object.dataNames()
|
||||
).analyze(*_object.code);
|
||||
yulAssert(success && errorList.empty(), "Invalid assembly/yul code.");
|
||||
yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code.");
|
||||
return analysisInfo;
|
||||
}
|
||||
|
||||
@ -259,6 +259,8 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
||||
returnTypes = &f->returns;
|
||||
if (f->literalArguments)
|
||||
needsLiteralArguments = &f->literalArguments.value();
|
||||
|
||||
warnOnInstructions(_funCall);
|
||||
}
|
||||
else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
|
||||
[&](Scope::Variable const&)
|
||||
@ -275,10 +277,11 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
||||
}
|
||||
}))
|
||||
{
|
||||
if (!warnOnInstructions(_funCall.functionName.name.str(), _funCall.functionName.location))
|
||||
if (!warnOnInstructions(_funCall))
|
||||
declarationError(_funCall.functionName.location, "Function not found.");
|
||||
yulAssert(!watcher.ok(), "Expected a reported error.");
|
||||
}
|
||||
|
||||
if (parameterTypes && _funCall.arguments.size() != parameterTypes->size())
|
||||
typeError(
|
||||
_funCall.functionName.location,
|
||||
@ -553,6 +556,14 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
|
||||
errorForVM("only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID())
|
||||
errorForVM("only available for Istanbul-compatible");
|
||||
else if (_instr == evmasm::Instruction::PC)
|
||||
m_errorReporter.warning(
|
||||
2450_error,
|
||||
_location,
|
||||
"The \"" +
|
||||
boost::to_lower_copy(instructionInfo(_instr).name) +
|
||||
"\" instruction is deprecated and will be removed in the next breaking release."
|
||||
);
|
||||
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
||||
errorForVM("only available for Istanbul-compatible");
|
||||
else if (
|
||||
|
@ -112,6 +112,11 @@ private:
|
||||
bool warnOnInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location);
|
||||
bool warnOnInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
|
||||
|
||||
bool warnOnInstructions(FunctionCall const& _functionCall)
|
||||
{
|
||||
return warnOnInstructions(_functionCall.functionName.name.str(), _functionCall.functionName.location);
|
||||
}
|
||||
|
||||
void typeError(langutil::SourceLocation const& _location, std::string const& _description);
|
||||
void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
||||
|
||||
|
@ -396,6 +396,7 @@ bytes BinaryTransform::operator()(BranchIf const& _branchIf)
|
||||
|
||||
bytes BinaryTransform::operator()(Return const&)
|
||||
{
|
||||
// Note that this does not work if the function returns a value.
|
||||
return toBytes(Opcode::Return);
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,8 @@ wasm::Expression WasmCodeTransform::operator()(Continue const&)
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(Leave const&)
|
||||
{
|
||||
return wasm::Return{};
|
||||
yulAssert(!m_functionBodyLabel.empty(), "");
|
||||
return wasm::Branch{wasm::Label{m_functionBodyLabel}};
|
||||
}
|
||||
|
||||
wasm::Expression WasmCodeTransform::operator()(Block const& _block)
|
||||
@ -330,10 +331,16 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
|
||||
fun.returns = !_fun.returnVariables.empty();
|
||||
|
||||
yulAssert(m_localVariables.empty(), "");
|
||||
fun.body = visit(_fun.body.statements);
|
||||
yulAssert(m_functionBodyLabel.empty(), "");
|
||||
m_functionBodyLabel = newLabel();
|
||||
fun.body.emplace_back(wasm::Expression(wasm::Block{
|
||||
m_functionBodyLabel,
|
||||
visit(_fun.body.statements)
|
||||
}));
|
||||
fun.locals += m_localVariables;
|
||||
|
||||
m_localVariables.clear();
|
||||
m_functionBodyLabel = {};
|
||||
|
||||
if (!_fun.returnVariables.empty())
|
||||
{
|
||||
|
@ -95,6 +95,7 @@ private:
|
||||
std::vector<wasm::VariableDeclaration> m_localVariables;
|
||||
std::vector<wasm::GlobalVariableDeclaration> m_globalVariables;
|
||||
std::map<YulString, wasm::FunctionImport> m_functionsToImport;
|
||||
std::string m_functionBodyLabel;
|
||||
std::stack<std::pair<std::string, std::string>> m_breakContinueLabelNames;
|
||||
};
|
||||
|
||||
|
@ -90,7 +90,6 @@ void MSizeFinder::operator()(FunctionCall const& _functionCall)
|
||||
m_msizeFound = true;
|
||||
}
|
||||
|
||||
|
||||
map<YulString, SideEffects> SideEffectsPropagator::sideEffects(
|
||||
Dialect const& _dialect,
|
||||
CallGraph const& _directCallGraph
|
||||
|
@ -36,7 +36,7 @@ using namespace solidity::evmasm;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::yul;
|
||||
|
||||
SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
|
||||
SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
|
||||
Expression const& _expr,
|
||||
Dialect const& _dialect,
|
||||
map<YulString, AssignedValue> const& _ssaValues
|
||||
@ -46,7 +46,16 @@ SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
|
||||
if (!instruction)
|
||||
return nullptr;
|
||||
|
||||
static SimplificationRules rules;
|
||||
static std::map<std::optional<EVMVersion>, std::unique_ptr<SimplificationRules>> evmRules;
|
||||
|
||||
std::optional<EVMVersion> version;
|
||||
if (yul::EVMDialect const* evmDialect = dynamic_cast<yul::EVMDialect const*>(&_dialect))
|
||||
version = evmDialect->evmVersion();
|
||||
|
||||
if (!evmRules[version])
|
||||
evmRules[version] = std::make_unique<SimplificationRules>(version);
|
||||
|
||||
SimplificationRules& rules = *evmRules[version];
|
||||
assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized.");
|
||||
|
||||
for (auto const& rule: rules.m_rules[uint8_t(instruction->first)])
|
||||
@ -76,18 +85,18 @@ std::optional<std::pair<evmasm::Instruction, vector<Expression> const*>>
|
||||
return {};
|
||||
}
|
||||
|
||||
void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules)
|
||||
void SimplificationRules::addRules(std::vector<Rule> const& _rules)
|
||||
{
|
||||
for (auto const& r: _rules)
|
||||
addRule(r);
|
||||
}
|
||||
|
||||
void SimplificationRules::addRule(SimplificationRule<Pattern> const& _rule)
|
||||
void SimplificationRules::addRule(Rule const& _rule)
|
||||
{
|
||||
m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule);
|
||||
}
|
||||
|
||||
SimplificationRules::SimplificationRules()
|
||||
SimplificationRules::SimplificationRules(std::optional<langutil::EVMVersion> _evmVersion)
|
||||
{
|
||||
// Multiple occurrences of one of these inside one rule must match the same equivalence class.
|
||||
// Constants.
|
||||
@ -107,7 +116,7 @@ SimplificationRules::SimplificationRules()
|
||||
Y.setMatchGroup(6, m_matchGroups);
|
||||
Z.setMatchGroup(7, m_matchGroups);
|
||||
|
||||
addRules(simplificationRuleList(A, B, C, W, X, Y, Z));
|
||||
addRules(simplificationRuleList(_evmVersion, A, B, C, W, X, Y, Z));
|
||||
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <functional>
|
||||
@ -45,12 +47,14 @@ class Pattern;
|
||||
class SimplificationRules: public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
SimplificationRules();
|
||||
using Rule = evmasm::SimplificationRule<Pattern>;
|
||||
|
||||
explicit SimplificationRules(std::optional<langutil::EVMVersion> _evmVersion = std::nullopt);
|
||||
|
||||
/// @returns a pointer to the first matching pattern and sets the match
|
||||
/// groups accordingly.
|
||||
/// @param _ssaValues values of variables that are assigned exactly once.
|
||||
static evmasm::SimplificationRule<Pattern> const* findFirstMatch(
|
||||
static Rule const* findFirstMatch(
|
||||
Expression const& _expr,
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, AssignedValue> const& _ssaValues
|
||||
@ -64,8 +68,8 @@ public:
|
||||
instructionAndArguments(Dialect const& _dialect, Expression const& _expr);
|
||||
|
||||
private:
|
||||
void addRules(std::vector<evmasm::SimplificationRule<Pattern>> const& _rules);
|
||||
void addRule(evmasm::SimplificationRule<Pattern> const& _rule);
|
||||
void addRules(std::vector<Rule> const& _rules);
|
||||
void addRule(Rule const& _rule);
|
||||
|
||||
void resetMatchGroups() { m_matchGroups.clear(); }
|
||||
|
||||
|
@ -8,10 +8,13 @@ import json
|
||||
SOLC_BIN = sys.argv[1]
|
||||
REPORT_FILE = open("report.txt", mode="w", encoding='utf8', newline='\n')
|
||||
|
||||
def removeSMT(source):
|
||||
return source.replace('pragma experimental SMTChecker;', '')
|
||||
|
||||
for optimize in [False, True]:
|
||||
for f in sorted(glob.glob("*.sol")):
|
||||
sources = {}
|
||||
sources[f] = {'content': open(f, mode='r', encoding='utf8').read()}
|
||||
sources[f] = {'content': removeSMT(open(f, mode='r', encoding='utf8').read())}
|
||||
input_json = {
|
||||
'language': 'Solidity',
|
||||
'sources': sources,
|
||||
|
@ -64,6 +64,11 @@ var fs = require('fs')
|
||||
|
||||
var compiler = require('./solc-js/wrapper.js')(require('./solc-js/soljson.js'))
|
||||
|
||||
function removeSMT(source)
|
||||
{
|
||||
return source.replace('pragma experimental SMTChecker;', '');
|
||||
}
|
||||
|
||||
for (var optimize of [false, true])
|
||||
{
|
||||
for (var filename of process.argv.slice(2))
|
||||
@ -71,7 +76,7 @@ for (var optimize of [false, true])
|
||||
if (filename !== undefined)
|
||||
{
|
||||
var inputs = {}
|
||||
inputs[filename] = { content: fs.readFileSync(filename).toString() }
|
||||
inputs[filename] = { content: removeSMT(fs.readFileSync(filename).toString()) }
|
||||
var input = {
|
||||
language: 'Solidity',
|
||||
sources: inputs,
|
||||
@ -107,8 +112,10 @@ for (var optimize of [false, true])
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo "Running the compiler..."
|
||||
chmod +x solc
|
||||
./solc *.sol > report.txt
|
||||
echo "Finished running the compiler."
|
||||
else
|
||||
$REPO_ROOT/scripts/bytecodecompare/prepare_report.py $REPO_ROOT/$BUILD_DIR/solc/solc
|
||||
fi
|
||||
@ -138,6 +145,9 @@ EOF
|
||||
else
|
||||
echo "Adding report failed, it might already exist in the repository."
|
||||
fi
|
||||
else
|
||||
echo "Not storing bytecode because the keys are not available."
|
||||
fi
|
||||
)
|
||||
rm -rf "$TMPDIR"
|
||||
echo "Storebytecode finished."
|
@ -55,7 +55,6 @@ def get_used_ids(file_names):
|
||||
|
||||
def get_id(available_ids, used_ids):
|
||||
while len(available_ids) > 0:
|
||||
random.seed(len(available_ids))
|
||||
k = random.randrange(len(available_ids))
|
||||
id = list(available_ids.keys())[k]
|
||||
del available_ids[id]
|
||||
@ -117,6 +116,7 @@ def find_source_files(top_dir):
|
||||
|
||||
|
||||
def main():
|
||||
random.seed()
|
||||
cwd = os.getcwd()
|
||||
answer = input(
|
||||
f"This script checks and corrects *_error literals in .h and .cpp files\n"
|
||||
|
@ -45,7 +45,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010abe01052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3e01007e2000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acd01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b4101007e02402000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
@ -55,17 +55,22 @@ Text representation:
|
||||
|
||||
(func $main
|
||||
(local $_1 i64)
|
||||
(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)))
|
||||
(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)))
|
||||
)
|
||||
)
|
||||
|
||||
(func $endian_swap_16
|
||||
(param $x i64)
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||
(block $label__1
|
||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -74,8 +79,11 @@ Text representation:
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||
(block $label__2
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -84,8 +92,11 @@ Text representation:
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
(block $label__3
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -95,10 +106,12 @@ Text representation:
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(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)))
|
||||
(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)))
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
@ -154,7 +154,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020a82090df002011f7e4200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b2c01037e200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21042004240020030b6f010b7e200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b2011210820092400200a2401200b240220080b2301047e200020018420022003848450ada7ad210720052400200624012007240220040b4601047e2000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b20092400200a2401200b240220080b2a01027e02402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b20020b930101087e4200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b20092400200a2401200b240220080b8c0101087e4200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b210720052400200624012007240220040b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e2000100a421086210220022000421088100a84210120010b1b01027e2000100b422086210220022000422088100b84210120010b3e01007e2000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b2401007e42002000200120022003100d42202004200520062007100d4200a74220a710000b
|
||||
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa9090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b4101007e02402000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b0b2701007e024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
@ -198,79 +198,81 @@ Text representation:
|
||||
(local $x_9 i64)
|
||||
(local $x_10 i64)
|
||||
(local $x_11 i64)
|
||||
(local.set $_1 (i64.const 0))
|
||||
(block
|
||||
(local.set $x (call $calldataload (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)))
|
||||
(local.set $x_1 (global.get $global_))
|
||||
(local.set $x_2 (global.get $global__1))
|
||||
(local.set $x_3 (global.get $global__2))
|
||||
|
||||
)
|
||||
(local.set $x_4 (local.get $x))
|
||||
(local.set $x_5 (local.get $x_1))
|
||||
(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))))))))))))
|
||||
(block $label_
|
||||
(loop $label__4
|
||||
(br_if $label_ (i64.eqz (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (local.get $_3))))))
|
||||
(block $label__3
|
||||
(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)))
|
||||
(local.set $_5 (global.get $global_))
|
||||
(local.set $_6 (global.get $global__1))
|
||||
(local.set $_7 (global.get $global__2))
|
||||
(local.set $_1 (i64.const 0))
|
||||
(block
|
||||
(local.set $x (call $calldataload (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)))
|
||||
(local.set $x_1 (global.get $global_))
|
||||
(local.set $x_2 (global.get $global__1))
|
||||
(local.set $x_3 (global.get $global__2))
|
||||
|
||||
)
|
||||
(block
|
||||
(local.set $_8 (call $iszero (local.get $_4) (local.get $_5) (local.get $_6) (local.get $_7)))
|
||||
(local.set $_9 (global.get $global_))
|
||||
(local.set $_10 (global.get $global__1))
|
||||
(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
|
||||
(br $label_)
|
||||
))
|
||||
(block
|
||||
(local.set $_12 (call $eq (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 2)))
|
||||
(local.set $_13 (global.get $global_))
|
||||
(local.set $_14 (global.get $global__1))
|
||||
(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
|
||||
(br $label_)
|
||||
))
|
||||
(block
|
||||
(local.set $_16 (call $eq (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 4)))
|
||||
(local.set $_17 (global.get $global_))
|
||||
(local.set $_18 (global.get $global__1))
|
||||
(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
|
||||
(br $label__3)
|
||||
))
|
||||
|
||||
)
|
||||
(block
|
||||
(local.set $x_8 (call $add (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) (local.get $_2)))
|
||||
(local.set $x_9 (global.get $global_))
|
||||
(local.set $x_10 (global.get $global__1))
|
||||
(local.set $x_11 (global.get $global__2))
|
||||
|
||||
)
|
||||
(local.set $x_4 (local.get $x_8))
|
||||
(local.set $x_5 (local.get $x_9))
|
||||
(local.set $x_6 (local.get $x_10))
|
||||
(local.set $x_7 (local.get $x_11))
|
||||
(br $label__4)
|
||||
)
|
||||
(local.set $x_4 (local.get $x))
|
||||
(local.set $x_5 (local.get $x_1))
|
||||
(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))))))))))))
|
||||
(block $label__3
|
||||
(loop $label__5
|
||||
(br_if $label__3 (i64.eqz (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (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)))
|
||||
(local.set $_5 (global.get $global_))
|
||||
(local.set $_6 (global.get $global__1))
|
||||
(local.set $_7 (global.get $global__2))
|
||||
|
||||
)
|
||||
(block
|
||||
(local.set $_8 (call $iszero (local.get $_4) (local.get $_5) (local.get $_6) (local.get $_7)))
|
||||
(local.set $_9 (global.get $global_))
|
||||
(local.set $_10 (global.get $global__1))
|
||||
(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
|
||||
(br $label__3)
|
||||
))
|
||||
(block
|
||||
(local.set $_12 (call $eq (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 2)))
|
||||
(local.set $_13 (global.get $global_))
|
||||
(local.set $_14 (global.get $global__1))
|
||||
(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
|
||||
(br $label__3)
|
||||
))
|
||||
(block
|
||||
(local.set $_16 (call $eq (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 4)))
|
||||
(local.set $_17 (global.get $global_))
|
||||
(local.set $_18 (global.get $global__1))
|
||||
(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
|
||||
(br $label__4)
|
||||
))
|
||||
|
||||
)
|
||||
(block
|
||||
(local.set $x_8 (call $add (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) (local.get $_2)))
|
||||
(local.set $x_9 (global.get $global_))
|
||||
(local.set $x_10 (global.get $global__1))
|
||||
(local.set $x_11 (global.get $global__2))
|
||||
|
||||
)
|
||||
(local.set $x_4 (local.get $x_8))
|
||||
(local.set $x_5 (local.get $x_9))
|
||||
(local.set $x_6 (local.get $x_10))
|
||||
(local.set $x_7 (local.get $x_11))
|
||||
(br $label__5)
|
||||
)
|
||||
|
||||
)
|
||||
(call $sstore (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7))
|
||||
)
|
||||
(call $sstore (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7))
|
||||
)
|
||||
|
||||
(func $add_carry
|
||||
@ -281,9 +283,12 @@ Text representation:
|
||||
(local $r i64)
|
||||
(local $r_c i64)
|
||||
(local $t i64)
|
||||
(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)))))))))
|
||||
(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)))))))))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $r_c))
|
||||
(local.get $r)
|
||||
)
|
||||
@ -309,26 +314,29 @@ Text representation:
|
||||
(local $carry_1 i64)
|
||||
(local $r1_1 i64)
|
||||
(local $carry_2 i64)
|
||||
(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 $carry (global.get $global_))
|
||||
(block $label__7
|
||||
(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 $carry (global.get $global_))
|
||||
|
||||
)
|
||||
(local.set $r3 (local.get $r3_1))
|
||||
(block
|
||||
(local.set $r2_1 (call $add_carry (local.get $x2) (local.get $y2) (local.get $carry)))
|
||||
(local.set $carry_1 (global.get $global_))
|
||||
|
||||
)
|
||||
(local.set $r2 (local.get $r2_1))
|
||||
(block
|
||||
(local.set $r1_1 (call $add_carry (local.get $x1) (local.get $y1) (local.get $carry_1)))
|
||||
(local.set $carry_2 (global.get $global_))
|
||||
|
||||
)
|
||||
(local.set $r1 (local.get $r1_1))
|
||||
|
||||
)
|
||||
(local.set $r3 (local.get $r3_1))
|
||||
(block
|
||||
(local.set $r2_1 (call $add_carry (local.get $x2) (local.get $y2) (local.get $carry)))
|
||||
(local.set $carry_1 (global.get $global_))
|
||||
|
||||
)
|
||||
(local.set $r2 (local.get $r2_1))
|
||||
(block
|
||||
(local.set $r1_1 (call $add_carry (local.get $x1) (local.get $y1) (local.get $carry_1)))
|
||||
(local.set $carry_2 (global.get $global_))
|
||||
|
||||
)
|
||||
(local.set $r1 (local.get $r1_1))
|
||||
(global.set $global_ (local.get $r2))
|
||||
(global.set $global__1 (local.get $r3))
|
||||
(global.set $global__2 (local.get $r4))
|
||||
@ -345,7 +353,10 @@ Text representation:
|
||||
(local $r2 i64)
|
||||
(local $r3 i64)
|
||||
(local $r4 i64)
|
||||
(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))))))))
|
||||
(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))))))))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $r2))
|
||||
(global.set $global__1 (local.get $r3))
|
||||
(global.set $global__2 (local.get $r4))
|
||||
@ -366,15 +377,18 @@ Text representation:
|
||||
(local $r2 i64)
|
||||
(local $r3 i64)
|
||||
(local $r4 i64)
|
||||
(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
|
||||
(local.set $r4 (i64.const 1))
|
||||
(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
|
||||
(local.set $r4 (i64.const 1))
|
||||
))
|
||||
))
|
||||
))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $r2))
|
||||
(global.set $global__1 (local.get $r3))
|
||||
(global.set $global__2 (local.get $r4))
|
||||
@ -387,13 +401,16 @@ Text representation:
|
||||
(result i64)
|
||||
(local $r i64)
|
||||
(local $condition i64)
|
||||
(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))
|
||||
)(else
|
||||
(local.set $r (i64.extend_i32_u (i64.ne (local.get $a) (local.get $b))))
|
||||
))
|
||||
(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))
|
||||
)(else
|
||||
(local.set $r (i64.extend_i32_u (i64.ne (local.get $a) (local.get $b))))
|
||||
))
|
||||
|
||||
)
|
||||
|
||||
)
|
||||
(local.get $r)
|
||||
@ -414,48 +431,51 @@ Text representation:
|
||||
(local $z3 i64)
|
||||
(local $z4 i64)
|
||||
(local $z i64)
|
||||
(local $condition_5 i64)
|
||||
(local $condition_6 i64)
|
||||
(local $condition_7 i64)
|
||||
(local.set $z (i64.const 0))
|
||||
(block
|
||||
(local.set $condition_5 (call $cmp (local.get $x1) (local.get $y1)))
|
||||
(if (i64.eq (local.get $condition_5) (i64.const 0)) (then
|
||||
(block
|
||||
(local.set $condition_6 (call $cmp (local.get $x2) (local.get $y2)))
|
||||
(if (i64.eq (local.get $condition_6) (i64.const 0)) (then
|
||||
(block
|
||||
(local.set $condition_7 (call $cmp (local.get $x3) (local.get $y3)))
|
||||
(if (i64.eq (local.get $condition_7) (i64.const 0)) (then
|
||||
(local.set $z (i64.extend_i32_u (i64.lt_u (local.get $x4) (local.get $y4))))
|
||||
)(else
|
||||
(if (i64.eq (local.get $condition_7) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
(local $condition_12 i64)
|
||||
(local $condition_13 i64)
|
||||
(local $condition_14 i64)
|
||||
(block $label__11
|
||||
(local.set $z (i64.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
|
||||
(block
|
||||
(local.set $condition_13 (call $cmp (local.get $x2) (local.get $y2)))
|
||||
(if (i64.eq (local.get $condition_13) (i64.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))))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
(if (i64.eq (local.get $condition_14) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
)(else
|
||||
(if (i64.eq (local.get $condition_6) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
)
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
(if (i64.eq (local.get $condition_13) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
)(else
|
||||
(if (i64.eq (local.get $condition_5) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
)
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
(if (i64.eq (local.get $condition_12) (i64.const 1)) (then
|
||||
(local.set $z (i64.const 0))
|
||||
)(else
|
||||
(local.set $z (i64.const 1))
|
||||
))
|
||||
))
|
||||
))
|
||||
|
||||
)
|
||||
(local.set $z4 (i64.extend_i32_u (i32.wrap_i64 (local.get $z))))
|
||||
|
||||
)
|
||||
(local.set $z4 (i64.extend_i32_u (i32.wrap_i64 (local.get $z))))
|
||||
(global.set $global_ (local.get $z2))
|
||||
(global.set $global__1 (local.get $z3))
|
||||
(global.set $global__2 (local.get $z4))
|
||||
@ -476,19 +496,22 @@ Text representation:
|
||||
(local $z2_1 i64)
|
||||
(local $z3_1 i64)
|
||||
(local $z4_1 i64)
|
||||
(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
|
||||
(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
|
||||
(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))))))))
|
||||
(local.set $z1 (local.get $z1_1))
|
||||
(local.set $z2 (local.get $z2_1))
|
||||
(local.set $z3 (local.get $z3_1))
|
||||
(local.set $z4 (local.get $z4_1))
|
||||
(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
|
||||
(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
|
||||
(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))))))))
|
||||
(local.set $z1 (local.get $z1_1))
|
||||
(local.set $z2 (local.get $z2_1))
|
||||
(local.set $z3 (local.get $z3_1))
|
||||
(local.set $z4 (local.get $z4_1))
|
||||
|
||||
)
|
||||
(global.set $global_ (local.get $z2))
|
||||
(global.set $global__1 (local.get $z3))
|
||||
(global.set $global__2 (local.get $z4))
|
||||
@ -499,7 +522,10 @@ Text representation:
|
||||
(param $x i64)
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||
(block $label__16
|
||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -508,8 +534,11 @@ Text representation:
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||
(block $label__17
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -518,8 +547,11 @@ Text representation:
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
(block $label__18
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -529,10 +561,12 @@ Text representation:
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(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)))
|
||||
(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)))
|
||||
)
|
||||
)
|
||||
|
||||
(func $sstore
|
||||
@ -544,9 +578,11 @@ Text representation:
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(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)))
|
||||
(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)))
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
@ -16,25 +16,27 @@
|
||||
(local $z2 i64)
|
||||
(local $z3 i64)
|
||||
(local $_3 i64)
|
||||
(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
|
||||
(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
|
||||
(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))
|
||||
(call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||
(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
|
||||
(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
|
||||
(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))
|
||||
(call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||
)
|
||||
)
|
||||
|
||||
(func $u256_to_i32
|
||||
@ -44,11 +46,14 @@
|
||||
(param $x4 i64)
|
||||
(result i64)
|
||||
(local $v i64)
|
||||
(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
|
||||
(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
|
||||
(unreachable)))
|
||||
(local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4))))
|
||||
(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
|
||||
(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
|
||||
(unreachable)))
|
||||
(local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4))))
|
||||
|
||||
)
|
||||
(local.get $v)
|
||||
)
|
||||
|
||||
@ -60,10 +65,13 @@
|
||||
(result i64)
|
||||
(local $r i64)
|
||||
(local $p i64)
|
||||
(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
|
||||
(unreachable)))
|
||||
(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
|
||||
(unreachable)))
|
||||
|
||||
)
|
||||
(local.get $r)
|
||||
)
|
||||
|
||||
@ -80,14 +88,19 @@
|
||||
(param $z2 i64)
|
||||
(param $z3 i64)
|
||||
(param $z4 i64)
|
||||
(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))))
|
||||
(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))))
|
||||
)
|
||||
)
|
||||
|
||||
(func $endian_swap_16
|
||||
(param $x i64)
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||
(block $label__4
|
||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -96,8 +109,11 @@
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||
(block $label__5
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -106,8 +122,11 @@
|
||||
(result i64)
|
||||
(local $y i64)
|
||||
(local $hi i64)
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
(block $label__6
|
||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||
|
||||
)
|
||||
(local.get $y)
|
||||
)
|
||||
|
||||
@ -120,7 +139,9 @@
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(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))))
|
||||
(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))))
|
||||
)
|
||||
)
|
||||
|
||||
(func $revert
|
||||
@ -132,7 +153,9 @@
|
||||
(param $y2 i64)
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(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))))
|
||||
(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))))
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
@ -4,5 +4,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0xc0, 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 -> 0x20, 0x4, 0x3, 0x4, 0x5, 0x6
|
||||
|
@ -8,5 +8,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6
|
||||
|
@ -11,5 +11,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6
|
||||
|
@ -4,5 +4,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0x20, 0x21 -> 33
|
||||
|
@ -5,5 +5,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x21, 0x40, 0x7, "abcdefg"
|
||||
|
@ -5,5 +5,8 @@ contract C {
|
||||
f = abi.decode(msg.data[4 + 32 : 4 + 32 + 32], (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256,uint256): 42, 23 -> 42, 23, 42, 23
|
||||
|
@ -18,6 +18,9 @@ contract C {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test(bytes): 0x20, 0x80, 0x40, 0x60, 0, 0 -> false, false
|
||||
// test(bytes): 0x20, 0xC0, 0x40, 0x80, 1, 0x42, 1, 0x42 -> false, false
|
||||
|
@ -7,5 +7,8 @@ contract C {
|
||||
return abi.decode(data, (uint256, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"
|
||||
|
@ -3,5 +3,8 @@ contract C {
|
||||
return abi.decode(data, (uint256, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"
|
||||
|
@ -6,5 +6,6 @@ contract C {
|
||||
return abi.decode(data, (uint256, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"
|
||||
|
@ -0,0 +1,12 @@
|
||||
contract C {
|
||||
function f(bytes calldata b, uint i) internal pure returns (byte) {
|
||||
return b[i];
|
||||
}
|
||||
function f(uint, bytes calldata b, uint) external pure returns (byte) {
|
||||
return f(b, 2);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256,bytes,uint256): 7, 0x60, 7, 4, "abcd" -> "c"
|
@ -0,0 +1,17 @@
|
||||
contract C {
|
||||
function(bytes calldata) returns (byte) x;
|
||||
constructor() public { x = f; }
|
||||
function f(bytes calldata b) internal pure returns (byte) {
|
||||
return b[2];
|
||||
}
|
||||
function h(bytes calldata b) external returns (byte) {
|
||||
return x(b);
|
||||
}
|
||||
function g() external returns (byte) {
|
||||
bytes memory a = new bytes(34);
|
||||
a[2] = byte(uint8(7));
|
||||
return this.h(a);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// g() -> 0x0700000000000000000000000000000000000000000000000000000000000000
|
@ -0,0 +1,22 @@
|
||||
library L {
|
||||
function f(uint, bytes calldata _x, uint) internal returns (byte) {
|
||||
return _x[2];
|
||||
}
|
||||
}
|
||||
contract C {
|
||||
function f(bytes calldata a)
|
||||
external
|
||||
returns (byte)
|
||||
{
|
||||
return L.f(3, a, 9);
|
||||
}
|
||||
function g() public returns (byte) {
|
||||
bytes memory x = new bytes(4);
|
||||
x[2] = 0x08;
|
||||
return this.f(x);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 0x0800000000000000000000000000000000000000000000000000000000000000
|
@ -0,0 +1,23 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
function g(uint[][2] calldata s) internal pure returns (uint, uint[] calldata) {
|
||||
return (s[0][1], s[1]);
|
||||
}
|
||||
function f(uint, uint[][2] calldata s, uint) external pure returns (uint, uint) {
|
||||
(uint x, uint[] calldata y) = g(s);
|
||||
return (x, y[0]);
|
||||
}
|
||||
function g() public returns (uint, uint) {
|
||||
uint[][2] memory x;
|
||||
x[0] = new uint[](2);
|
||||
x[1] = new uint[](2);
|
||||
x[0][1] = 7;
|
||||
x[1][0] = 8;
|
||||
return this.f(4, x, 5);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 7, 8
|
@ -0,0 +1,19 @@
|
||||
contract C {
|
||||
function g(uint[3][2] calldata s) internal pure returns (uint, uint[3] calldata) {
|
||||
return (s[0][1], s[1]);
|
||||
}
|
||||
function f(uint, uint[3][2] calldata s, uint) external pure returns (uint, uint) {
|
||||
(uint x, uint[3] calldata y) = g(s);
|
||||
return (x, y[0]);
|
||||
}
|
||||
function g() public returns (uint, uint) {
|
||||
uint[3][2] memory x;
|
||||
x[0][1] = 7;
|
||||
x[1][0] = 8;
|
||||
return this.f(4, x, 5);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 7, 8
|
@ -0,0 +1,21 @@
|
||||
contract C {
|
||||
function f(bytes memory _a, bytes calldata _b, bytes memory _c)
|
||||
public
|
||||
returns (uint, byte, byte, byte)
|
||||
{
|
||||
return (_a.length + _b.length + _c.length, _a[1], _b[1], _c[1]);
|
||||
}
|
||||
function g() public returns (uint, byte, byte, byte) {
|
||||
bytes memory x = new bytes(3);
|
||||
bytes memory y = new bytes(4);
|
||||
bytes memory z = new bytes(7);
|
||||
x[1] = 0x08;
|
||||
y[1] = 0x09;
|
||||
z[1] = 0x0a;
|
||||
return this.f(x, y, z);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 0x0e, 0x0800000000000000000000000000000000000000000000000000000000000000, 0x0900000000000000000000000000000000000000000000000000000000000000, 0x0a00000000000000000000000000000000000000000000000000000000000000
|
@ -0,0 +1,17 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
struct S {
|
||||
uint x;
|
||||
uint y;
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f(S calldata s) internal pure returns (uint, uint) {
|
||||
return (s.x, s.y);
|
||||
}
|
||||
function f(uint, S calldata s, uint) external pure returns (uint, uint) {
|
||||
return f(s);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f(uint256,(uint256,uint256),uint256): 7, 1, 2, 4 -> 1, 2
|
@ -0,0 +1,31 @@
|
||||
contract Test {
|
||||
bytes6 name;
|
||||
|
||||
constructor() public {
|
||||
function (bytes6 _name) internal setter = setName;
|
||||
setter("abcdef");
|
||||
|
||||
applyShift(leftByteShift, 3);
|
||||
}
|
||||
|
||||
function getName() public returns (bytes6 ret) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function setName(bytes6 _name) private {
|
||||
name = _name;
|
||||
}
|
||||
|
||||
function leftByteShift(bytes6 _value, uint _shift) public returns (bytes6) {
|
||||
return _value << _shift * 8;
|
||||
}
|
||||
|
||||
function applyShift(function (bytes6 _value, uint _shift) internal returns (bytes6) _shiftOperator, uint _bytes) internal {
|
||||
name = _shiftOperator(name, _bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// getName() -> "def\x00\x00\x00"
|
@ -0,0 +1,24 @@
|
||||
contract C {
|
||||
function foo() internal returns (uint) {
|
||||
return 42;
|
||||
}
|
||||
|
||||
function get_ptr(function() internal returns (uint) ptr) internal returns(function() internal returns (uint)) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function associated() public returns (uint) {
|
||||
// This expression directly references function definition
|
||||
return (foo)();
|
||||
}
|
||||
|
||||
function unassociated() public returns (uint) {
|
||||
// This expression is not associated with a specific function definition
|
||||
return (get_ptr(foo))();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// associated() -> 42
|
||||
// unassociated() -> 42
|
@ -22,5 +22,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256[]): 0x20, 0x3, 0x1, 0x7, 0x3 -> 11
|
||||
|
@ -0,0 +1,21 @@
|
||||
contract A {
|
||||
function f() internal virtual returns (uint256) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract B is A {
|
||||
function f() internal override returns (uint256) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
function g() public returns (uint256) {
|
||||
function() internal returns (uint256) ptr = A.f;
|
||||
return ptr();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 1
|
@ -0,0 +1,17 @@
|
||||
library L {
|
||||
function f() internal returns (uint) {
|
||||
return 66;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function g() public returns (uint) {
|
||||
function() internal returns(uint) ptr;
|
||||
ptr = L.f;
|
||||
return ptr();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 66
|
@ -0,0 +1,26 @@
|
||||
contract Base {
|
||||
function f() internal returns (uint256 i) {
|
||||
function() internal returns (uint256) ptr = g;
|
||||
return ptr();
|
||||
}
|
||||
|
||||
function g() internal virtual returns (uint256 i) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract Derived is Base {
|
||||
function g() internal override returns (uint256 i) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
function h() public returns (uint256 i) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// h() -> 2
|
@ -0,0 +1,8 @@
|
||||
// Used to cause ICE
|
||||
contract C {
|
||||
function f() public {
|
||||
abi.decode("", (byte[999999999]));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (75-90): Type too large for memory.
|
@ -6,4 +6,4 @@ contract C {
|
||||
// ----
|
||||
// DeclarationError: (28-45): The "constant" keyword can only be used for state variables.
|
||||
// TypeError: (69-72): Invalid array length, expected integer literal or constant expression.
|
||||
// TypeError: (64-75): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (64-75): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -0,0 +1,8 @@
|
||||
// Used to cause ICE
|
||||
contract C {
|
||||
function f(uint[] calldata x) external pure {
|
||||
x[1:2].a;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (92-100): Member "a" not found or not visible after argument-dependent lookup in uint256[] calldata slice.
|
@ -0,0 +1,10 @@
|
||||
contract C {
|
||||
function f(uint[] calldata _c) public pure {
|
||||
uint[] calldata c;
|
||||
if (_c[2] > 10)
|
||||
c = _c;
|
||||
c[2];
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (141-142): This variable is of calldata pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
|
@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
function f(uint[] calldata _c) public pure {
|
||||
uint[] calldata c;
|
||||
if (_c[2] > 10)
|
||||
c = _c;
|
||||
else
|
||||
c = _c;
|
||||
c[2];
|
||||
}
|
||||
}
|
||||
// ----
|
@ -0,0 +1,16 @@
|
||||
contract C {
|
||||
function g() internal pure returns (bytes calldata) {
|
||||
return msg.data;
|
||||
}
|
||||
function h(uint[] calldata _c) internal pure {
|
||||
uint[] calldata c;
|
||||
c = _c;
|
||||
c[2];
|
||||
}
|
||||
function i(uint[] calldata _c) internal pure {
|
||||
uint[] calldata c;
|
||||
(c) = _c;
|
||||
c[2];
|
||||
}
|
||||
}
|
||||
// ----
|
@ -5,5 +5,4 @@ library L {
|
||||
}
|
||||
|
||||
// ----
|
||||
// TypeError: (66-81): Data location must be "memory" for parameter in function, but "calldata" was given.
|
||||
// TypeError: (159-173): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
// TypeError: (159-173): Data location must be "memory" or "calldata" for parameter in function, but "storage" was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function i() external pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (52-58): Data location must be "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (52-58): Data location must be "memory" or "calldata" for return parameter in function, but none was given.
|
||||
|
@ -2,4 +2,5 @@ contract test {
|
||||
function f(bytes memory) external;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-43): Data location must be "calldata" for parameter in external function, but "memory" was given.
|
||||
// TypeError: (0-56): Contract "test" should be marked as abstract.
|
||||
// TypeError: (20-54): Functions without implementation must be marked virtual.
|
||||
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes storage) external;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-44): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
// TypeError: (31-44): Data location must be "memory" or "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -2,4 +2,5 @@ contract test {
|
||||
function f(bytes calldata) internal;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-45): Data location must be "storage" or "memory" for parameter in function, but "calldata" was given.
|
||||
// TypeError: (0-58): Contract "test" should be marked as abstract.
|
||||
// TypeError: (20-56): Functions without implementation must be marked virtual.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function g(uint[]) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-34): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (28-34): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function g() internal pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (52-58): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (52-58): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
|
@ -6,7 +6,7 @@ library L {
|
||||
function j(mapping(uint => uint)) external pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (52-59): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (93-99): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (133-134): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (168-189): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (52-59): Data location must be "storage", "memory" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (93-99): Data location must be "storage", "memory" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (133-134): Data location must be "storage", "memory" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (168-189): Data location must be "storage", "memory" or "calldata" for parameter in external function, but none was given.
|
||||
|
@ -6,7 +6,7 @@ library L {
|
||||
function j() external pure returns (mapping(uint => uint)) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (77-84): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (129-135): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (180-181): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (226-247): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (77-84): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (129-135): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (180-181): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (226-247): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
|
@ -10,11 +10,11 @@ library L {
|
||||
function jp(mapping(uint => uint)) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (77-84): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (129-135): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (180-181): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (226-247): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (268-275): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (310-316): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (351-352): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (387-408): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (77-84): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (129-135): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (180-181): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (226-247): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (268-275): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (310-316): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (351-352): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (387-408): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
|
@ -10,11 +10,11 @@ library L {
|
||||
function jp(mapping(uint => uint)) private pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (76-83): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (127-133): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (177-178): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (222-243): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (264-271): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (305-311): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (345-346): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (380-401): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (76-83): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (127-133): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (177-178): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (222-243): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (264-271): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (305-311): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (345-346): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (380-401): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
|
@ -9,11 +9,11 @@ library L {
|
||||
function ip(S) private pure {}
|
||||
function jp(mapping(uint => uint)) private pure {}}
|
||||
// ----
|
||||
// TypeError: (76-83): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (127-133): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (177-178): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (222-243): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (264-271): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (305-311): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (345-346): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (380-401): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (76-83): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (127-133): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (177-178): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (222-243): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
// TypeError: (264-271): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (305-311): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (345-346): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
// TypeError: (380-401): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
|
@ -2,4 +2,3 @@ library test {
|
||||
function f(bytes memory) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (30-42): Data location must be "storage" or "calldata" for parameter in external function, but "memory" was given.
|
||||
|
@ -2,4 +2,3 @@ library test {
|
||||
function f(bytes calldata) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (30-44): Data location must be "storage" or "memory" for parameter in function, but "calldata" was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function f(uint[]) private pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-34): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (28-34): Data location must be "storage", "memory" or "calldata" for parameter in function, but none was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function f() private pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-57): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (51-57): Data location must be "storage", "memory" or "calldata" for return parameter in function, but none was given.
|
||||
|
@ -2,4 +2,5 @@ contract test {
|
||||
function f(bytes calldata) public;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-45): Data location must be "memory" for parameter in function, but "calldata" was given.
|
||||
// TypeError: (0-56): Contract "test" should be marked as abstract.
|
||||
// TypeError: (20-54): Functions without implementation must be marked virtual.
|
||||
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes storage) public;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-44): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
// TypeError: (31-44): Data location must be "memory" or "calldata" for parameter in function, but "storage" was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function h(uint[]) public pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-34): Data location must be "memory" for parameter in function, but none was given.
|
||||
// TypeError: (28-34): Data location must be "memory" or "calldata" for parameter in function, but none was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function h() public pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (50-56): Data location must be "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (50-56): Data location must be "memory" or "calldata" for return parameter in function, but none was given.
|
||||
|
9
test/libsolidity/syntaxTests/inlineAssembly/pc.sol
Normal file
9
test/libsolidity/syntaxTests/inlineAssembly/pc.sol
Normal file
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function f() pure public {
|
||||
assembly {
|
||||
pop(pc())
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (61-63): The "pc" instruction is deprecated and will be removed in the next breaking release.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f() public {
|
||||
[msg];
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (47-52): Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f() public {
|
||||
[type(C)];
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (47-56): Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element.
|
@ -3,4 +3,4 @@ contract c {
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-52): Invalid array length, expected integer literal or constant expression.
|
||||
// TypeError: (45-55): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (45-55): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -3,4 +3,4 @@ contract c {
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-53): Array with negative length specified.
|
||||
// TypeError: (45-56): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (45-56): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -2,4 +2,3 @@ contract C {
|
||||
function f(uint[] memory a) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-43): Data location must be "calldata" for parameter in external function, but "memory" was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function f(uint[] storage a) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-44): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
// TypeError: (28-44): Data location must be "memory" or "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -5,4 +5,4 @@ contract test {
|
||||
}
|
||||
// ----
|
||||
// TypeError: (55-58): Array with fractional length specified.
|
||||
// TypeError: (50-61): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (50-61): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -5,4 +5,4 @@ contract test {
|
||||
}
|
||||
// ----
|
||||
// TypeError: (55-65): Invalid array length, expected integer literal or constant expression.
|
||||
// TypeError: (50-68): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (50-68): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -5,4 +5,4 @@ contract test {
|
||||
}
|
||||
// ----
|
||||
// TypeError: (55-66): Invalid array length, expected integer literal or constant expression.
|
||||
// TypeError: (50-69): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (50-69): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -9,5 +9,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (104-107): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (123-131): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (104-107): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
// TypeError: (123-131): Data location must be "storage", "memory" or "calldata" for variable, but none was given.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-57): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
// TypeError: (28-57): Data location must be "memory" or "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-57): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
// TypeError: (28-57): Data location must be "memory" or "calldata" for parameter in function, but "storage" was given.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-59): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
// TypeError: (28-59): Data location must be "memory" or "calldata" for parameter in external function, but "storage" was given.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user