Merge pull request #9038 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth 2020-05-27 15:24:27 +02:00 committed by GitHub
commit 894478ff8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
116 changed files with 1424 additions and 582 deletions

View File

@ -20,6 +20,8 @@ Bugfixes:
### 0.6.9 (unreleased) ### 0.6.9 (unreleased)
Language Features: 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: Compiler Features:
@ -31,6 +33,9 @@ Compiler Features:
Bugfixes: Bugfixes:
* Optimizer: Fixed a bug in BlockDeDuplicator. * Optimizer: Fixed a bug in BlockDeDuplicator.
* Type Checker: Disallow assignments to storage variables of type ``mapping``. * 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. * NatSpec: DocString block is terminated when encountering an empty line.
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL. * Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
* Code Generator: Trigger proper unimplemented errors on certain array copy operations. * Code Generator: Trigger proper unimplemented errors on certain array copy operations.

View File

@ -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 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 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) are stored, where the lifetime is limited to the lifetime of a contract)
or ``calldata`` (special data location that contains the function arguments, or ``calldata`` (special data location that contains the function arguments).
only available for external function call parameters).
An assignment or type conversion that changes the data location will always incur an automatic copy operation, 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. 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 Every reference type has an additional
annotation, the "data location", about where it is stored. There are three data locations: 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 ``memory``, ``storage`` and ``calldata``. Calldata is a non-modifiable,
functions and is required for this type of parameter. Calldata is a non-modifiable,
non-persistent area where function arguments are stored, and behaves mostly like memory. 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:: .. 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 depending on the kind of variable, function type, etc., but all complex types must now give an explicit
data location. 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-assignment:
Data location and assignment behaviour Data location and assignment behaviour

View File

@ -29,6 +29,10 @@
#include <boost/multiprecision/detail/min_max.hpp> #include <boost/multiprecision/detail/min_max.hpp>
#include <libyul/Dialect.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/EVMVersion.h>
#include <vector> #include <vector>
#include <functional> #include <functional>
@ -657,12 +661,37 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
return rules; 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. /// @returns a list of simplification rules given certain match placeholders.
/// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions. /// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions.
/// The simplifications should never change the order of evaluation of /// The simplifications should never change the order of evaluation of
/// arbitrary operations. /// arbitrary operations.
template <class Pattern> template <class Pattern>
std::vector<SimplificationRule<Pattern>> simplificationRuleList( std::vector<SimplificationRule<Pattern>> simplificationRuleList(
std::optional<langutil::EVMVersion> _evmVersion,
Pattern A, Pattern A,
Pattern B, Pattern B,
Pattern C, Pattern C,
@ -691,6 +720,10 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
rules += simplificationRuleListPart7(A, B, C, W, X); rules += simplificationRuleListPart7(A, B, C, W, X);
rules += simplificationRuleListPart8(A, B, C, W, X); rules += simplificationRuleListPart8(A, B, C, W, X);
rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z); 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; return rules;
} }

View File

@ -92,7 +92,7 @@ Rules::Rules()
Y.setMatchGroup(6, m_matchGroups); Y.setMatchGroup(6, m_matchGroups);
Z.setMatchGroup(7, 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."); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
} }

View File

@ -41,8 +41,8 @@ bool hasEqualNameAndParameters(T const& _a, B const& _b)
{ {
return return
_a.name() == _b.name() && _a.name() == _b.name() &&
FunctionType(_a).asCallableFunction(false)->hasEqualParameterTypes( FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
*FunctionType(_b).asCallableFunction(false) *FunctionType(_b).asExternallyCallableFunction(false)
); );
} }
@ -345,7 +345,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
// under non error circumstances this should be true // under non error circumstances this should be true
if (functionType->interfaceFunctionType()) if (functionType->interfaceFunctionType())
externalDeclarations[functionType->externalSignature()].emplace_back( externalDeclarations[functionType->externalSignature()].emplace_back(
f, functionType->asCallableFunction(false) f, functionType->asExternallyCallableFunction(false)
); );
} }
for (VariableDeclaration const* v: contract->stateVariables()) for (VariableDeclaration const* v: contract->stateVariables())
@ -355,7 +355,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
// under non error circumstances this should be true // under non error circumstances this should be true
if (functionType->interfaceFunctionType()) if (functionType->interfaceFunctionType())
externalDeclarations[functionType->externalSignature()].emplace_back( externalDeclarations[functionType->externalSignature()].emplace_back(
v, functionType->asCallableFunction(false) v, functionType->asExternallyCallableFunction(false)
); );
} }
} }

View File

@ -94,7 +94,10 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
case VariableOccurrence::Kind::Return: case VariableOccurrence::Kind::Return:
if (unassignedVariables.count(&variableOccurrence.declaration())) 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 // 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 // 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). // 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()) if (variableOccurrence->occurrence())
ssl.append("The variable was declared here.", variableOccurrence->declaration().location()); ssl.append("The variable was declared here.", variableOccurrence->declaration().location());
bool isStorage = variableOccurrence->declaration().type()->dataStoredIn(DataLocation::Storage);
m_errorReporter.typeError( m_errorReporter.typeError(
3464_error, 3464_error,
variableOccurrence->occurrence() ? variableOccurrence->occurrence() ?
*variableOccurrence->occurrence() : *variableOccurrence->occurrence() :
variableOccurrence->declaration().location(), variableOccurrence->declaration().location(),
ssl, 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") + (variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") +
" without prior assignment, which would lead to undefined behaviour." " without prior assignment, which would lead to undefined behaviour."
); );

View File

@ -151,7 +151,7 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
{ {
_typeName.annotation().type = TypeProvider::emptyTuple(); _typeName.annotation().type = TypeProvider::emptyTuple();
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
9755_error, 5172_error,
_typeName.location(), _typeName.location(),
"Name has to refer to a struct, enum or contract." "Name has to refer to a struct, enum or contract."
); );
@ -176,7 +176,7 @@ bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
break; break;
default: default:
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
7653_error, 6012_error,
_typeName.location(), _typeName.location(),
"Invalid visibility, can only be \"external\" or \"internal\"." "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) if (_typeName.isPayable() && _typeName.visibility() != Visibility::External)
{ {
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
6138_error, 7415_error,
_typeName.location(), _typeName.location(),
"Only external function types can be payable." "Only external function types can be payable."
); );
@ -246,7 +246,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
} }
if (baseType->storageBytes() == 0) if (baseType->storageBytes() == 0)
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
9390_error, 6493_error,
_typeName.baseType().location(), _typeName.baseType().location(),
"Illegal base type of storage size zero for array." "Illegal base type of storage size zero for array."
); );
@ -259,16 +259,16 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
u256 lengthValue = 0; u256 lengthValue = 0;
if (!lengthType || !lengthType->mobileType()) if (!lengthType || !lengthType->mobileType())
m_errorReporter.typeError( m_errorReporter.typeError(
8922_error, 5462_error,
length->location(), length->location(),
"Invalid array length, expected integer literal or constant expression." "Invalid array length, expected integer literal or constant expression."
); );
else if (lengthType->isZero()) 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()) 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()) 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 else
lengthValue = lengthType->literalValue(nullptr); lengthValue = lengthType->literalValue(nullptr);
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue); _typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue);
@ -345,7 +345,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
errorString += " for variable"; errorString += " for variable";
} }
errorString += ", but " + locationToString(varLoc) + " was given."; 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(), ""); solAssert(!allowedDataLocations.empty(), "");
varLoc = *allowedDataLocations.begin(); varLoc = *allowedDataLocations.begin();

View File

