From 90b66a736250a1af0a897f0c5c67cecbdd4b74f6 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 10 Jun 2020 17:27:59 +0200 Subject: [PATCH] Fix struct member access for memory and implement for calldata. --- libsolidity/ast/Types.cpp | 15 +++++++ libsolidity/ast/Types.h | 2 + .../codegen/ir/IRGeneratorForStatements.cpp | 22 ++++++++++- .../viaYul/struct_member_access.sol | 39 +++++++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/struct_member_access.sol diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 8114be800..dfddaef8e 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2457,6 +2457,21 @@ set StructType::membersMissingInMemory() const return missing; } +vector> StructType::makeStackItems() const +{ + switch (m_location) + { + case DataLocation::CallData: + return {std::make_tuple("offset", TypeProvider::uint256())}; + case DataLocation::Memory: + return {std::make_tuple("mpos", TypeProvider::uint256())}; + case DataLocation::Storage: + return {std::make_tuple("slot", TypeProvider::uint256())}; + } + solAssert(false, ""); +} + + TypePointer EnumType::encodingType() const { return TypeProvider::uint(8 * storageBytes()); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 609f2e9ed..4ae780b63 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -980,6 +980,8 @@ public: void clearCache() const override; +protected: + std::vector> makeStackItems() const override; private: StructDefinition const& m_struct; // Caches for interfaceType(bool) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index a62251ab1..53e23d849 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) pair const& offsets = structType.storageOffsetsOfMember(member); string slot = m_context.newYulVariable(); m_code << "let " << slot << " := " << - ("add(" + expression.name() + ", " + offsets.first.str() + ")\n"); + ("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n"); setLValue(_memberAccess, IRLValue{ type(_memberAccess), IRLValue::Storage{slot, offsets.second} @@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } case DataLocation::CallData: { - solUnimplementedAssert(false, ""); + string baseRef = expression.part("offset").name(); + string offset = m_context.newYulVariable(); + m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n"; + if (_memberAccess.annotation().type->isDynamicallyEncoded()) + define(_memberAccess) << + m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) << + "(" << + baseRef << + ", " << + offset << + ")" << + std::endl; + else + define(_memberAccess) << + m_utils.readFromCalldata(*_memberAccess.annotation().type) << + "(" << + offset << + ")" << + std::endl; break; } default: diff --git a/test/libsolidity/semanticTests/viaYul/struct_member_access.sol b/test/libsolidity/semanticTests/viaYul/struct_member_access.sol new file mode 100644 index 000000000..60733d414 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/struct_member_access.sol @@ -0,0 +1,39 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint a; + uint[] b; + uint c; + } + + S s; + constructor() public { + s.a = 42; + s.b.push(1); + s.b.push(2); + s.b.push(3); + s.c = 21; + } + + function f(S memory m) public pure returns (uint, uint[] memory, uint) { + return (m.a, m.b, m.c); + } + function g(S calldata c) external pure returns (uint, uint, uint, uint, uint, uint) { + return (c.a, c.b.length, c.c, c.b[0], c.b[1], c.b[2]); + } + function g2(S calldata c1, S calldata c2) external pure returns (uint, uint, uint, uint, uint, uint) { + return (c1.a, c1.c, c2.a, c2.b.length, c2.c, c2.b[0]); + } + function h() external view returns (uint, uint, uint, uint, uint, uint) { + return (s.a, s.b.length, s.c, s.b[0], s.b[1], s.b[2]); + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// f((uint256,uint256[],uint256)): 0x20, 42, 0x60, 21, 3, 1, 2, 3 -> 42, 0x60, 21, 3, 1, 2, 3 +// g((uint256,uint256[],uint256)): 0x20, 42, 0x60, 21, 3, 1, 2, 3 -> 42, 3, 21, 1, 2, 3 +// g2((uint256,uint256[],uint256),(uint256,uint256[],uint256)): 0x40, 0x0120, 42, 0x60, 21, 2, 1, 2, 3, 7, 0x80, 9, 0, 1, 17 -> 42, 21, 7, 1, 9, 17 +// h() -> 42, 3, 21, 1, 2, 3