edwardw
edwardw

Reputation: 13942

Rust: use of partially moved values

In Rust 0.8:

struct TwoStr {
  one: ~str,
  two: ~str,
}

#[test]
fn test_contents() {
  let strs = TwoStr {
    one: ~"pillar",
    two: ~"post",
  };

  assert_eq!(strs.one, ~"pillar");
  assert_eq!(strs.two, ~"post");
}

The code won't even compile. The rust test thinks there's an error in the second assert_eq:

error: use of partially moved value: strs

It is somewhat counter-intuitive. I mean, whatever effects the first assert_eq may have, it should be well out of the scope when the execution reaches the second assert_eq. Unless of course, it does some spawn behind the scene. Does it?

If not, why this mysterious error? Hopefully there's no fundamental flaws in my understanding of Rust pointers.

Upvotes: 3

Views: 1377

Answers (2)

Lily Ballard
Lily Ballard

Reputation: 185671

In Rust 0.8, assert_eq! is defined as

macro_rules! assert_eq (
    ($given:expr , $expected:expr) => (
        {
            let given_val = $given;
            let expected_val = $expected;
            // check both directions of equality....
            if !((given_val == expected_val) && (expected_val == given_val)) {
                fail!(\"assertion failed: `(left == right) && (right == \
                left)` (left: `%?`, right: `%?`)\", given_val, expected_val);
            }
        }
    )
)

Note here that it moves both arguments into local let-bindings given_val and expected_val. This is what is causing your error.

In current master, this has been fixed. assert_eq! now takes references to the arguments:

macro_rules! assert_eq (
    ($given:expr , $expected:expr) => (
        {
            let given_val = &($given);
            let expected_val = &($expected);
            // check both directions of equality....
            if !((*given_val == *expected_val) &&
                 (*expected_val == *given_val)) {
                fail!("assertion failed: `(left == right) && (right == left)` \
                       (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
            }
        }
    )
)

This means that it no longer moves its arguments, which fixes your error.

If you need to stick with rust 0.8, you can change this to using assert!() instead and do the comparison directly, which will avoid the move. But my recommendation is to upgrade to latest master.

Upvotes: 6

telotortium
telotortium

Reputation: 3541

It works on Git master. It must be a bug that was fixed after 0.8 was cut. In general, the released versions are not constrained to be particularly stable before release - they're essentially just snapshots.

The definition of the assert_eq! macro, in libsyntax, takes references to the arguments, so the arguments should not be moved and you can use them after you call the macro.

If you do find another bug, try to compile master if you can, or just make a new issue.

Upvotes: 3

Related Questions