@ -311,8 +311,8 @@ Token OverrideProxy::functionKind() const
FunctionType const* OverrideProxy::functionType() const FunctionType const* OverrideProxy::functionType() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](FunctionDefinition const* _item) { return FunctionType(*_item).asCallableFunction(false); }, [&](FunctionDefinition const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
[&](VariableDeclaration const* _item) { return FunctionType(*_item).asCallableFunction(false); }, [&](VariableDeclaration const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
[&](ModifierDefinition const*) -> FunctionType const* { solAssert(false, "Requested function type of modifier."); return nullptr; } [&](ModifierDefinition const*) -> FunctionType const* { solAssert(false, "Requested function type of modifier."); return nullptr; }
}, m_item); }, m_item);
} }
@ -559,7 +559,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
overrideError( overrideError(
_overriding, _overriding,
_super, _super,
2837_error, 6959_error,
"Overriding function changes state mutability from \"" + "Overriding function changes state mutability from \"" +
stateMutabilityToString(_super.stateMutability()) + stateMutabilityToString(_super.stateMutability()) +
"\" to \"" + "\" to \"" +

View File

@ -119,7 +119,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
else else
errorMessage += " Did you mean " + std::move(suggestions) + "?"; 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) else if (declarations.size() == 1)
_identifier.annotation().referencedDeclaration = declarations.front(); _identifier.annotation().referencedDeclaration = declarations.front();
@ -157,7 +157,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath()); Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
if (!declaration) 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; return;
} }
@ -210,7 +210,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
if (realName.empty()) if (realName.empty())
{ {
m_errorReporter.declarationError( m_errorReporter.declarationError(
9553_error, 4794_error,
_identifier.location, _identifier.location,
"In variable names _slot and _offset can only be used as a suffix." "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) if (declarations.size() > 1)
{ {
m_errorReporter.declarationError( m_errorReporter.declarationError(
8827_error, 4718_error,
_identifier.location, _identifier.location,
"Multiple matching identifiers. Resolving overloaded identifiers is not supported." "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) if (var->isLocalVariable() && m_yulInsideFunction)
{ {
m_errorReporter.declarationError( m_errorReporter.declarationError(
8477_error, 6578_error,
_identifier.location, _identifier.location,
"Cannot access local Solidity variables from inside an inline assembly function." "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('.')); string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
if (isSlot || isOffset) if (isSlot || isOffset)
m_errorReporter.declarationError( m_errorReporter.declarationError(
8820_error, 9155_error,
identifier.location, identifier.location,
"In variable declarations _slot and _offset can not be used as a suffix." "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()); ssl.append("The shadowed declaration is here:", decl->location());
if (!ssl.infos.empty()) if (!ssl.infos.empty())
m_errorReporter.declarationError( m_errorReporter.declarationError(
6005_error, 3859_error,
identifier.location, identifier.location,
ssl, ssl,
namePrefix.size() < identifier.name.str().size() ? namePrefix.size() < identifier.name.str().size() ?

View File

@ -273,6 +273,7 @@ bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
"The msize instruction cannot be used when the Yul optimizer is activated because " "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." "it can change its semantics. Either disable the Yul optimizer or do not use the instruction."
); );
return false; return false;
} }

View File

@ -193,6 +193,18 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
typeArgument->location(), typeArgument->location(),
"Decoding type " + actualType->toString(false) + " not supported." "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); components.push_back(actualType);
} }
else else
@ -1511,6 +1523,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{ {
if (!inlineArrayType) if (!inlineArrayType)
m_errorReporter.fatalTypeError(6378_error, _tuple.location(), "Unable to deduce common type for array elements."); 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()) else if (!inlineArrayType->canLiveOutsideStorage())
m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage."); 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 = bool const isStructConstructorCall =
_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall; _functionCall.annotation().kind == FunctionCallKind::StructConstructorCall;
string msg; auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
string msg = isVariadic ?
if (isVariadic)
msg +=
"Need at least " + "Need at least " +
toString(parameterTypes.size()) + toString(parameterTypes.size()) +
" arguments for " + " arguments for " +
string(isStructConstructorCall ? "struct constructor" : "function call") + string(isStructConstructorCall ? "struct constructor" : "function call") +
", but provided only " + ", but provided only " +
toString(arguments.size()) + toString(arguments.size()) +
"."; "."
else :
msg +=
"Wrong argument count for " + "Wrong argument count for " +
string(isStructConstructorCall ? "struct constructor" : "function call") + string(isStructConstructorCall ? "struct constructor" : "function call") +
": " + ": " +
@ -2023,7 +2038,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
{ {
/// For error message: Struct members that were removed during conversion to memory. /// For error message: Struct members that were removed during conversion to memory.
TypePointer const expressionType = type(_functionCall.expression()); TypePointer const expressionType = type(_functionCall.expression());
TypeType const& t = dynamic_cast<TypeType const&>(*expressionType); auto const& t = dynamic_cast<TypeType const&>(*expressionType);
auto const& structType = dynamic_cast<StructType const&>(*t.actualType()); auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory(); set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
@ -2033,6 +2048,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
for (auto const& member: membersRemovedForStructConstructor) for (auto const& member: membersRemovedForStructConstructor)
msg += " " + member; msg += " " + member;
} }
return { isVariadic ? 1123_error : 9755_error, msg };
} }
else if ( else if (
_functionType->kind() == FunctionType::Kind::BareCall || _functionType->kind() == FunctionType::Kind::BareCall ||
@ -2042,25 +2059,38 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
) )
{ {
if (arguments.empty()) if (arguments.empty())
msg += return {
isVariadic ? 7653_error : 6138_error,
msg +
" This function requires a single bytes argument." " This function requires a single bytes argument."
" Use \"\" as argument to provide empty calldata."; " Use \"\" as argument to provide empty calldata."
};
else else
msg += return {
isVariadic ? 9390_error : 8922_error,
msg +
" This function requires a single bytes argument." " This function requires a single bytes argument."
" If all your arguments are value types, you can use" " If all your arguments are value types, you can use"
" abi.encode(...) to properly generate it."; " abi.encode(...) to properly generate it."
};
} }
else if ( else if (
_functionType->kind() == FunctionType::Kind::KECCAK256 || _functionType->kind() == FunctionType::Kind::KECCAK256 ||
_functionType->kind() == FunctionType::Kind::SHA256 || _functionType->kind() == FunctionType::Kind::SHA256 ||
_functionType->kind() == FunctionType::Kind::RIPEMD160 _functionType->kind() == FunctionType::Kind::RIPEMD160
) )
msg += return {
isVariadic ? 1220_error : 4323_error,
msg +
" This function requires a single bytes argument." " This function requires a single bytes argument."
" Use abi.encodePacked(...) to obtain the pre-0.5.0" " Use abi.encodePacked(...) to obtain the pre-0.5.0"
" behaviour or abi.encode(...) to use ABI encoding."; " behaviour or abi.encode(...) to use ABI encoding."
m_errorReporter.typeError(1093_error, _functionCall.location(), msg); };
else
return { isVariadic ? 9308_error : 6160_error, msg };
}();
m_errorReporter.typeError(errorId, _functionCall.location(), description);
return; return;
} }
@ -2136,6 +2166,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
solAssert(!!paramArgMap[i], "unmapped parameter"); solAssert(!!paramArgMap[i], "unmapped parameter");
if (!type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i])) if (!type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
{ {
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
string msg = string msg =
"Invalid type for argument in function call. " "Invalid type for argument in function call. "
"Invalid implicit conversion from " + "Invalid implicit conversion from " +
@ -2149,20 +2180,29 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
_functionType->kind() == FunctionType::Kind::BareDelegateCall || _functionType->kind() == FunctionType::Kind::BareDelegateCall ||
_functionType->kind() == FunctionType::Kind::BareStaticCall _functionType->kind() == FunctionType::Kind::BareStaticCall
) )
msg += return {
8051_error,
msg +
" This function requires a single bytes argument." " This function requires a single bytes argument."
" If all your arguments are value types, you can" " If all your arguments are value types, you can"
" use abi.encode(...) to properly generate it."; " use abi.encode(...) to properly generate it."
};
else if ( else if (
_functionType->kind() == FunctionType::Kind::KECCAK256 || _functionType->kind() == FunctionType::Kind::KECCAK256 ||
_functionType->kind() == FunctionType::Kind::SHA256 || _functionType->kind() == FunctionType::Kind::SHA256 ||
_functionType->kind() == FunctionType::Kind::RIPEMD160 _functionType->kind() == FunctionType::Kind::RIPEMD160
) )
msg += return {
7556_error,
msg +
" This function requires a single bytes argument." " This function requires a single bytes argument."
" Use abi.encodePacked(...) to obtain the pre-0.5.0" " Use abi.encodePacked(...) to obtain the pre-0.5.0"
" behaviour or abi.encode(...) to use ABI encoding."; " behaviour or abi.encode(...) to use ABI encoding."
m_errorReporter.typeError(6706_error, paramArgMap[i]->location(), msg); };
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 (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. // Try to see if the member was removed because it is only available for storage types.
auto storageType = TypeProvider::withLocationIfReference( auto storageType = TypeProvider::withLocationIfReference(
@ -2551,44 +2591,50 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
" outside of storage." " outside of storage."
); );
} }
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
string errorMsg = "Member \"" + memberName + "\" not found or not visible " string errorMsg = "Member \"" + memberName + "\" not found or not visible "
"after argument-dependent lookup in " + exprType->toString() + "."; "after argument-dependent lookup in " + exprType->toString() + ".";
if (auto const& funType = dynamic_cast<FunctionType const*>(exprType)) if (auto const* funType = dynamic_cast<FunctionType const*>(exprType))
{ {
auto const& t = funType->returnParameterTypes(); TypePointers const& t = funType->returnParameterTypes();
if (memberName == "value") if (memberName == "value")
{ {
if (funType->kind() == FunctionType::Kind::Creation) if (funType->kind() == FunctionType::Kind::Creation)
errorMsg = "Constructor for " + t.front()->toString() + " must be payable for member \"value\" to be available."; return {
8827_error,
"Constructor for " + t.front()->toString() + " must be payable for member \"value\" to be available."
};
else if ( else if (
funType->kind() == FunctionType::Kind::DelegateCall || funType->kind() == FunctionType::Kind::DelegateCall ||
funType->kind() == FunctionType::Kind::BareDelegateCall funType->kind() == FunctionType::Kind::BareDelegateCall
) )
errorMsg = "Member \"value\" is not allowed in delegated calls due to \"msg.value\" persisting."; return { 8477_error, "Member \"value\" is not allowed in delegated calls due to \"msg.value\" persisting." };
else else
errorMsg = "Member \"value\" is only available for payable functions."; return { 8820_error, "Member \"value\" is only available for payable functions." };
} }
else if ( else if (
t.size() == 1 && t.size() == 1 && (
(t.front()->category() == Type::Category::Struct || t.front()->category() == Type::Category::Struct ||
t.front()->category() == Type::Category::Contract) t.front()->category() == Type::Category::Contract
) )
errorMsg += " Did you intend to call the function?"; )
return { 6005_error, errorMsg + " Did you intend to call the function?" };
} }
else if (exprType->category() == Type::Category::Contract) else if (exprType->category() == Type::Category::Contract)
{ {
for (auto const& addressMember: TypeProvider::payableAddress()->nativeMembers(nullptr)) for (MemberList::Member const& addressMember: TypeProvider::payableAddress()->nativeMembers(nullptr))
if (addressMember.name == memberName) if (addressMember.name == memberName)
{ {
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression()); auto const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
string varName = var ? var->name() : "..."; string varName = var ? var->name() : "...";
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member."; errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
break; return { 3125_error, errorMsg };
} }
} }
else if (auto addressType = dynamic_cast<AddressType const*>(exprType)) else if (auto const* addressType = dynamic_cast<AddressType const*>(exprType))
{ {
// Trigger error when using send or transfer with a non-payable fallback function. // Trigger error when using send or transfer with a non-payable fallback function.
if (memberName == "send" || memberName == "transfer") if (memberName == "send" || memberName == "transfer")
@ -2598,14 +2644,17 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
"Expected address not-payable as members were not found" "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() + "\"."; 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( m_errorReporter.fatalTypeError(
4035_error, errorId,
_memberAccess.location(), _memberAccess.location(),
errorMsg description
); );
} }
else if (possibleMembers.size() > 1) else if (possibleMembers.size() > 1)
@ -2875,7 +2924,7 @@ bool TypeChecker::visit(IndexRangeAccess const& _access)
if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized()) if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized())
m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays."); m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays.");
else if (arrayType->baseType()->isDynamicallyEncoded()) 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().type = TypeProvider::arraySlice(*arrayType);
_access.annotation().isLValue = isLValue; _access.annotation().isLValue = isLValue;
_access.annotation().isPure = isPure; _access.annotation().isPure = isPure;
@ -3181,17 +3230,17 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
if (_expression.annotation().isLValue) if (_expression.annotation().isLValue)
return; return;
return m_errorReporter.typeError(1123_error, _expression.location(), [&]() { auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
if (_expression.annotation().isConstant) 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 (auto indexAccess = dynamic_cast<IndexAccess const*>(&_expression))
{ {
if (type(indexAccess->baseExpression())->category() == Type::Category::FixedBytes) 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()))) else if (auto arrayType = dynamic_cast<ArrayType const*>(type(indexAccess->baseExpression())))
if (arrayType->dataStoredIn(DataLocation::CallData)) 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)) 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 (auto structType = dynamic_cast<StructType const*>(type(memberAccess->expression())))
{ {
if (structType->dataStoredIn(DataLocation::CallData)) 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()))) else if (dynamic_cast<ArrayType const*>(type(memberAccess->expression())))
if (memberAccess->memberName() == "length") 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 identifier = dynamic_cast<Identifier const*>(&_expression))
if (auto varDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) if (auto varDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration))
if (varDecl->isExternalCallableParameter() && dynamic_cast<ReferenceType const*>(identifier->annotation().type)) 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);
} }

