diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 285f05298..6b0fb9ec1 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1147,6 +1147,45 @@ string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type) }); } +string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) +{ + solAssert(_type.location() == DataLocation::Storage, ""); + + string functionName = "clear_struct_storage_" + _type.identifier(); + + return m_functionCollector.createFunction(functionName, [&] { + MemberList::MemberMap structMembers = _type.nativeMembers(nullptr); + vector> memberSetValues; + + for (auto const& member: structMembers) + { + auto const& [memberSlotDiff, memberStorageOffset] = _type.storageOffsetsOfMember(member.name); + + memberSetValues.emplace_back().emplace("clearMember", Whiskers(R"( + (add(slot, ), ) + )") + ("setZero", storageSetToZeroFunction(*member.type)) + ("memberSlotDiff", memberSlotDiff.str()) + ("memberStorageOffset", to_string(memberStorageOffset)) + .render() + ); + } + + return Whiskers(R"( + function (slot) { + <#member> + + + } + )") + ("functionName", functionName) + ("allocStruct", allocateMemoryStructFunction(_type)) + ("storageSize", _type.storageSize().str()) + ("member", memberSetValues) + .render(); + }); +} + string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type) { string functionName = "array_convert_length_to_size_" + _type.identifier(); @@ -2741,12 +2780,23 @@ string YulUtilFunctions::storageSetToZeroFunction(Type const& _type) else if (_type.category() == Type::Category::Array) return Whiskers(R"( function (slot, offset) { + if iszero(eq(offset, 0)) { panic() } (slot) } )") ("functionName", functionName) ("clearArray", clearStorageArrayFunction(dynamic_cast(_type))) .render(); + else if (_type.category() == Type::Category::Struct) + return Whiskers(R"( + function (slot, offset) { + if iszero(eq(offset, 0)) { panic() } + (slot) + } + )") + ("functionName", functionName) + ("clearStruct", clearStorageStructFunction(dynamic_cast(_type))) + .render(); else solUnimplemented("setToZero for type " + _type.identifier() + " not yet implemented!"); }); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 351c857d4..377e5da52 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -427,6 +427,10 @@ private: /// signature: (slot, offset) std::string partialClearStorageSlotFunction(); + /// @returns the name of a function that will clear the given storage struct + /// signature: (slot) -> + std::string clearStorageStructFunction(StructType const& _type); + langutil::EVMVersion m_evmVersion; RevertStrings m_revertStrings; MultiUseYulFunctionCollector& m_functionCollector;