3

Say we have the following structure:

struct MyStruct {
  uint256 x;
  uint256 y;
}

and that it is passed as an argument to some function. Inside that function, we have assembly block from where we try to access x and y:

function myFunc(MyStruct memory data) internal view returns (bool) {
  // (...)
  assembly {
    let args := mload(0x40);
    mstore(args, data.x);
    mstore(args, data.y);
    // (...)
  }
  // (...)

}

And the compilation fails with:

Error: CompileError: ParsedContract.sol:404:28: ParserError: Expected ')' but got '.'
            mstore(args, data.x)

Is it not allowed? Is there any workaround? I want to avoid creating temporary uint256 fields to avoid additional gas expenses.

2
  • 2
    Yes, it should be possible mload(data) should be the first field, and mload(add(data, 0x20)) the second, etc.
    – Ismael
    Nov 5, 2019 at 22:36
  • @Ismael I had no idea mload allows for this. Is it the same for a nested structure? struct MyStruct {point x, point y} and struct point { uint256 x, uint256 y} ? I am trying to do it the same way with mload(data), mload(add(data, 0x20)), then 0x40, 0x60 but with no success.
    – omnomnom
    Nov 6, 2019 at 8:36

1 Answer 1

4

As @Ismael said, it is possible by using mload(data), here is an example you can test in remix:

Simple struct

pragma solidity ^0.5.0;

contract Test {

    struct MyStruct {
        uint256 x;
        uint256 y;
    }

    function testFunc() public pure returns (uint, uint) {
        MyStruct memory data1 = MyStruct(5,7);
        return myFunc(data1);
    }

    function myFunc(MyStruct memory data) internal pure returns (uint256 _z, uint _w) {
        assembly {
            _z := mload(data)
            _w := mload(add(data,0x20))
        }
    }
}

Nested struct

Answering to your comment, it is possible for a nested struct too. Now you need to load the position where the struct starts.

pragma solidity ^0.5.0;

contract Test {

    struct MyStruct {
        Point x;
        Point y;
    } 

    struct Point {
        uint256 x;
        uint256 y;
    }

    function testFunc() public pure returns (uint256, uint256, uint256, uint256) {
        MyStruct memory data1 = MyStruct(Point(3,5), Point(7,9));
        return myFunc(data1);
    }

    function myFunc(MyStruct memory data) internal pure returns (uint256 _x, uint256 _y, uint256 _u, uint256 _v) {
        assembly {

            let first_point := mload(data)
            _x := mload(first_point)
            _y := mload(add(first_point,0x20))

            let second_point := mload(add(data,0x20))
            _u := mload(second_point)
            _v := mload(add(second_point,0x20))

            /** Same as above but summarized
            _x := mload(mload(data))
            _y := mload(add(mload(data),0x20))
            _u := mload(add(mload(data),0x40))
            _v := mload(add(mload(data),0x60))
            */
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.