View File

@ -338,7 +338,13 @@ TypePointer FunctionDefinition::type() const
TypePointer FunctionDefinition::typeViaContractName() const TypePointer FunctionDefinition::typeViaContractName() const
{ {
if (annotation().contract->isLibrary()) if (annotation().contract->isLibrary())
return FunctionType(*this).asCallableFunction(true); {
if (isPublic())
return FunctionType(*this).asExternallyCallableFunction(true);
else
return TypeProvider::function(*this, FunctionType::Kind::Internal);
}
else
return TypeProvider::function(*this, FunctionType::Kind::Declaration); return TypeProvider::function(*this, FunctionType::Kind::Declaration);
} }
@ -369,7 +375,7 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
solAssert(!dynamic_cast<ContractDefinition const&>(*scope()).isLibrary(), ""); 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) for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts)
{ {
@ -380,7 +386,7 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
if ( if (
function->name() == name() && function->name() == name() &&
!function->isConstructor() && !function->isConstructor() &&
FunctionType(*function).asCallableFunction(false)->hasEqualParameterTypes(*functionType) FunctionType(*function).asExternallyCallableFunction(false)->hasEqualParameterTypes(*functionType)
) )
return *function; return *function;
} }
@ -616,18 +622,14 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter()) if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
return set<Location>{ Location::Unspecified }; return set<Location>{ Location::Unspecified };
else if (isExternalCallableParameter())
{
set<Location> locations{ Location::CallData };
if (isLibraryFunctionParameter())
locations.insert(Location::Storage);
return locations;
}
else if (isCallableOrCatchParameter()) else if (isCallableOrCatchParameter())
{ {
set<Location> locations{ Location::Memory }; set<Location> locations{ Location::Memory };
if (isInternalCallableParameter() || isLibraryFunctionParameter() || isTryCatchParameter()) if (isInternalCallableParameter() || isLibraryFunctionParameter() || isTryCatchParameter())
locations.insert(Location::Storage); locations.insert(Location::Storage);
if (!isTryCatchParameter())
locations.insert(Location::CallData);
return locations; return locations;
} }
else if (isLocalVariable()) else if (isLocalVariable())
@ -642,8 +644,7 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
case Type::Category::Mapping: case Type::Category::Mapping:
return set<Location>{ Location::Storage }; return set<Location>{ Location::Storage };
default: default:
// TODO: add Location::Calldata once implemented for local variables. return set<Location>{ Location::Memory, Location::Storage, Location::CallData };
return set<Location>{ Location::Memory, Location::Storage };
} }
}; };
return dataLocations(typeName()->annotation().type, dataLocations); return dataLocations(typeName()->annotation().type, dataLocations);

View File

@ -349,14 +349,17 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope) MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope)
{ {
// Normalise data location of type. // 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; set<Declaration const*> seenFunctions;
MemberList::MemberMap members; MemberList::MemberMap members;
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts) for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
for (UsingForDirective const* ufd: contract->usingForDirectives()) for (UsingForDirective const* ufd: contract->usingForDirectives())
{ {
if (ufd->typeName() && *type != *TypeProvider::withLocationIfReference( if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference(
DataLocation::Storage, typeLocation,
ufd->typeName()->annotation().type ufd->typeName()->annotation().type
)) ))
continue; continue;
@ -370,7 +373,7 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
seenFunctions.insert(function); seenFunctions.insert(function);
if (function->parameters().empty()) if (function->parameters().empty())
continue; 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())) if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.emplace_back(function->name(), fun, function); 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()) for (auto const& it: m_contract.interfaceFunctions())
members.emplace_back( members.emplace_back(
it.second->declaration().name(), it.second->declaration().name(),
it.second->asCallableFunction(m_contract.isLibrary()), it.second->asExternallyCallableFunction(m_contract.isLibrary()),
&it.second->declaration() &it.second->declaration()
); );
} }
@ -3026,6 +3029,17 @@ unsigned FunctionType::storageBytes() const
solAssert(false, "Storage size of non-storable function type requested."); 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>> FunctionType::makeStackItems() const
{ {
vector<tuple<string, TypePointer>> slots; 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) if (_bound)
solAssert(!m_parameterTypes.empty(), ""); solAssert(!m_parameterTypes.empty(), "");

View File

@ -263,6 +263,10 @@ public:
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack, /// 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. /// i.e. it behaves differently in lvalue context and in value context.
virtual bool isValueType() const { return false; } 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. /// @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 /// 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. /// 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; } unsigned storageBytes() const override { return 160 / 8; }
bool leftAligned() const override { return false; } bool leftAligned() const override { return false; }
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool nameable() const override { return true; }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override; MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
@ -446,6 +451,7 @@ public:
unsigned storageBytes() const override { return m_bits / 8; } unsigned storageBytes() const override { return m_bits / 8; }
bool leftAligned() const override { return false; } bool leftAligned() const override { return false; }
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
@ -492,6 +498,7 @@ public:
unsigned storageBytes() const override { return m_totalBits / 8; } unsigned storageBytes() const override { return m_totalBits / 8; }
bool leftAligned() const override { return false; } bool leftAligned() const override { return false; }
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
@ -639,6 +646,7 @@ public:
unsigned storageBytes() const override { return m_bytes; } unsigned storageBytes() const override { return m_bytes; }
bool leftAligned() const override { return true; } bool leftAligned() const override { return true; }
bool isValueType() 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); } std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override; MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
@ -666,6 +674,7 @@ public:
unsigned storageBytes() const override { return 1; } unsigned storageBytes() const override { return 1; }
bool leftAligned() const override { return false; } bool leftAligned() const override { return false; }
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool) const override { return "bool"; } std::string toString(bool) const override { return "bool"; }
u256 literalValue(Literal const* _literal) const override; u256 literalValue(Literal const* _literal) const override;
@ -773,6 +782,7 @@ public:
bool isDynamicallyEncoded() const override; bool isDynamicallyEncoded() const override;
u256 storageSize() const override; u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); } bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
bool nameable() const override { return true; }
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
std::string canonicalName() const override; std::string canonicalName() const override;
std::string signatureInExternalFunction(bool _structsByName) const override; std::string signatureInExternalFunction(bool _structsByName) const override;
@ -875,6 +885,7 @@ public:
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; } bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
bool canLiveOutsideStorage() const override { return !isSuper(); } bool canLiveOutsideStorage() const override { return !isSuper(); }
bool isValueType() 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 toString(bool _short) const override;
std::string canonicalName() const override; std::string canonicalName() const override;
@ -935,6 +946,7 @@ public:
u256 memoryDataSize() const override; u256 memoryDataSize() const override;
u256 storageSize() const override; u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return true; } bool canLiveOutsideStorage() const override { return true; }
bool nameable() const override { return true; }
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
@ -997,6 +1009,7 @@ public:
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
std::string canonicalName() const override; std::string canonicalName() const override;
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool nameable() const override { return true; }
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer encodingType() const override; TypePointer encodingType() const override;
@ -1202,6 +1215,7 @@ public:
bool leftAligned() const override; bool leftAligned() const override;
unsigned storageBytes() const override; unsigned storageBytes() const override;
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool nameable() const override;
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; } bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
bool hasSimpleZeroValueInMemory() const override { return false; } bool hasSimpleZeroValueInMemory() const override { return false; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; 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 /// @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 /// 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. /// Also supports variants to be used for library or bound calls.
/// @param _inLibrary if true, uses DelegateCall as location. /// @param _inLibrary if true, uses DelegateCall as location.
/// @param _bound if true, the function type is set to be bound. /// @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: protected:
std::vector<std::tuple<std::string, TypePointer>> makeStackItems() const override; 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; } bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
/// Cannot be stored in memory, but just in case. /// Cannot be stored in memory, but just in case.
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
bool nameable() const override { return true; }
Type const* keyType() const { return m_keyType; } Type const* keyType() const { return m_keyType; }
Type const* valueType() const { return m_valueType; } Type const* valueType() const { return m_valueType; }

