mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8462 from ethereum/allocate_memory_zero_function
[Yul codegen] Zero initialize memory arrays
This commit is contained in:
commit
ed1000dde7
@ -2338,7 +2338,7 @@ TypePointers StructType::memoryMemberTypes() const
|
|||||||
TypePointers types;
|
TypePointers types;
|
||||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||||
if (variable->annotation().type->canLiveOutsideStorage())
|
if (variable->annotation().type->canLiveOutsideStorage())
|
||||||
types.push_back(variable->annotation().type);
|
types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type));
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,6 +658,8 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
|
|||||||
solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!");
|
solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!");
|
||||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
|
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
|
||||||
|
|
||||||
|
solAssert(_type.baseType()->isValueType(), "");
|
||||||
|
|
||||||
string functionName = "array_push_zero_" + _type.identifier();
|
string functionName = "array_push_zero_" + _type.identifier();
|
||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
@ -794,6 +796,7 @@ string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type)
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type)
|
string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
||||||
@ -1334,28 +1337,112 @@ string YulUtilFunctions::allocationFunction()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::allocateMemoryArrayFunction(ArrayType const& _type)
|
string YulUtilFunctions::zeroMemoryArrayFunction(ArrayType const& _type)
|
||||||
|
{
|
||||||
|
if (_type.baseType()->hasSimpleZeroValueInMemory())
|
||||||
|
return zeroMemoryFunction(*_type.baseType());
|
||||||
|
return zeroComplexMemoryArrayFunction(_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::zeroMemoryFunction(Type const& _type)
|
||||||
|
{
|
||||||
|
solAssert(_type.hasSimpleZeroValueInMemory(), "");
|
||||||
|
|
||||||
|
string functionName = "zero_memory_chunk_" + _type.identifier();
|
||||||
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(dataStart, dataSizeInBytes) {
|
||||||
|
calldatacopy(dataStart, calldatasize(), dataSizeInBytes)
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("functionName", functionName)
|
||||||
|
.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::zeroComplexMemoryArrayFunction(ArrayType const& _type)
|
||||||
|
{
|
||||||
|
solAssert(!_type.baseType()->hasSimpleZeroValueInMemory(), "");
|
||||||
|
|
||||||
|
string functionName = "zero_complex_memory_array_" + _type.identifier();
|
||||||
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
solAssert(_type.memoryStride() == 32, "");
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(dataStart, dataSizeInBytes) {
|
||||||
|
for {let i := 0} lt(i, dataSizeInBytes) { i := add(i, <stride>) } {
|
||||||
|
mstore(add(dataStart, i), <zeroValue>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("functionName", functionName)
|
||||||
|
("stride", to_string(_type.memoryStride()))
|
||||||
|
("zeroValue", zeroValueFunction(*_type.baseType(), false))
|
||||||
|
.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::allocateAndInitializeMemoryArrayFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(!_type.isByteArray(), "");
|
solUnimplementedAssert(!_type.isByteArray(), "");
|
||||||
|
|
||||||
string functionName = "allocate_memory_array_" + _type.identifier();
|
string functionName = "allocate_and_zero_memory_array_" + _type.identifier();
|
||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>(length) -> memPtr {
|
function <functionName>(length) -> memPtr {
|
||||||
memPtr := <alloc>(<allocSize>(length))
|
let allocSize := <allocSize>(length)
|
||||||
|
memPtr := <alloc>(allocSize)
|
||||||
|
let dataStart := memPtr
|
||||||
|
let dataSize := allocSize
|
||||||
<?dynamic>
|
<?dynamic>
|
||||||
|
dataStart := add(dataStart, 32)
|
||||||
|
dataSize := sub(dataSize, 32)
|
||||||
mstore(memPtr, length)
|
mstore(memPtr, length)
|
||||||
</dynamic>
|
</dynamic>
|
||||||
|
<zeroArrayFunction>(dataStart, dataSize)
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("alloc", allocationFunction())
|
("alloc", allocationFunction())
|
||||||
("allocSize", arrayAllocationSizeFunction(_type))
|
("allocSize", arrayAllocationSizeFunction(_type))
|
||||||
|
("zeroArrayFunction", zeroMemoryArrayFunction(_type))
|
||||||
("dynamic", _type.isDynamicallySized())
|
("dynamic", _type.isDynamicallySized())
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType const& _type)
|
||||||
|
{
|
||||||
|
string functionName = "allocate_and_initialize_memory_struct_" + _type.identifier();
|
||||||
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
Whiskers templ(R"(
|
||||||
|
function <functionName>() -> memPtr {
|
||||||
|
let allocSize := <allocSize>()
|
||||||
|
memPtr := <alloc>(allocSize)
|
||||||
|
let offset := memPtr
|
||||||
|
<#member>
|
||||||
|
mstore(offset, <zeroValue>())
|
||||||
|
offset := add(offset, 32)
|
||||||
|
</member>
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
templ("functionName", functionName);
|
||||||
|
templ("alloc", allocationFunction());
|
||||||
|
|
||||||
|
TypePointers const& members = _type.memoryMemberTypes();
|
||||||
|
templ("allocSize", _type.memoryDataSize().str());
|
||||||
|
|
||||||
|
vector<map<string, string>> memberParams(members.size());
|
||||||
|
for (size_t i = 0; i < members.size(); ++i)
|
||||||
|
{
|
||||||
|
solAssert(members[i]->memoryHeadSize() == 32, "");
|
||||||
|
solAssert(members[i]->dataStoredIn(DataLocation::Memory), "");
|
||||||
|
memberParams[i]["zeroValue"] = zeroValueFunction(*members[i], false);
|
||||||
|
}
|
||||||
|
templ("member", memberParams);
|
||||||
|
return templ.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||||
{
|
{
|
||||||
if (_from.category() == Type::Category::Function)
|
if (_from.category() == Type::Category::Function)
|
||||||
@ -1884,22 +1971,57 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::zeroValueFunction(Type const& _type)
|
string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(_type.sizeOnStack() == 1, "Stacksize not yet implemented!");
|
solAssert(_type.category() != Type::Category::Mapping, "");
|
||||||
solUnimplementedAssert(_type.isValueType(), "Zero value for non-value types not yet implemented");
|
|
||||||
|
|
||||||
string const functionName = "zero_value_for_" + _type.identifier();
|
string const functionName = "zero_value_for_" + string(_splitFunctionTypes ? "split_" : "") + _type.identifier();
|
||||||
|
|
||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
FunctionType const* fType = dynamic_cast<FunctionType const*>(&_type);
|
||||||
|
if (fType && fType->kind() == FunctionType::Kind::External && _splitFunctionTypes)
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>() -> ret {
|
function <functionName>() -> retAddress, retFunction {
|
||||||
<body>
|
retAddress := 0
|
||||||
|
retFunction := 0
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("body", "ret := 0x0")
|
|
||||||
.render();
|
.render();
|
||||||
|
|
||||||
|
Whiskers templ(R"(
|
||||||
|
function <functionName>() -> ret {
|
||||||
|
ret := <zeroValue>
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
templ("functionName", functionName);
|
||||||
|
|
||||||
|
if (_type.isValueType())
|
||||||
|
{
|
||||||
|
solAssert((
|
||||||
|
_type.hasSimpleZeroValueInMemory() ||
|
||||||
|
(fType && (fType->kind() == FunctionType::Kind::Internal || fType->kind() == FunctionType::Kind::External))
|
||||||
|
), "");
|
||||||
|
templ("zeroValue", "0");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(_type.dataStoredIn(DataLocation::Memory), "");
|
||||||
|
if (auto const* arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||||
|
{
|
||||||
|
if (_type.isDynamicallySized())
|
||||||
|
templ("zeroValue", to_string(CompilerUtils::zeroPointer));
|
||||||
|
else
|
||||||
|
templ("zeroValue", allocateAndInitializeMemoryArrayFunction(*arrayType) + "(" + to_string(unsigned(arrayType->length())) + ")");
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (auto const* structType = dynamic_cast<StructType const*>(&_type))
|
||||||
|
templ("zeroValue", allocateAndInitializeMemoryStructFunction(*structType) + "()");
|
||||||
|
else
|
||||||
|
solUnimplementedAssert(false, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return templ.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ class Type;
|
|||||||
class ArrayType;
|
class ArrayType;
|
||||||
class MappingType;
|
class MappingType;
|
||||||
class IntegerType;
|
class IntegerType;
|
||||||
|
class StructType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that can generate various useful Yul functions.
|
* Component that can generate various useful Yul functions.
|
||||||
@ -154,6 +155,7 @@ public:
|
|||||||
/// to store an array in memory given its length (internally encoded, not ABI encoded).
|
/// to store an array in memory given its length (internally encoded, not ABI encoded).
|
||||||
/// The function reverts for too large lengths.
|
/// The function reverts for too large lengths.
|
||||||
std::string arrayAllocationSizeFunction(ArrayType const& _type);
|
std::string arrayAllocationSizeFunction(ArrayType const& _type);
|
||||||
|
|
||||||
/// @returns the name of a function that converts a storage slot number
|
/// @returns the name of a function that converts a storage slot number
|
||||||
/// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer
|
/// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer
|
||||||
/// for the data position of an array which is stored in that slot / memory area / calldata area.
|
/// for the data position of an array which is stored in that slot / memory area / calldata area.
|
||||||
@ -250,10 +252,27 @@ public:
|
|||||||
/// Return value: pointer
|
/// Return value: pointer
|
||||||
std::string allocationFunction();
|
std::string allocationFunction();
|
||||||
|
|
||||||
/// @returns the name of a function that allocates a memory array.
|
/// @returns the name of a function that zeroes an array.
|
||||||
|
/// signature: (dataStart, dataSizeInBytes) ->
|
||||||
|
std::string zeroMemoryArrayFunction(ArrayType const& _type);
|
||||||
|
|
||||||
|
/// @returns the name of a function that zeroes a chunk of memory.
|
||||||
|
/// signature: (dataStart, dataSizeInBytes) ->
|
||||||
|
std::string zeroMemoryFunction(Type const& _type);
|
||||||
|
|
||||||
|
/// @returns the name of a function that zeroes an array
|
||||||
|
/// where the base does not have simple zero value in memory.
|
||||||
|
/// signature: (dataStart, dataSizeInBytes) ->
|
||||||
|
std::string zeroComplexMemoryArrayFunction(ArrayType const& _type);
|
||||||
|
|
||||||
|
/// @returns the name of a function that allocates and zeroes a memory array.
|
||||||
/// For dynamic arrays it adds space for length and stores it.
|
/// For dynamic arrays it adds space for length and stores it.
|
||||||
/// signature: (length) -> memPtr
|
/// signature: (length) -> memPtr
|
||||||
std::string allocateMemoryArrayFunction(ArrayType const& _type);
|
std::string allocateAndInitializeMemoryArrayFunction(ArrayType const& _type);
|
||||||
|
|
||||||
|
/// @returns the name of a function that allocates and zeroes a memory struct.
|
||||||
|
/// signature: (members) -> memPtr
|
||||||
|
std::string allocateAndInitializeMemoryStructFunction(StructType const& _type);
|
||||||
|
|
||||||
/// @returns the name of the function that converts a value of type @a _from
|
/// @returns the name of the function that converts a value of type @a _from
|
||||||
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
|
/// to a value of type @a _to. The resulting vale is guaranteed to be in range
|
||||||
@ -288,8 +307,9 @@ public:
|
|||||||
std::string negateNumberCheckedFunction(Type const& _type);
|
std::string negateNumberCheckedFunction(Type const& _type);
|
||||||
|
|
||||||
/// @returns the name of a function that returns the zero value for the
|
/// @returns the name of a function that returns the zero value for the
|
||||||
/// provided type
|
/// provided type.
|
||||||
std::string zeroValueFunction(Type const& _type);
|
/// @param _splitFunctionTypes if false, returns two zeroes
|
||||||
|
std::string zeroValueFunction(Type const& _type, bool _splitFunctionTypes = true);
|
||||||
|
|
||||||
/// @returns the name of a function that will set the given storage item to
|
/// @returns the name of a function that will set the given storage item to
|
||||||
/// zero
|
/// zero
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
#include <libsolutil/Whiskers.h>
|
#include <libsolutil/Whiskers.h>
|
||||||
#include <libsolutil/StringUtils.h>
|
#include <libsolutil/StringUtils.h>
|
||||||
@ -112,9 +113,10 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
|
|||||||
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts)
|
||||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||||
if (
|
if (
|
||||||
|
FunctionType const* functionType = TypeProvider::function(*function)->asCallableFunction(false);
|
||||||
!function->isConstructor() &&
|
!function->isConstructor() &&
|
||||||
function->parameters().size() == _in &&
|
TupleType(functionType->parameterTypes()).sizeOnStack() == _in &&
|
||||||
function->returnParameters().size() == _out
|
TupleType(functionType->returnParameterTypes()).sizeOnStack() == _out
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// 0 is reserved for uninitialized function pointers
|
// 0 is reserved for uninitialized function pointers
|
||||||
|
@ -133,6 +133,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
|||||||
return m_context.functionCollector().createFunction(functionName, [&]() {
|
return m_context.functionCollector().createFunction(functionName, [&]() {
|
||||||
Whiskers t(R"(
|
Whiskers t(R"(
|
||||||
function <functionName>(<params>) <returns> {
|
function <functionName>(<params>) <returns> {
|
||||||
|
<initReturnVariables>
|
||||||
<body>
|
<body>
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
@ -142,9 +143,14 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
|||||||
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||||
t("params", params);
|
t("params", params);
|
||||||
string retParams;
|
string retParams;
|
||||||
|
string retInit;
|
||||||
for (auto const& varDecl: _function.returnParameters())
|
for (auto const& varDecl: _function.returnParameters())
|
||||||
|
{
|
||||||
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList();
|
||||||
|
retInit += generateInitialAssignment(*varDecl);
|
||||||
|
}
|
||||||
t("returns", retParams.empty() ? "" : " -> " + retParams);
|
t("returns", retParams.empty() ? "" : " -> " + retParams);
|
||||||
|
t("initReturnVariables", retInit);
|
||||||
t("body", generate(_function.body()));
|
t("body", generate(_function.body()));
|
||||||
return t.render();
|
return t.render();
|
||||||
});
|
});
|
||||||
@ -226,6 +232,13 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
|
||||||
|
{
|
||||||
|
IRGeneratorForStatements generator(m_context, m_utils);
|
||||||
|
generator.initializeLocalVar(_varDecl);
|
||||||
|
return generator.code();
|
||||||
|
}
|
||||||
|
|
||||||
string IRGenerator::constructorCode(ContractDefinition const& _contract)
|
string IRGenerator::constructorCode(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
// Initialization of state variables in base-to-derived order.
|
// Initialization of state variables in base-to-derived order.
|
||||||
|
@ -61,6 +61,9 @@ private:
|
|||||||
/// Generates a getter for the given declaration and returns its name
|
/// Generates a getter for the given declaration and returns its name
|
||||||
std::string generateGetter(VariableDeclaration const& _varDecl);
|
std::string generateGetter(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
|
/// Generates code that assigns the initial value of the respective type.
|
||||||
|
std::string generateInitialAssignment(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
std::string constructorCode(ContractDefinition const& _contract);
|
std::string constructorCode(ContractDefinition const& _contract);
|
||||||
std::string deployCode(ContractDefinition const& _contract);
|
std::string deployCode(ContractDefinition const& _contract);
|
||||||
std::string callValueCheck();
|
std::string callValueCheck();
|
||||||
|
@ -154,6 +154,19 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl)
|
||||||
|
{
|
||||||
|
solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
|
||||||
|
|
||||||
|
auto const* type = _varDecl.type();
|
||||||
|
if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
|
||||||
|
if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
|
||||||
|
return;
|
||||||
|
|
||||||
|
IRVariable zero = zeroValue(*type);
|
||||||
|
assign(m_context.localVariable(_varDecl), zero);
|
||||||
|
}
|
||||||
|
|
||||||
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
|
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
|
||||||
{
|
{
|
||||||
if (Expression const* expression = _varDeclStatement.initialValue())
|
if (Expression const* expression = _varDeclStatement.initialValue())
|
||||||
@ -179,7 +192,10 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var
|
|||||||
else
|
else
|
||||||
for (auto const& decl: _varDeclStatement.declarations())
|
for (auto const& decl: _varDeclStatement.declarations())
|
||||||
if (decl)
|
if (decl)
|
||||||
|
{
|
||||||
declare(m_context.addLocalVariable(*decl));
|
declare(m_context.addLocalVariable(*decl));
|
||||||
|
initializeLocalVar(*decl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRGeneratorForStatements::visit(Conditional const& _conditional)
|
bool IRGeneratorForStatements::visit(Conditional const& _conditional)
|
||||||
@ -670,7 +686,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
IRVariable value = convert(*arguments[0], *TypeProvider::uint256());
|
IRVariable value = convert(*arguments[0], *TypeProvider::uint256());
|
||||||
define(_functionCall) <<
|
define(_functionCall) <<
|
||||||
m_utils.allocateMemoryArrayFunction(arrayType) <<
|
m_utils.allocateAndInitializeMemoryArrayFunction(arrayType) <<
|
||||||
"(" <<
|
"(" <<
|
||||||
value.commaSeparatedList() <<
|
value.commaSeparatedList() <<
|
||||||
")\n";
|
")\n";
|
||||||
@ -1439,6 +1455,12 @@ std::ostream& IRGeneratorForStatements::define(IRVariable const& _var)
|
|||||||
return m_code;
|
return m_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRGeneratorForStatements::declare(IRVariable const& _var)
|
||||||
|
{
|
||||||
|
if (_var.type().sizeOnStack() > 0)
|
||||||
|
m_code << "let " << _var.commaSeparatedList() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare)
|
void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare)
|
||||||
{
|
{
|
||||||
string output;
|
string output;
|
||||||
@ -1458,10 +1480,15 @@ void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable
|
|||||||
_rhs.commaSeparatedList() <<
|
_rhs.commaSeparatedList() <<
|
||||||
")\n";
|
")\n";
|
||||||
}
|
}
|
||||||
void IRGeneratorForStatements::declare(IRVariable const& _var)
|
|
||||||
|
IRVariable IRGeneratorForStatements::zeroValue(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
if (_var.type().sizeOnStack() > 0)
|
IRVariable irVar{
|
||||||
m_code << "let " << _var.commaSeparatedList() << "\n";
|
"zero_value_for_type_" + _type.identifier() + m_context.newYulVariable(),
|
||||||
|
_type
|
||||||
|
};
|
||||||
|
define(irVar) << m_utils.zeroValueFunction(_type, _splitFunctionTypes) << "()\n";
|
||||||
|
return irVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
|
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
|
||||||
|
@ -46,6 +46,8 @@ public:
|
|||||||
|
|
||||||
/// Generates code to initialize the given state variable.
|
/// Generates code to initialize the given state variable.
|
||||||
void initializeStateVar(VariableDeclaration const& _varDecl);
|
void initializeStateVar(VariableDeclaration const& _varDecl);
|
||||||
|
/// Generates code to initialize the given local variable.
|
||||||
|
void initializeLocalVar(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
|
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
|
||||||
bool visit(Conditional const& _conditional) override;
|
bool visit(Conditional const& _conditional) override;
|
||||||
@ -100,6 +102,11 @@ private:
|
|||||||
|
|
||||||
void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define);
|
void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define);
|
||||||
|
|
||||||
|
/// @returns an IRVariable with the zero
|
||||||
|
/// value of @a _type.
|
||||||
|
/// @param _splitFunctionTypes if false, returns two zeroes
|
||||||
|
IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true);
|
||||||
|
|
||||||
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
|
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
|
||||||
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
|
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ object \"C_6\" {
|
|||||||
|
|
||||||
function fun_f_5() {
|
function fun_f_5() {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -69,6 +70,7 @@ object \"C_6\" {
|
|||||||
|
|
||||||
function fun_f_5() {
|
function fun_f_5() {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function shift_right_224_unsigned(value) -> newValue {
|
function shift_right_224_unsigned(value) -> newValue {
|
||||||
|
@ -35,11 +35,18 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4_mpos {
|
function fun_f_9() -> vloc__4_mpos {
|
||||||
|
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||||
|
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||||
|
|
||||||
vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr()
|
vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr()
|
||||||
leave
|
leave
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||||
|
ret := 96
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
@ -131,6 +138,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4_mpos {
|
function fun_f_9() -> vloc__4_mpos {
|
||||||
|
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||||
|
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||||
|
|
||||||
vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr()
|
vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr()
|
||||||
leave
|
leave
|
||||||
|
|
||||||
@ -147,6 +157,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||||
|
ret := 96
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,18 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4 {
|
function fun_f_9() -> vloc__4 {
|
||||||
|
let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32()
|
||||||
|
vloc__4 := zero_value_for_type_t_bytes32_1
|
||||||
|
|
||||||
vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32()
|
vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32()
|
||||||
leave
|
leave
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_bytes32() -> ret {
|
||||||
|
ret := 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
@ -88,6 +95,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4 {
|
function fun_f_9() -> vloc__4 {
|
||||||
|
let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32()
|
||||||
|
vloc__4 := zero_value_for_type_t_bytes32_1
|
||||||
|
|
||||||
vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32()
|
vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32()
|
||||||
leave
|
leave
|
||||||
|
|
||||||
@ -100,6 +110,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_bytes32() -> ret {
|
||||||
|
ret := 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4 {
|
function fun_f_9() -> vloc__4 {
|
||||||
|
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||||
|
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||||
|
|
||||||
let expr_6 := 0x61626364
|
let expr_6 := 0x61626364
|
||||||
vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6)
|
vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6)
|
||||||
leave
|
leave
|
||||||
@ -40,6 +43,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_bytes4() -> ret {
|
||||||
|
ret := 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
@ -104,6 +111,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4 {
|
function fun_f_9() -> vloc__4 {
|
||||||
|
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||||
|
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||||
|
|
||||||
let expr_6 := 0x61626364
|
let expr_6 := 0x61626364
|
||||||
vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6)
|
vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6)
|
||||||
leave
|
leave
|
||||||
@ -124,6 +134,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_bytes4() -> ret {
|
||||||
|
ret := 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,18 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4_mpos {
|
function fun_f_9() -> vloc__4_mpos {
|
||||||
|
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||||
|
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||||
|
|
||||||
vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr()
|
vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr()
|
||||||
leave
|
leave
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||||
|
ret := 96
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
@ -139,6 +146,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4_mpos {
|
function fun_f_9() -> vloc__4_mpos {
|
||||||
|
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
|
||||||
|
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
|
||||||
|
|
||||||
vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr()
|
vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr()
|
||||||
leave
|
leave
|
||||||
|
|
||||||
@ -155,6 +165,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_string_memory_ptr() -> ret {
|
||||||
|
ret := 96
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4 {
|
function fun_f_9() -> vloc__4 {
|
||||||
|
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||||
|
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||||
|
|
||||||
let expr_6 := 0xaabbccdd
|
let expr_6 := 0xaabbccdd
|
||||||
vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6)
|
vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6)
|
||||||
leave
|
leave
|
||||||
@ -40,6 +43,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_bytes4() -> ret {
|
||||||
|
ret := 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
object \"C_10_deployed\" {
|
object \"C_10_deployed\" {
|
||||||
code {
|
code {
|
||||||
@ -104,6 +111,9 @@ object \"C_10\" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fun_f_9() -> vloc__4 {
|
function fun_f_9() -> vloc__4 {
|
||||||
|
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
|
||||||
|
vloc__4 := zero_value_for_type_t_bytes4_1
|
||||||
|
|
||||||
let expr_6 := 0xaabbccdd
|
let expr_6 := 0xaabbccdd
|
||||||
vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6)
|
vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6)
|
||||||
leave
|
leave
|
||||||
@ -124,6 +134,10 @@ object \"C_10\" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zero_value_for_split_t_bytes4() -> ret {
|
||||||
|
ret := 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
contract C {
|
||||||
|
function f(uint n, uint m) public {
|
||||||
|
function() internal returns (uint)[] memory arr = new function() internal returns (uint)[](n);
|
||||||
|
arr[m]();
|
||||||
|
}
|
||||||
|
function f2(uint n, uint m, uint a, uint b) public {
|
||||||
|
function() internal returns (uint)[][] memory arr = new function() internal returns (uint)[][](n);
|
||||||
|
for (uint i = 0; i < n; ++i)
|
||||||
|
arr[i] = new function() internal returns (uint)[](m);
|
||||||
|
arr[a][b]();
|
||||||
|
}
|
||||||
|
function g(uint n, uint m) public {
|
||||||
|
function() external returns (uint)[] memory arr = new function() external returns (uint)[](n);
|
||||||
|
arr[m]();
|
||||||
|
}
|
||||||
|
function g2(uint n, uint m, uint a, uint b) public {
|
||||||
|
function() external returns (uint)[][] memory arr = new function() external returns (uint)[][](n);
|
||||||
|
for (uint i = 0; i < n; ++i)
|
||||||
|
arr[i] = new function() external returns (uint)[](m);
|
||||||
|
arr[a][b]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint256,uint256): 1823621, 12323 -> FAILURE
|
||||||
|
// f2(uint256,uint256,uint256,uint256): 18723921, 1823621, 123, 12323 -> FAILURE
|
||||||
|
// g(uint256,uint256): 1823621, 12323 -> FAILURE
|
||||||
|
// g2(uint256,uint256,uint256,uint256): 18723921, 1823621, 123, 12323 -> FAILURE
|
@ -0,0 +1,24 @@
|
|||||||
|
contract C {
|
||||||
|
uint test1;
|
||||||
|
uint test2;
|
||||||
|
uint test3;
|
||||||
|
uint test4;
|
||||||
|
uint test5;
|
||||||
|
uint test6;
|
||||||
|
uint test7;
|
||||||
|
mapping (string => uint) map;
|
||||||
|
function set(string memory s, uint n, uint m, uint a, uint b) public returns (uint) {
|
||||||
|
map[s] = 0;
|
||||||
|
uint[][] memory x = new uint[][](n);
|
||||||
|
for (uint i = 0; i < n; ++i)
|
||||||
|
x[i] = new uint[](m);
|
||||||
|
return x[a][b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 0, 0, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 3, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 3, 3, 32, "01234567890123456789012345678901" -> FAILURE
|
||||||
|
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 5, 32, "01234567890123456789012345678901" -> FAILURE
|
@ -0,0 +1,22 @@
|
|||||||
|
contract C {
|
||||||
|
uint test1;
|
||||||
|
uint test2;
|
||||||
|
uint test3;
|
||||||
|
uint test4;
|
||||||
|
uint test5;
|
||||||
|
uint test6;
|
||||||
|
uint test7;
|
||||||
|
mapping (string => uint) map;
|
||||||
|
function set(string memory s, uint n, uint m) public returns (uint) {
|
||||||
|
map[s] = 0;
|
||||||
|
uint[4][] memory x = new uint[4][](n);
|
||||||
|
return x[m][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// set(string,uint256,uint256): 0x60, 2, 0, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256): 0x60, 2, 1, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256): 0x60, 2, 2, 32, "01234567890123456789012345678901" -> FAILURE
|
||||||
|
// set(string,uint256,uint256): 0x60, 200, 199, 32, "01234567890123456789012345678901" -> 0
|
@ -0,0 +1,17 @@
|
|||||||
|
contract C {
|
||||||
|
uint test1;
|
||||||
|
uint test2;
|
||||||
|
uint test3;
|
||||||
|
uint test4;
|
||||||
|
uint test5;
|
||||||
|
uint test6;
|
||||||
|
uint test7;
|
||||||
|
mapping (string => uint) map;
|
||||||
|
function set(string memory s) public returns (uint[3] memory x, uint[2] memory y, uint[] memory z, uint t) {
|
||||||
|
map[s] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// set(string): 0x20, 32, "01234567890123456789012345678901" -> 0, 0, 0, 0, 0, 0xe0, 0, 0
|
@ -0,0 +1,19 @@
|
|||||||
|
contract C {
|
||||||
|
uint test1;
|
||||||
|
uint test2;
|
||||||
|
uint test3;
|
||||||
|
uint test4;
|
||||||
|
uint test5;
|
||||||
|
uint test6;
|
||||||
|
uint test7;
|
||||||
|
mapping (string => uint) map;
|
||||||
|
function set(string memory s) public returns (uint) {
|
||||||
|
map[s] = 0;
|
||||||
|
uint[3] memory x;
|
||||||
|
return x[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// set(string): 0x20, 32, "01234567890123456789012345678901" -> 0
|
@ -0,0 +1,22 @@
|
|||||||
|
contract C {
|
||||||
|
uint test1;
|
||||||
|
uint test2;
|
||||||
|
uint test3;
|
||||||
|
uint test4;
|
||||||
|
uint test5;
|
||||||
|
uint test6;
|
||||||
|
uint test7;
|
||||||
|
mapping (string => uint) map;
|
||||||
|
function set(string memory s, uint n, uint a) public returns (uint) {
|
||||||
|
map[s] = 0;
|
||||||
|
uint[] memory x = new uint[](n);
|
||||||
|
return x[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// set(string,uint256,uint256): 0x60, 5, 0, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256): 0x60, 5, 1, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256): 0x60, 5, 4, 32, "01234567890123456789012345678901" -> 0
|
||||||
|
// set(string,uint256,uint256): 0x60, 5, 5, 32, "01234567890123456789012345678901" -> FAILURE
|
25
test/libsolidity/semanticTests/viaYul/function_pointers.sol
Normal file
25
test/libsolidity/semanticTests/viaYul/function_pointers.sol
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public {
|
||||||
|
function() internal returns (uint) _f;
|
||||||
|
_f();
|
||||||
|
}
|
||||||
|
function g() public {
|
||||||
|
function() external returns (uint) _g;
|
||||||
|
_g();
|
||||||
|
}
|
||||||
|
function h1() internal returns (function() internal returns (uint) _h) {}
|
||||||
|
function h2() public {
|
||||||
|
h1()();
|
||||||
|
}
|
||||||
|
function k1() internal returns (function() external returns (uint) _k) {}
|
||||||
|
function k2() public {
|
||||||
|
k1()();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> FAILURE
|
||||||
|
// g() -> FAILURE
|
||||||
|
// h2() -> FAILURE
|
||||||
|
// k2() -> FAILURE
|
@ -0,0 +1,16 @@
|
|||||||
|
contract C {
|
||||||
|
uint[] arr1;
|
||||||
|
uint[][] arr2;
|
||||||
|
function f() internal returns (uint[] storage ptr1, uint[][] storage ptr2) {
|
||||||
|
ptr1 = arr1;
|
||||||
|
ptr2 = arr2;
|
||||||
|
}
|
||||||
|
function g() public returns (uint, uint) {
|
||||||
|
return (arr1.length, arr2.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// g() -> 0, 0
|
Loading…
Reference in New Issue
Block a user