View File

@ -1022,6 +1022,10 @@ void CompilerUtils::convertType(
case Type::Category::ArraySlice: case Type::Category::ArraySlice:
{ {
auto& typeOnStack = dynamic_cast<ArraySliceType const&>(_typeOnStack); 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(), ""); solAssert(_targetType == typeOnStack.arrayType(), "");
solUnimplementedAssert( solUnimplementedAssert(
typeOnStack.arrayType().location() == DataLocation::CallData && typeOnStack.arrayType().location() == DataLocation::CallData &&
@ -1218,6 +1222,15 @@ void CompilerUtils::pushZeroValue(Type const& _type)
m_context << u256(0); m_context << u256(0);
return; 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, ""); solAssert(referenceType->location() == DataLocation::Memory, "");
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type)) if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
if (arrayType->isDynamicallySized()) if (arrayType->isDynamicallySized())

View File

@ -1667,8 +1667,10 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co
for (size_t i = 0; i < members.size(); ++i) for (size_t i = 0; i < members.size(); ++i)
{ {
solAssert(members[i]->memoryHeadSize() == 32, ""); solAssert(members[i]->memoryHeadSize() == 32, "");
solAssert(members[i]->dataStoredIn(DataLocation::Memory), ""); memberParams[i]["zeroValue"] = zeroValueFunction(
memberParams[i]["zeroValue"] = zeroValueFunction(*members[i], false); *TypeProvider::withLocationIfReference(DataLocation::Memory, members[i]),
false
);
} }
templ("member", memberParams); templ("member", memberParams);
return templ.render(); return templ.render();
@ -2238,6 +2240,27 @@ string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctio
("functionName", functionName) ("functionName", functionName)
.render(); .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"( Whiskers templ(R"(
function <functionName>() -> ret { function <functionName>() -> ret {
ret := <zeroValue> ret := <zeroValue>
@ -2622,4 +2645,3 @@ string YulUtilFunctions::copyConstructorArgumentsToMemoryFunction(
.render(); .render();
}); });
} }

View File

@ -29,6 +29,8 @@
#include <libsolutil/Whiskers.h> #include <libsolutil/Whiskers.h>
#include <libsolutil/StringUtils.h> #include <libsolutil/StringUtils.h>
#include <boost/range/adaptor/map.hpp>
using namespace std; using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
@ -121,52 +123,55 @@ string IRGenerationContext::newYulVariable()
return "_" + to_string(++m_varCounter); return "_" + to_string(++m_varCounter);
} }
string IRGenerationContext::generateInternalDispatchFunction(YulArity const& _arity) void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _internalDispatch)
{ {
string funName = IRNames::internalDispatch(_arity); solAssert(internalDispatchClean(), "");
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)}
});
for (set<FunctionDefinition const*> const& functions: _internalDispatch | boost::adaptors::map_values)
for (auto function: functions)
enqueueFunctionForCodeGeneration(*function); enqueueFunctionForCodeGeneration(*function);
}
templ("cases", move(cases)); m_internalDispatchMap = move(_internalDispatch);
return templ.render(); }
});
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() YulUtilFunctions IRGenerationContext::utils()
@ -183,21 +188,3 @@ std::string IRGenerationContext::revertReasonIfDebug(std::string const& _message
{ {
return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _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;
}

View File

@ -43,6 +43,8 @@ namespace solidity::frontend
class YulUtilFunctions; class YulUtilFunctions;
class ABIFunctions; class ABIFunctions;
using InternalDispatchMap = std::map<YulArity, std::set<FunctionDefinition const*>>;
/** /**
* Class that contains contextual information during IR generation. * Class that contains contextual information during IR generation.
*/ */
@ -102,7 +104,26 @@ public:
std::string newYulVariable(); 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). /// @returns a new copy of the utility function generator (but using the same function set).
YulUtilFunctions utils(); YulUtilFunctions utils();
@ -120,8 +141,6 @@ public:
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; } std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
private: private:
std::set<FunctionDefinition const*> collectFunctionsOfArity(YulArity const& _arity);
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;
RevertStrings m_revertStrings; RevertStrings m_revertStrings;
OptimiserSettings m_optimiserSettings; OptimiserSettings m_optimiserSettings;
@ -147,6 +166,13 @@ private:
/// all platforms - which is a property guaranteed by MultiUseYulFunctionCollector. /// all platforms - which is a property guaranteed by MultiUseYulFunctionCollector.
std::set<FunctionDefinition const*> m_functionGenerationQueue; 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; std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
}; };

View File

@ -38,6 +38,8 @@
#include <liblangutil/SourceReferenceFormatter.h> #include <liblangutil/SourceReferenceFormatter.h>
#include <boost/range/adaptor/map.hpp>
#include <sstream> #include <sstream>
using namespace std; using namespace std;
@ -137,14 +139,22 @@ string IRGenerator::generate(
t("deploy", deployCode(_contract)); t("deploy", deployCode(_contract));
generateImplicitConstructors(_contract); generateImplicitConstructors(_contract);
generateQueuedFunctions(); generateQueuedFunctions();
InternalDispatchMap internalDispatchMap = generateInternalDispatchFunctions();
t("functions", m_context.functionCollector().requestedFunctions()); t("functions", m_context.functionCollector().requestedFunctions());
t("subObjects", subObjectSources(m_context.subObjectsCreated())); t("subObjects", subObjectSources(m_context.subObjectsCreated()));
resetContext(_contract); 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. // Do not register immutables to avoid assignment.
t("RuntimeObject", IRNames::runtimeObject(_contract)); t("RuntimeObject", IRNames::runtimeObject(_contract));
t("dispatch", dispatchRoutine(_contract)); t("dispatch", dispatchRoutine(_contract));
generateQueuedFunctions(); generateQueuedFunctions();
generateInternalDispatchFunctions();
t("runtimeFunctions", m_context.functionCollector().requestedFunctions()); t("runtimeFunctions", m_context.functionCollector().requestedFunctions());
t("runtimeSubObjects", subObjectSources(m_context.subObjectsCreated())); t("runtimeSubObjects", subObjectSources(m_context.subObjectsCreated()));
return t.render(); return t.render();
@ -164,6 +174,68 @@ void IRGenerator::generateQueuedFunctions()
generateFunction(*m_context.dequeueFunctionForCodeGeneration()); 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 IRGenerator::generateFunction(FunctionDefinition const& _function)
{ {
string functionName = IRNames::function(_function); string functionName = IRNames::function(_function);
@ -556,6 +628,10 @@ void IRGenerator::resetContext(ContractDefinition const& _contract)
m_context.functionCollector().requestedFunctions().empty(), m_context.functionCollector().requestedFunctions().empty(),
"Reset context while it still had functions." "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 = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings);
m_context.setMostDerivedContract(_contract); m_context.setMostDerivedContract(_contract);

View File

@ -65,6 +65,11 @@ private:
/// Generates code for all the functions from the function generation queue. /// Generates code for all the functions from the function generation queue.
/// The resulting code is stored in the function collector in IRGenerationContext. /// The resulting code is stored in the function collector in IRGenerationContext.
void generateQueuedFunctions(); 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. /// Generates code for and returns the name of the function.
std::string generateFunction(FunctionDefinition const& _function); std::string generateFunction(FunctionDefinition const& _function);
/// Generates a getter for the given declaration and returns its name /// Generates a getter for the given declaration and returns its name

View File

@ -583,6 +583,20 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
return false; 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) void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
{ {
solUnimplementedAssert( solUnimplementedAssert(
@ -661,8 +675,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
solAssert(functionDef->isImplemented(), ""); solAssert(functionDef->isImplemented(), "");
} }
else
solAssert(!functionType->hasDeclaration(), "");
solAssert(!functionType->takesArbitraryParameters(), ""); solAssert(!functionType->takesArbitraryParameters(), "");
@ -688,9 +700,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
else else
{ {
YulArity arity = YulArity::fromType(*functionType); YulArity arity = YulArity::fromType(*functionType);
m_context.internalFunctionCalledThroughDispatch(arity);
define(_functionCall) << define(_functionCall) <<
// NOTE: generateInternalDispatchFunction() takes care of adding the function to function generation queue IRNames::internalDispatch(arity) <<
m_context.generateInternalDispatchFunction(arity) <<
"(" << "(" <<
IRVariable(_functionCall.expression()).part("functionIdentifier").name() << IRVariable(_functionCall.expression()).part("functionIdentifier").name() <<
joinHumanReadablePrefixed(args) << joinHumanReadablePrefixed(args) <<
@ -869,6 +882,45 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
m_code << templ.render(); m_code << templ.render();
break; 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: case FunctionType::Kind::Revert:
{ {
solAssert(arguments.size() == parameterTypes.size(), ""); solAssert(arguments.size() == parameterTypes.size(), "");
@ -1354,7 +1406,6 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
else if (member == "data") else if (member == "data")
{ {
IRVariable var(_memberAccess); IRVariable var(_memberAccess);
declare(var);
define(var.part("offset")) << "0\n"; define(var.part("offset")) << "0\n";
define(var.part("length")) << "calldatasize()\n"; define(var.part("length")) << "calldatasize()\n";
} }
@ -1492,7 +1543,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
break; break;
case FunctionType::Kind::Internal: case FunctionType::Kind::Internal:
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration)) if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
{
define(_memberAccess) << to_string(function->id()) << "\n"; define(_memberAccess) << to_string(function->id()) << "\n";
m_context.internalFunctionAccessed(_memberAccess, *function);
}
else else
solAssert(false, "Function not found in member access"); solAssert(false, "Function not found in member access");
break; break;
@ -1756,7 +1810,14 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
return; return;
} }
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration)) 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)) else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
handleVariableReference(*varDecl, _identifier); handleVariableReference(*varDecl, _identifier);
else if (dynamic_cast<ContractDefinition const*>(declaration)) else if (dynamic_cast<ContractDefinition const*>(declaration))

View File

@ -70,6 +70,7 @@ public:
void endVisit(Return const& _return) override; void endVisit(Return const& _return) override;
void endVisit(UnaryOperation const& _unaryOperation) override; void endVisit(UnaryOperation const& _unaryOperation) override;
bool visit(BinaryOperation const& _binOp) override; bool visit(BinaryOperation const& _binOp) override;
bool visit(FunctionCall const& _funCall) override;
void endVisit(FunctionCall const& _funCall) override; void endVisit(FunctionCall const& _funCall) override;
void endVisit(FunctionCallOptions const& _funCallOptions) override; void endVisit(FunctionCallOptions const& _funCallOptions) override;
void endVisit(MemberAccess const& _memberAccess) override; void endVisit(MemberAccess const& _memberAccess) override;

View File

@ -74,8 +74,8 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
if ( if (
function->name() == baseFunction->name() && function->name() == baseFunction->name() &&
function->kind() == baseFunction->kind() && function->kind() == baseFunction->kind() &&
FunctionType(*function).asCallableFunction(false)-> FunctionType(*function).asExternallyCallableFunction(false)->
hasEqualParameterTypes(*FunctionType(*baseFunction).asCallableFunction(false)) hasEqualParameterTypes(*FunctionType(*baseFunction).asExternallyCallableFunction(false))
) )
{ {
overridden = true; overridden = true;

View File

@ -73,7 +73,7 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect,
{}, {},
_object.dataNames() _object.dataNames()
).analyze(*_object.code); ).analyze(*_object.code);
yulAssert(success && errorList.empty(), "Invalid assembly/yul code."); yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code.");
return analysisInfo; return analysisInfo;
} }
@ -259,6 +259,8 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
returnTypes = &f->returns; returnTypes = &f->returns;
if (f->literalArguments) if (f->literalArguments)
needsLiteralArguments = &f->literalArguments.value(); needsLiteralArguments = &f->literalArguments.value();
warnOnInstructions(_funCall);
} }
else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{ else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
[&](Scope::Variable const&) [&](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."); declarationError(_funCall.functionName.location, "Function not found.");
yulAssert(!watcher.ok(), "Expected a reported error."); yulAssert(!watcher.ok(), "Expected a reported error.");
} }
if (parameterTypes && _funCall.arguments.size() != parameterTypes->size()) if (parameterTypes && _funCall.arguments.size() != parameterTypes->size())
typeError( typeError(
_funCall.functionName.location, _funCall.functionName.location,
@ -553,6 +556,14 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
errorForVM("only available for Constantinople-compatible"); errorForVM("only available for Constantinople-compatible");
else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID()) else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID())
errorForVM("only available for Istanbul-compatible"); 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()) else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
errorForVM("only available for Istanbul-compatible"); errorForVM("only available for Istanbul-compatible");
else if ( else if (

View File

@ -112,6 +112,11 @@ private:
bool warnOnInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location); bool warnOnInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location);
bool warnOnInstructions(std::string const& _instrIdentifier, 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 typeError(langutil::SourceLocation const& _location, std::string const& _description);
void declarationError(langutil::SourceLocation const& _location, std::string const& _description); void declarationError(langutil::SourceLocation const& _location, std::string const& _description);

View File

@ -396,6 +396,7 @@ bytes BinaryTransform::operator()(BranchIf const& _branchIf)
bytes BinaryTransform::operator()(Return const&) bytes BinaryTransform::operator()(Return const&)
{ {
// Note that this does not work if the function returns a value.
return toBytes(Opcode::Return); return toBytes(Opcode::Return);
} }

View File

@ -280,7 +280,8 @@ wasm::Expression WasmCodeTransform::operator()(Continue const&)
wasm::Expression WasmCodeTransform::operator()(Leave 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) wasm::Expression WasmCodeTransform::operator()(Block const& _block)
@ -330,10 +331,16 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin
fun.returns = !_fun.returnVariables.empty(); fun.returns = !_fun.returnVariables.empty();
yulAssert(m_localVariables.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; fun.locals += m_localVariables;
m_localVariables.clear(); m_localVariables.clear();
m_functionBodyLabel = {};
if (!_fun.returnVariables.empty()) if (!_fun.returnVariables.empty())
{ {

View File

@ -95,6 +95,7 @@ private:
std::vector<wasm::VariableDeclaration> m_localVariables; std::vector<wasm::VariableDeclaration> m_localVariables;
std::vector<wasm::GlobalVariableDeclaration> m_globalVariables; std::vector<wasm::GlobalVariableDeclaration> m_globalVariables;
std::map<YulString, wasm::FunctionImport> m_functionsToImport; std::map<YulString, wasm::FunctionImport> m_functionsToImport;
std::string m_functionBodyLabel;
std::stack<std::pair<std::string, std::string>> m_breakContinueLabelNames; std::stack<std::pair<std::string, std::string>> m_breakContinueLabelNames;
}; };

View File

@ -90,7 +90,6 @@ void MSizeFinder::operator()(FunctionCall const& _functionCall)
m_msizeFound = true; m_msizeFound = true;
} }
map<YulString, SideEffects> SideEffectsPropagator::sideEffects( map<YulString, SideEffects> SideEffectsPropagator::sideEffects(
Dialect const& _dialect, Dialect const& _dialect,
CallGraph const& _directCallGraph CallGraph const& _directCallGraph

View File

@ -36,7 +36,7 @@ using namespace solidity::evmasm;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::yul; using namespace solidity::yul;
SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch( SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
Expression const& _expr, Expression const& _expr,
Dialect const& _dialect, Dialect const& _dialect,
map<YulString, AssignedValue> const& _ssaValues map<YulString, AssignedValue> const& _ssaValues
@ -46,7 +46,16 @@ SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
if (!instruction) if (!instruction)
return nullptr; 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."); assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized.");
for (auto const& rule: rules.m_rules[uint8_t(instruction->first)]) 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 {}; return {};
} }
void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules) void SimplificationRules::addRules(std::vector<Rule> const& _rules)
{ {
for (auto const& r: _rules) for (auto const& r: _rules)
addRule(r); 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); 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. // Multiple occurrences of one of these inside one rule must match the same equivalence class.
// Constants. // Constants.
@ -107,7 +116,7 @@ SimplificationRules::SimplificationRules()
Y.setMatchGroup(6, m_matchGroups); Y.setMatchGroup(6, m_matchGroups);
Z.setMatchGroup(7, 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."); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
} }

View File

@ -27,6 +27,8 @@
#include <libsolutil/CommonData.h> #include <libsolutil/CommonData.h>
#include <liblangutil/EVMVersion.h>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <functional> #include <functional>
@ -45,12 +47,14 @@ class Pattern;
class SimplificationRules: public boost::noncopyable class SimplificationRules: public boost::noncopyable
{ {
public: 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 /// @returns a pointer to the first matching pattern and sets the match
/// groups accordingly. /// groups accordingly.
/// @param _ssaValues values of variables that are assigned exactly once. /// @param _ssaValues values of variables that are assigned exactly once.
static evmasm::SimplificationRule<Pattern> const* findFirstMatch( static Rule const* findFirstMatch(
Expression const& _expr, Expression const& _expr,
Dialect const& _dialect, Dialect const& _dialect,
std::map<YulString, AssignedValue> const& _ssaValues std::map<YulString, AssignedValue> const& _ssaValues
@ -64,8 +68,8 @@ public:
instructionAndArguments(Dialect const& _dialect, Expression const& _expr); instructionAndArguments(Dialect const& _dialect, Expression const& _expr);
private: private:
void addRules(std::vector<evmasm::SimplificationRule<Pattern>> const& _rules); void addRules(std::vector<Rule> const& _rules);
void addRule(evmasm::SimplificationRule<Pattern> const& _rule); void addRule(Rule const& _rule);
void resetMatchGroups() { m_matchGroups.clear(); } void resetMatchGroups() { m_matchGroups.clear(); }

View File

@ -8,10 +8,13 @@ import json
SOLC_BIN = sys.argv[1] SOLC_BIN = sys.argv[1]
REPORT_FILE = open("report.txt", mode="w", encoding='utf8', newline='\n') 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 optimize in [False, True]:
for f in sorted(glob.glob("*.sol")): for f in sorted(glob.glob("*.sol")):
sources = {} sources = {}
sources[f] = {'content': open(f, mode='r', encoding='utf8').read()} sources[f] = {'content': removeSMT(open(f, mode='r', encoding='utf8').read())}
input_json = { input_json = {
'language': 'Solidity', 'language': 'Solidity',
'sources': sources, 'sources': sources,

View File

@ -64,6 +64,11 @@ var fs = require('fs')
var compiler = require('./solc-js/wrapper.js')(require('./solc-js/soljson.js')) 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 optimize of [false, true])
{ {
for (var filename of process.argv.slice(2)) for (var filename of process.argv.slice(2))
@ -71,7 +76,7 @@ for (var optimize of [false, true])
if (filename !== undefined) if (filename !== undefined)
{ {
var inputs = {} var inputs = {}
inputs[filename] = { content: fs.readFileSync(filename).toString() } inputs[filename] = { content: removeSMT(fs.readFileSync(filename).toString()) }
var input = { var input = {
language: 'Solidity', language: 'Solidity',
sources: inputs, sources: inputs,
@ -107,8 +112,10 @@ for (var optimize of [false, true])
} }
} }
EOF EOF
echo "Running the compiler..."
chmod +x solc chmod +x solc
./solc *.sol > report.txt ./solc *.sol > report.txt
echo "Finished running the compiler."
else else
$REPO_ROOT/scripts/bytecodecompare/prepare_report.py $REPO_ROOT/$BUILD_DIR/solc/solc $REPO_ROOT/scripts/bytecodecompare/prepare_report.py $REPO_ROOT/$BUILD_DIR/solc/solc
fi fi
@ -138,6 +145,9 @@ EOF
else else
echo "Adding report failed, it might already exist in the repository." echo "Adding report failed, it might already exist in the repository."
fi fi
else
echo "Not storing bytecode because the keys are not available."
fi fi
) )
rm -rf "$TMPDIR" rm -rf "$TMPDIR"
echo "Storebytecode finished."

View File

@ -55,7 +55,6 @@ def get_used_ids(file_names):
def get_id(available_ids, used_ids): def get_id(available_ids, used_ids):
while len(available_ids) > 0: while len(available_ids) > 0:
random.seed(len(available_ids))
k = random.randrange(len(available_ids)) k = random.randrange(len(available_ids))
id = list(available_ids.keys())[k] id = list(available_ids.keys())[k]
del available_ids[id] del available_ids[id]
@ -117,6 +116,7 @@ def find_source_files(top_dir):
def main(): def main():
random.seed()
cwd = os.getcwd() cwd = os.getcwd()
answer = input( answer = input(
f"This script checks and corrects *_error literals in .h and .cpp files\n" f"This script checks and corrects *_error literals in .h and .cpp files\n"

View File

@ -45,7 +45,7 @@ object "object" {
Binary representation: Binary representation:
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010abe01052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3e01007e2000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b 0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acd01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b4101007e02402000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b0b
Text representation: Text representation:
(module (module
@ -55,17 +55,22 @@ Text representation:
(func $main (func $main
(local $_1 i64) (local $_1 i64)
(block $label_
(local.set $_1 (i64.const 0)) (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 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 $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32))) (call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
)
) )
(func $endian_swap_16 (func $endian_swap_16
(param $x i64) (param $x i64)
(result i64) (result i64)
(local $y i64) (local $y i64)
(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.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) (local.get $y)
) )
@ -74,8 +79,11 @@ Text representation:
(result i64) (result i64)
(local $y i64) (local $y i64)
(local $hi i64) (local $hi i64)
(block $label__2
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16))) (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.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
)
(local.get $y) (local.get $y)
) )
@ -84,8 +92,11 @@ Text representation:
(result i64) (result i64)
(local $y i64) (local $y i64)
(local $hi i64) (local $hi i64)
(block $label__3
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) (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.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
)
(local.get $y) (local.get $y)
) )
@ -95,10 +106,12 @@ Text representation:
(param $y2 i64) (param $y2 i64)
(param $y3 i64) (param $y3 i64)
(param $y4 i64) (param $y4 i64)
(block $label__4
(i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1))) (i64.store (i32.wrap_i64 (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 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 16))))) (call $endian_swap (local.get $y3)))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4))) (i64.store (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)))
)
) )
) )

View File

@ -154,7 +154,7 @@ object "object" {
Binary representation: Binary representation:
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020a82090df002011f7e4200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b2c01037e200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21042004240020030b6f010b7e200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b2011210820092400200a2401200b240220080b2301047e200020018420022003848450ada7ad210720052400200624012007240220040b4601047e2000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b20092400200a2401200b240220080b2a01027e02402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b20020b930101087e4200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b20092400200a2401200b240220080b8c0101087e4200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b210720052400200624012007240220040b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e2000100a421086210220022000421088100a84210120010b1b01027e2000100b422086210220022000422088100b84210120010b3e01007e2000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b2401007e42002000200120022003100d42202004200520062007100d4200a74220a710000b 0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa9090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b4101007e02402000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b0b2701007e024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b
Text representation: Text representation:
(module (module
@ -198,6 +198,7 @@ Text representation:
(local $x_9 i64) (local $x_9 i64)
(local $x_10 i64) (local $x_10 i64)
(local $x_11 i64) (local $x_11 i64)
(block $label_
(local.set $_1 (i64.const 0)) (local.set $_1 (i64.const 0))
(block (block
(local.set $x (call $calldataload (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (local.set $x (call $calldataload (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)))
@ -212,10 +213,10 @@ Text representation:
(local.set $x_7 (local.get $x_3)) (local.set $x_7 (local.get $x_3))
(local.set $_2 (i64.const 1)) (local.set $_2 (i64.const 1))
(local.set $_3 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_1) (local.get $_1)) (i64.or (local.get $_1) (local.get $_2)))))))))))) (local.set $_3 (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 $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 (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 $_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 $_5 (global.get $global_))
@ -231,7 +232,7 @@ Text representation:
) )
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_8) (local.get $_9)) (i64.or (local.get $_10) (local.get $_11)))))))) (i64.const 0)) (then (if (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_) (br $label__3)
)) ))
(block (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 $_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)))
@ -241,7 +242,7 @@ Text representation:
) )
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_12) (local.get $_13)) (i64.or (local.get $_14) (local.get $_15)))))))) (i64.const 0)) (then (if (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_) (br $label__3)
)) ))
(block (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 $_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)))
@ -251,7 +252,7 @@ Text representation:
) )
(if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_16) (local.get $_17)) (i64.or (local.get $_18) (local.get $_19)))))))) (i64.const 0)) (then (if (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) (br $label__4)
)) ))
) )
@ -266,11 +267,12 @@ Text representation:
(local.set $x_5 (local.get $x_9)) (local.set $x_5 (local.get $x_9))
(local.set $x_6 (local.get $x_10)) (local.set $x_6 (local.get $x_10))
(local.set $x_7 (local.get $x_11)) (local.set $x_7 (local.get $x_11))
(br $label__4) (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 (func $add_carry
@ -281,9 +283,12 @@ Text representation:
(local $r i64) (local $r i64)
(local $r_c i64) (local $r_c i64)
(local $t i64) (local $t i64)
(block $label__6
(local.set $t (i64.add (local.get $x) (local.get $y))) (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 (i64.add (local.get $t) (local.get $c)))
(local.set $r_c (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $t))))))))) (local.set $r_c (i64.extend_i32_u (i32.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)) (global.set $global_ (local.get $r_c))
(local.get $r) (local.get $r)
) )
@ -309,6 +314,7 @@ Text representation:
(local $carry_1 i64) (local $carry_1 i64)
(local $r1_1 i64) (local $r1_1 i64)
(local $carry_2 i64) (local $carry_2 i64)
(block $label__7
(local.set $t (i64.add (local.get $x4) (local.get $y4))) (local.set $t (i64.add (local.get $x4) (local.get $y4)))
(local.set $r4 (i64.add (local.get $t) (i64.const 0))) (local.set $r4 (i64.add (local.get $t) (i64.const 0)))
(block (block
@ -329,6 +335,8 @@ Text representation:
) )
(local.set $r1 (local.get $r1_1)) (local.set $r1 (local.get $r1_1))
)
(global.set $global_ (local.get $r2)) (global.set $global_ (local.get $r2))
(global.set $global__1 (local.get $r3)) (global.set $global__1 (local.get $r3))
(global.set $global__2 (local.get $r4)) (global.set $global__2 (local.get $r4))
@ -345,7 +353,10 @@ Text representation:
(local $r2 i64) (local $r2 i64)
(local $r3 i64) (local $r3 i64)
(local $r4 i64) (local $r4 i64)
(block $label__8
(local.set $r4 (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $x1) (local.get $x2)) (i64.or (local.get $x3) (local.get $x4)))))))) (local.set $r4 (i64.extend_i32_u (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_ (local.get $r2))
(global.set $global__1 (local.get $r3)) (global.set $global__1 (local.get $r3))
(global.set $global__2 (local.get $r4)) (global.set $global__2 (local.get $r4))
@ -366,6 +377,7 @@ Text representation:
(local $r2 i64) (local $r2 i64)
(local $r3 i64) (local $r3 i64)
(local $r4 i64) (local $r4 i64)
(block $label__9
(if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x1) (local.get $y1))) (i64.const 0)) (then (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $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 $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 $x3) (local.get $y3))) (i64.const 0)) (then
@ -375,6 +387,8 @@ Text representation:
)) ))
)) ))
)) ))
)
(global.set $global_ (local.get $r2)) (global.set $global_ (local.get $r2))
(global.set $global__1 (local.get $r3)) (global.set $global__1 (local.get $r3))
(global.set $global__2 (local.get $r4)) (global.set $global__2 (local.get $r4))
@ -387,6 +401,7 @@ Text representation:
(result i64) (result i64)
(local $r i64) (local $r i64)
(local $condition i64) (local $condition i64)
(block $label__10
(block (block
(local.set $condition (i64.extend_i32_u (i64.lt_u (local.get $a) (local.get $b)))) (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 (if (i64.eq (local.get $condition) (i64.const 1)) (then
@ -396,6 +411,8 @@ Text representation:
)) ))
) )
)
(local.get $r) (local.get $r)
) )
@ -414,22 +431,23 @@ Text representation:
(local $z3 i64) (local $z3 i64)
(local $z4 i64) (local $z4 i64)
(local $z i64) (local $z i64)
(local $condition_5 i64) (local $condition_12 i64)
(local $condition_6 i64) (local $condition_13 i64)
(local $condition_7 i64) (local $condition_14 i64)
(block $label__11
(local.set $z (i64.const 0)) (local.set $z (i64.const 0))
(block (block
(local.set $condition_5 (call $cmp (local.get $x1) (local.get $y1))) (local.set $condition_12 (call $cmp (local.get $x1) (local.get $y1)))
(if (i64.eq (local.get $condition_5) (i64.const 0)) (then (if (i64.eq (local.get $condition_12) (i64.const 0)) (then
(block (block
(local.set $condition_6 (call $cmp (local.get $x2) (local.get $y2))) (local.set $condition_13 (call $cmp (local.get $x2) (local.get $y2)))
(if (i64.eq (local.get $condition_6) (i64.const 0)) (then (if (i64.eq (local.get $condition_13) (i64.const 0)) (then
(block (block
(local.set $condition_7 (call $cmp (local.get $x3) (local.get $y3))) (local.set $condition_14 (call $cmp (local.get $x3) (local.get $y3)))
(if (i64.eq (local.get $condition_7) (i64.const 0)) (then (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)))) (local.set $z (i64.extend_i32_u (i64.lt_u (local.get $x4) (local.get $y4))))
)(else )(else
(if (i64.eq (local.get $condition_7) (i64.const 1)) (then (if (i64.eq (local.get $condition_14) (i64.const 1)) (then
(local.set $z (i64.const 0)) (local.set $z (i64.const 0))
)(else )(else
(local.set $z (i64.const 1)) (local.set $z (i64.const 1))
@ -438,7 +456,7 @@ Text representation:
) )
)(else )(else
(if (i64.eq (local.get $condition_6) (i64.const 1)) (then (if (i64.eq (local.get $condition_13) (i64.const 1)) (then
(local.set $z (i64.const 0)) (local.set $z (i64.const 0))
)(else )(else
(local.set $z (i64.const 1)) (local.set $z (i64.const 1))
@ -447,7 +465,7 @@ Text representation:
) )
)(else )(else
(if (i64.eq (local.get $condition_5) (i64.const 1)) (then (if (i64.eq (local.get $condition_12) (i64.const 1)) (then
(local.set $z (i64.const 0)) (local.set $z (i64.const 0))
)(else )(else
(local.set $z (i64.const 1)) (local.set $z (i64.const 1))
@ -456,6 +474,8 @@ Text representation:
) )
(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_ (local.get $z2))
(global.set $global__1 (local.get $z3)) (global.set $global__1 (local.get $z3))
(global.set $global__2 (local.get $z4)) (global.set $global__2 (local.get $z4))
@ -476,6 +496,7 @@ Text representation:
(local $z2_1 i64) (local $z2_1 i64)
(local $z3_1 i64) (local $z3_1 i64)
(local $z4_1 i64) (local $z4_1 i64)
(block $label__15
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then (if (i64.ne (i64.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))) (unreachable)))
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then
@ -489,6 +510,8 @@ Text representation:
(local.set $z2 (local.get $z2_1)) (local.set $z2 (local.get $z2_1))
(local.set $z3 (local.get $z3_1)) (local.set $z3 (local.get $z3_1))
(local.set $z4 (local.get $z4_1)) (local.set $z4 (local.get $z4_1))
)
(global.set $global_ (local.get $z2)) (global.set $global_ (local.get $z2))
(global.set $global__1 (local.get $z3)) (global.set $global__1 (local.get $z3))
(global.set $global__2 (local.get $z4)) (global.set $global__2 (local.get $z4))
@ -499,7 +522,10 @@ Text representation:
(param $x i64) (param $x i64)
(result i64) (result i64)
(local $y i64) (local $y i64)
(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.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) (local.get $y)
) )
@ -508,8 +534,11 @@ Text representation:
(result i64) (result i64)
(local $y i64) (local $y i64)
(local $hi i64) (local $hi i64)
(block $label__17
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16))) (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.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
)
(local.get $y) (local.get $y)
) )
@ -518,8 +547,11 @@ Text representation:
(result i64) (result i64)
(local $y i64) (local $y i64)
(local $hi i64) (local $hi i64)
(block $label__18
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) (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.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
)
(local.get $y) (local.get $y)
) )
@ -529,10 +561,12 @@ Text representation:
(param $y2 i64) (param $y2 i64)
(param $y3 i64) (param $y3 i64)
(param $y4 i64) (param $y4 i64)
(block $label__19
(i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1))) (i64.store (i32.wrap_i64 (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 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 16))))) (call $endian_swap (local.get $y3)))
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4))) (i64.store (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 (func $sstore
@ -544,9 +578,11 @@ Text representation:
(param $y2 i64) (param $y2 i64)
(param $y3 i64) (param $y3 i64)
(param $y4 i64) (param $y4 i64)
(block $label__20
(call $mstore_internal (i64.const 0) (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $mstore_internal (i64.const 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 $mstore_internal (i64.const 32) (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32))) (call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
)
) )
) )

View File

@ -16,6 +16,7 @@
(local $z2 i64) (local $z2 i64)
(local $z3 i64) (local $z3 i64)
(local $_3 i64) (local $_3 i64)
(block $label_
(local.set $_1 (i64.const 0)) (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 $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))))) (local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
@ -35,6 +36,7 @@
(local.set $_3 (datasize \"C_2_deployed\")) (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 $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)) (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 (func $u256_to_i32
@ -44,11 +46,14 @@
(param $x4 i64) (param $x4 i64)
(result i64) (result i64)
(local $v i64) (local $v i64)
(block $label__1
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then (if (i64.ne (i64.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))) (unreachable)))
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then
(unreachable))) (unreachable)))
(local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4)))) (local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4))))
)
(local.get $v) (local.get $v)
) )
@ -60,10 +65,13 @@
(result i64) (result i64)
(local $r i64) (local $r i64)
(local $p i64) (local $p i64)
(block $label__2
(local.set $p (call $u256_to_i32 (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (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))))) (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 (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))) (unreachable)))
)
(local.get $r) (local.get $r)
) )
@ -80,14 +88,19 @@
(param $z2 i64) (param $z2 i64)
(param $z3 i64) (param $z3 i64)
(param $z4 i64) (param $z4 i64)
(block $label__3
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4)))) (call $eth.codeCopy (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 (func $endian_swap_16
(param $x i64) (param $x i64)
(result i64) (result i64)
(local $y i64) (local $y i64)
(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.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) (local.get $y)
) )
@ -96,8 +109,11 @@
(result i64) (result i64)
(local $y i64) (local $y i64)
(local $hi i64) (local $hi i64)
(block $label__5
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16))) (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.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
)
(local.get $y) (local.get $y)
) )
@ -106,8 +122,11 @@
(result i64) (result i64)
(local $y i64) (local $y i64)
(local $hi i64) (local $hi i64)
(block $label__6
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) (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.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
)
(local.get $y) (local.get $y)
) )
@ -120,7 +139,9 @@
(param $y2 i64) (param $y2 i64)
(param $y3 i64) (param $y3 i64)
(param $y4 i64) (param $y4 i64)
(block $label__7
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))) (call $eth.finish (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 (func $revert
@ -132,7 +153,9 @@
(param $y2 i64) (param $y2 i64)
(param $y3 i64) (param $y3 i64)
(param $y4 i64) (param $y4 i64)
(block $label__8
(call $eth.revert (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))) (call $eth.revert (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))))
)
) )
) )

View File

@ -4,5 +4,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(bytes): 0x20, 0xc0, 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 -> 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 // f(bytes): 0x20, 0xc0, 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 -> 0x20, 0x4, 0x3, 0x4, 0x5, 0x6

View File

@ -8,5 +8,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6 // f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6

View File

@ -11,5 +11,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6 // f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6

View File

@ -4,5 +4,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(bytes): 0x20, 0x20, 0x21 -> 33 // f(bytes): 0x20, 0x20, 0x21 -> 33

View File

@ -5,5 +5,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 0x21, 0x40, 0x7, "abcdefg" // f() -> 0x21, 0x40, 0x7, "abcdefg"

View File

@ -5,5 +5,8 @@ contract C {
f = abi.decode(msg.data[4 + 32 : 4 + 32 + 32], (uint256)); f = abi.decode(msg.data[4 + 32 : 4 + 32 + 32], (uint256));
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(uint256,uint256): 42, 23 -> 42, 23, 42, 23 // f(uint256,uint256): 42, 23 -> 42, 23, 42, 23

View File

@ -18,6 +18,9 @@ contract C {
} }
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// test(bytes): 0x20, 0x80, 0x40, 0x60, 0, 0 -> false, false // test(bytes): 0x20, 0x80, 0x40, 0x60, 0, 0 -> false, false
// test(bytes): 0x20, 0xC0, 0x40, 0x80, 1, 0x42, 1, 0x42 -> false, false // test(bytes): 0x20, 0xC0, 0x40, 0x80, 1, 0x42, 1, 0x42 -> false, false

View File

@ -7,5 +7,8 @@ contract C {
return abi.decode(data, (uint256, bytes)); return abi.decode(data, (uint256, bytes));
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" // f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"

View File

@ -3,5 +3,8 @@ contract C {
return abi.decode(data, (uint256, bytes)); return abi.decode(data, (uint256, bytes));
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" // f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"

View File

@ -6,5 +6,6 @@ contract C {
return abi.decode(data, (uint256, bytes)); return abi.decode(data, (uint256, bytes));
} }
} }
// ---- // ----
// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" // f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -22,5 +22,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f(uint256[]): 0x20, 0x3, 0x1, 0x7, 0x3 -> 11 // f(uint256[]): 0x20, 0x3, 0x1, 0x7, 0x3 -> 11

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -6,4 +6,4 @@ contract C {
// ---- // ----
// DeclarationError: (28-45): The "constant" keyword can only be used for state variables. // 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: (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.

View File

@ -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.

View File

@ -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.

View File

@ -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];
}
}
// ----

View File

@ -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];
}
}
// ----

View File

@ -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" or "calldata" for parameter in function, but "storage" was given.
// TypeError: (159-173): Data location must be "memory" for parameter in function, but "storage" was given.

View File

@ -2,4 +2,4 @@ contract C {
function i() external pure returns(uint[]) {} 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.

View File

@ -2,4 +2,5 @@ contract test {
function f(bytes memory) external; 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.

View File

@ -2,4 +2,4 @@ contract test {
function f(bytes storage) external; 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.

View File

@ -2,4 +2,5 @@ contract test {
function f(bytes calldata) internal; 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.

View File

@ -2,4 +2,4 @@ contract C {
function g(uint[]) internal pure {} 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.

View File

@ -2,4 +2,4 @@ contract C {
function g() internal pure returns(uint[]) {} 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.

View File

@ -6,7 +6,7 @@ library L {
function j(mapping(uint => uint)) external pure {} 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: (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" 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" 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" 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.

View File

@ -6,7 +6,7 @@ library L {
function j() external pure returns (mapping(uint => uint)) {} 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: (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" or "memory" 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" or "memory" 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" or "memory" 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.

View File

@ -10,11 +10,11 @@ library L {
function jp(mapping(uint => uint)) internal pure {} 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: (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" or "memory" 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" or "memory" 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" or "memory" 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" or "memory" for 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" or "memory" 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" or "memory" 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" or "memory" 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.

View File

@ -10,11 +10,11 @@ library L {
function jp(mapping(uint => uint)) 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: (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" or "memory" 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" or "memory" 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" or "memory" 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" or "memory" for 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" or "memory" 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" or "memory" 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" or "memory" 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.

View File

@ -9,11 +9,11 @@ library L {
function ip(S) private pure {} function ip(S) private pure {}
function jp(mapping(uint => uint)) 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: (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" or "memory" 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" or "memory" 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" or "memory" 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" or "memory" for 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" or "memory" 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" or "memory" 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" or "memory" 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.

View File

@ -2,4 +2,3 @@ library test {
function f(bytes memory) external {} function f(bytes memory) external {}
} }
// ---- // ----
// TypeError: (30-42): Data location must be "storage" or "calldata" for parameter in external function, but "memory" was given.

View File

@ -2,4 +2,3 @@ library test {
function f(bytes calldata) internal pure {} function f(bytes calldata) internal pure {}
} }
// ---- // ----
// TypeError: (30-44): Data location must be "storage" or "memory" for parameter in function, but "calldata" was given.

View File

@ -2,4 +2,4 @@ contract C {
function f(uint[]) private pure {} 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.

View File

@ -2,4 +2,4 @@ contract C {
function f() private pure returns(uint[]) {} 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.

View File

@ -2,4 +2,5 @@ contract test {
function f(bytes calldata) public; 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.

View File

@ -2,4 +2,4 @@ contract test {
function f(bytes storage) public; 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.

View File

@ -2,4 +2,4 @@ contract C {
function h(uint[]) public pure {} 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.

View File

@ -2,4 +2,4 @@ contract C {
function h() public pure returns(uint[]) {} 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.

View 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.

View File

@ -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.

View File

@ -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.

View File

@ -3,4 +3,4 @@ contract c {
} }
// ---- // ----
// TypeError: (51-52): Invalid array length, expected integer literal or constant expression. // 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.

View File

@ -3,4 +3,4 @@ contract c {
} }
// ---- // ----
// TypeError: (51-53): Array with negative length specified. // 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.

View File

@ -2,4 +2,3 @@ contract C {
function f(uint[] memory a) external {} function f(uint[] memory a) external {}
} }
// ---- // ----
// TypeError: (28-43): Data location must be "calldata" for parameter in external function, but "memory" was given.

View File

@ -2,4 +2,4 @@ contract C {
function f(uint[] storage a) external {} 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.

View File

@ -5,4 +5,4 @@ contract test {
} }
// ---- // ----
// TypeError: (55-58): Array with fractional length specified. // 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.

View File

@ -5,4 +5,4 @@ contract test {
} }
// ---- // ----
// TypeError: (55-65): Invalid array length, expected integer literal or constant expression. // 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.

View File

@ -5,4 +5,4 @@ contract test {
} }
// ---- // ----
// TypeError: (55-66): Invalid array length, expected integer literal or constant expression. // 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.

View File

@ -9,5 +9,5 @@ contract C {
} }
} }
// ---- // ----
// TypeError: (104-107): 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" or "memory" for variable, but none was given. // TypeError: (123-131): Data location must be "storage", "memory" or "calldata" for variable, but none was given.

View File

@ -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.

View File

@ -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.

View File

@ -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