diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/locals_safety/enum_non_drop_assignment.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/locals_safety/enum_non_drop_assignment.exp new file mode 100644 index 0000000000000..4f74b554b982e --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/locals_safety/enum_non_drop_assignment.exp @@ -0,0 +1,19 @@ +processed 2 tasks + +task 0 'publish'. lines 1-22: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::Enums'. Got VMError: { + major_status: WRITEREF_WITHOUT_DROP_ABILITY, + sub_status: None, + location: 0x1::Enums, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 10)], +} + +task 1 'publish'. lines 24-47: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::Enums'. Got VMError: { + major_status: WRITEREF_WITHOUT_DROP_ABILITY, + sub_status: None, + location: 0x1::Enums, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 10)], +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/locals_safety/enum_non_drop_assignment.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/locals_safety/enum_non_drop_assignment.mvir new file mode 100644 index 0000000000000..3897bb553470c --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/locals_safety/enum_non_drop_assignment.mvir @@ -0,0 +1,47 @@ +//# publish +module 0x1.Enums { + enum PolyEnumWithTwoVariants { + One { }, + Two { x: T } + } + + public g(t: T, x2: T): T { + let e: Self.PolyEnumWithTwoVariants; + let x: &mut T; + label b0: + e = PolyEnumWithTwoVariants.Two { x: move(t) }; + variant_switch PolyEnumWithTwoVariants (&e) { + One : b1, + Two : b1, + }; + label b1: + &mut PolyEnumWithTwoVariants.Two { x: x } = &mut e; + *move(x) = move(x2); + abort 0; + } +} + +//# publish +module 0x1.Enums { + struct X { b: bool } + + enum MonoEnumWithTwoVariants { + One { }, + Two { x: Self.X } + } + + public g(t: Self.X, x2: Self.X): Self.X { + let e: Self.MonoEnumWithTwoVariants; + let x: &mut Self.X; + label b0: + e = MonoEnumWithTwoVariants.Two { x: move(t) }; + variant_switch MonoEnumWithTwoVariants (&e) { + One : b1, + Two : b1, + }; + label b1: + &mut MonoEnumWithTwoVariants.Two { x: x } = &mut e; + *move(x) = move(x2); + abort 0; + } +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/double_enum_unpack.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/double_enum_unpack.exp new file mode 100644 index 0000000000000..6cd67db3f6472 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/double_enum_unpack.exp @@ -0,0 +1 @@ +processed 1 task diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/double_enum_unpack.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/double_enum_unpack.mvir new file mode 100644 index 0000000000000..94a43fd91aa1e --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/double_enum_unpack.mvir @@ -0,0 +1,30 @@ +//# publish +module 0x1.o { + enum X has drop { + One { x: u64, y: u64 }, + Two { x: u64, y: u64}, + } + + a(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.One { x: x, y: y} = copy(e); + &mut X.Two { x: x, y: y} = move(e); + return; + } + + b(e: &mut Self.X) { + let x: &mut u64; + let x2: &mut u64; + let y: &mut u64; + label b0: + &mut X.One { x: x, y: y} = copy(e); + *move(y) = 0; + &mut X.One { x: x2, y: y} = move(e); + // x and x2 are aliases of each other + *move(x) = 0; + *move(x2) = 0; + return; + } +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/enum_variant_factor.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/enum_variant_factor.exp new file mode 100644 index 0000000000000..6f29d65d31bf9 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/enum_variant_factor.exp @@ -0,0 +1,55 @@ +processed 7 tasks + +task 0 'publish'. lines 1-17: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: FIELD_EXISTS_MUTABLE_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 5)], +} + +task 1 'publish'. lines 19-36: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: FIELD_EXISTS_MUTABLE_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 3)], +} + +task 2 'publish'. lines 38-54: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: FIELD_EXISTS_MUTABLE_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 3)], +} + +task 3 'publish'. lines 56-74: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: FIELD_EXISTS_MUTABLE_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 5)], +} + +task 5 'publish'. lines 96-118: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::invalid'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::invalid, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 21)], +} + +task 6 'publish'. lines 120-142: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::invalid'. Got VMError: { + major_status: READREF_EXISTS_MUTABLE_BORROW_ERROR, + sub_status: None, + location: 0x1::invalid, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 17)], +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/enum_variant_factor.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/enum_variant_factor.mvir new file mode 100644 index 0000000000000..4835883b66abd --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/enum_variant_factor.mvir @@ -0,0 +1,142 @@ +//# publish +module 0x1.o { + enum X has drop { + Empty { }, + One { x: u64, y: u64 }, + } + + f(e: &mut Self.X) { + let a1: &mut Self.X; + let a2: &mut Self.X; + label b0: + a1 = copy(e); + a2 = copy(e); + &mut X.Empty{} = move(a2); + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64, y: u64 }, + Two { x: u64, y: u64}, + } + + c(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let a1: &mut Self.X; + label b0: + a1 = copy(e); + &mut X.One { x: x, y: y} = copy(e); + return; + } + +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64, y: u64 }, + Two { x: u64, y: u64}, + } + + c(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let a1: &mut Self.X; + label b0: + a1 = copy(e); + &mut X.One { x: x, y: y} = move(e); + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64, y: u64 }, + Two { x: u64, y: u64}, + } + + c(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let a1: &mut Self.X; + let a2: &mut Self.X; + label b0: + a1 = copy(e); + a2 = copy(e); + &mut X.One { x: x, y: y} = move(a2); + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64, y: u64 }, + Two { x: u64, y: u64}, + } + + c(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let a1: &mut Self.X; + let a2: &mut Self.X; + label b0: + a1 = copy(e); + a2 = copy(e); + &mut X.One { x: x, y: y} = move(a1); + return; + } +} + +//# publish +module 0x1.invalid { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = move(y); + &mut X.Two { x: x, y: y} = copy(e); + // Error: Invalid to write to `y` since it's factored to `counter` which is still a live mutable reference + *copy(y) = *copy(counter) - 1; + counter = move(y); + return; + } +} + +//# publish +module 0x1.invalid { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = move(y); + &mut X.Two { x: x, y: y} = copy(e); + // Error: Invalid to read `y` since it's factored to `counter` which is still a live mutable reference + *copy(y) = *copy(y) - 1; + counter = move(y); + return; + } +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack.exp new file mode 100644 index 0000000000000..ae5cc2f4bf16f --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack.exp @@ -0,0 +1,64 @@ +processed 7 tasks + +task 0 'publish'. lines 1-20: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 13)], +} + +task 1 'publish'. lines 22-47: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: CALL_BORROWED_MUTABLE_REFERENCE_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 11)], +} + +task 2 'publish'. lines 49-68: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 10)], +} + +task 3 'publish'. lines 70-95: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: CALL_BORROWED_MUTABLE_REFERENCE_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 8)], +} + +task 4 'publish'. lines 97-114: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 10)], +} + +task 5 'publish'. lines 116-134: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 10)], +} + +task 6 'publish'. lines 136-160: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: CALL_BORROWED_MUTABLE_REFERENCE_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 8)], +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack.mvir new file mode 100644 index 0000000000000..4f18922ca7b27 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack.mvir @@ -0,0 +1,160 @@ +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + i(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + &mut X.One { x: x } = copy(e); + *move(e) = X.One { x: 0 }; // ERROR + *move(y) = 3; + *move(x) = 2; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + i(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + &mut X.One { x: x } = copy(e); + Self.overwrite(move(e));// ERROR + *move(y) = 3; + *move(x) = 2; + return; + } + + overwrite(e: &mut Self.X) { + label b0: + *move(e) = X.One { x: 0 }; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + j(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(e) = X.One { x: 0 }; // ERROR + &mut X.One { x: x } = move(e); + *move(y) = 3; + *move(x) = 2; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + j(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + Self.overwrite(copy(e)); + &mut X.One { x: x } = move(e); + *move(y) = 3; + *move(x) = 2; + return; + } + + overwrite(e: &mut Self.X) { + label b0: + *move(e) = X.One { x: 0 }; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + k(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(e) = X.One { x: 0 }; // ERROR since z lives across the assignment + *move(y) = 3; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + k(e: &mut Self.X) { + let x: &u64; + let y: &u64; + let t: u64; + label b0: + &X.Two { x: x, y: y} = freeze(copy(e)); + _ = move(x); + *move(e) = X.One { x: 0 }; // ERROR since z lives across the assignment + t = *move(y); + abort move(t); + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + k(e: &mut Self.X) { + let x: &u64; + let y: &u64; + let t: u64; + label b0: + &X.Two { x: x, y: y} = freeze(copy(e)); + _ = move(x); + Self.overwrite(move(e)); + t = *move(y); + abort move(t); + } + + overwrite(e: &mut Self.X) { + label b0: + *move(e) = X.One { x: 0 }; + return; + } +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack_loop.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack_loop.exp new file mode 100644 index 0000000000000..53383d6af92c3 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack_loop.exp @@ -0,0 +1,46 @@ +processed 5 tasks + +task 0 'publish'. lines 1-37: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 30)], +} + +task 1 'publish'. lines 39-76: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 32)], +} + +task 2 'publish'. lines 78-114: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 32)], +} + +task 3 'publish'. lines 116-155: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: WRITEREF_EXISTS_BORROW_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 54)], +} + +task 4 'publish'. lines 157-197: +Error: Unable to publish module '0000000000000000000000000000000000000000000000000000000000000001::o'. Got VMError: { + major_status: COPYLOC_UNAVAILABLE_ERROR, + sub_status: None, + location: 0x1::o, + indices: [(FunctionDefinition, 0)], + offsets: [(FunctionDefinitionIndex(0), 13)], +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack_loop.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack_loop.mvir new file mode 100644 index 0000000000000..2886ea875ae51 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/invalid_enum_ref_unpack_loop.mvir @@ -0,0 +1,197 @@ +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // Invalid since `y`'s referene stays live between loop iterations, but we then write to `y`'s root in the loop. + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + label looper: + jump_if (*copy(y) == 0) c1; + jump_if (*copy(y) == 2) c2; + jump_if (*copy(y) == 1) c3; + jump c4; + label c1: + return; + label c2: + *copy(e) = X.One { x: 2 }; + jump looper; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + jump looper; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + jump looper; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // Same as above, but we alias `y` to `counter` between loop iterations. + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = move(y); + label looper: + jump_if (*copy(counter) == 0) c1; + jump_if (*copy(counter) == 2) c2; + jump_if (*copy(counter) == 1) c3; + jump c4; + label c1: + return; + label c2: + *copy(e) = X.One { x: 2 }; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + counter = move(y); + jump looper; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // Same as above, but we alias `y` to `counter` with no loops + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = move(y); + label looper: + jump_if (*copy(counter) == 0) c1; + jump_if (*copy(counter) == 2) c2; + jump_if (*copy(counter) == 1) c3; + jump c4; + label c1: + return; + label c2: + *copy(e) = X.One { x: 2 }; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + counter = move(y); + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // Same as above, but we alias `y` to an immutable ref `counter` between loop iterations. + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = freeze(move(y)); + label looper: + jump_if (*copy(counter) == 0) c1; + jump_if (*copy(counter) == 2) c2; + jump_if (*copy(counter) == 1) c3; + jump c4; + label c1: + return; + label c2: + *copy(e) = X.One { x: 2 }; + jump looper; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + jump looper; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + counter = freeze(move(y)); + jump looper; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // Invalid since `counter` is invalidated, but not written again before the loop starts back up. + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = freeze(move(y)); + label looper: + jump_if (*copy(counter) == 0) c1; + jump_if (*copy(counter) == 2) c2; + jump_if (*copy(counter) == 1) c3; + jump c4; + label c1: + return; + label c2: + _ = move(counter); + *copy(e) = X.One { x: 2 }; + jump looper; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + jump looper; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + counter = freeze(move(y)); + jump looper; + return; + } +} diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_ref_unpack.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_ref_unpack.exp new file mode 100644 index 0000000000000..6cd67db3f6472 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_ref_unpack.exp @@ -0,0 +1 @@ +processed 1 task diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_ref_unpack.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_ref_unpack.mvir new file mode 100644 index 0000000000000..21c14caea1c66 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_ref_unpack.mvir @@ -0,0 +1,64 @@ +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + &mut X.One { x: x } = move(e); + *move(y) = 3; + *move(x) = 2; + return; + } + + f(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.One { x: x } = copy(e); + *move(x) = 1; + &mut X.Two { x: x, y: y} = move(e); + *move(x) = 2; + return; + } + + g(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + &mut X.One { x: x } = move(e); + *move(x) = 2; + return; + } + + k(e: &mut Self.X) { + let x: &u64; + let y: &u64; + label b0: + &X.Two { x: x, y: y} = freeze(copy(e)); + _ = move(x); + _ = move(y); + *move(e) = X.One { x: 0 }; + return; + } + + k1(e: &mut Self.X) { + let x: &u64; + let y: &u64; + let t: u64; + label b0: + &X.Two { x: x, y: y} = freeze(copy(e)); + _ = move(x); + t = *move(y); + *move(e) = X.One { x: 0 }; // Fine since z's value is copied out first + abort move(t); + } + } diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_unpack_loop.exp b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_unpack_loop.exp new file mode 100644 index 0000000000000..fc5a4436b29d4 --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_unpack_loop.exp @@ -0,0 +1 @@ +processed 3 tasks diff --git a/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_unpack_loop.mvir b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_unpack_loop.mvir new file mode 100644 index 0000000000000..09df5def8354f --- /dev/null +++ b/external-crates/move/crates/bytecode-verifier-transactional-tests/tests/reference_safety/valid_enum_unpack_loop.mvir @@ -0,0 +1,111 @@ +//# publish +module 0x1.woo { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // This loop is fine since `y`'s reference does escape the loop, but then is killed off right before the write. + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: &u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = freeze(move(y)); + label looper: + jump_if (*copy(counter) == 0) c1; + jump_if (*copy(counter) == 2) c2; + jump_if (*copy(counter) == 1) c3; + jump c4; + label c1: + return; + label c2: + _ = move(counter); + *copy(e) = X.One { x: 2 }; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + counter = freeze(move(y)); + jump looper; + return; + } +} + +//# publish +module 0x1.o { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // This loop is fine since `y`'s reference does not escape the loop + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + let counter: u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + counter = *move(y); + label looper: + jump_if (copy(counter) == 0) c1; + jump_if (copy(counter) == 2) c2; + jump_if (copy(counter) == 1) c3; + jump c4; + label c1: + return; + label c2: + *copy(e) = X.One { x: 2 }; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + counter = *move(y); + jump looper; + return; + } +} + +//# publish +module 0x1.k { + enum X has drop { + One { x: u64 }, + Two { x: u64, y: u64}, + } + + // Valid since we don't write to `e` in the loop. + h(e: &mut Self.X) { + let x: &mut u64; + let y: &mut u64; + label b0: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = 3; + label looper: + jump_if (*copy(y) == 0) c1; + jump_if (*copy(y) == 1) c3; + jump c4; + label c1: + return; + label c3: + &mut X.One { x: x } = copy(e); + *move(x) = 10; + label c4: + &mut X.Two { x: x, y: y} = copy(e); + *move(x) = 1; + *copy(y) = *copy(y) - 1; + jump looper; + return; + } +} diff --git a/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_jump_same_label.exp b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_jump_same_label.exp new file mode 100644 index 0000000000000..e4d56a66fe3f8 --- /dev/null +++ b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_jump_same_label.exp @@ -0,0 +1,79 @@ +processed 5 tasks + +task 0 'print-bytecode'. lines 1-43: +// Move bytecode v7 +module 1.Enums { + + +enum EnumWithThreeVariants { + One { }, + Two { x: Ty0 }, + Three { } +} + +public call_success(Arg0: Ty0): Ty0 { +B0: + 0: MoveLoc[0](Arg0: Ty0) + 1: PackVariantGeneric(VariantInstantiationHandleIndex(0)) + 2: StLoc[1](loc0: EnumWithThreeVariants) + 3: MoveLoc[1](loc0: EnumWithThreeVariants) + 4: Call f(EnumWithThreeVariants): Ty0 + 5: Ret + +} +public call_fail_1(): Ty0 { +L0: loc0: EnumWithThreeVariants +B0: + 0: PackVariantGeneric(VariantInstantiationHandleIndex(1)) + 1: StLoc[0](loc0: EnumWithThreeVariants) + 2: MoveLoc[0](loc0: EnumWithThreeVariants) + 3: Call f(EnumWithThreeVariants): Ty0 + 4: Ret + +} +public call_fail_3(): Ty0 { +L0: loc0: EnumWithThreeVariants +B0: + 0: PackVariantGeneric(VariantInstantiationHandleIndex(2)) + 1: StLoc[0](loc0: EnumWithThreeVariants) + 2: MoveLoc[0](loc0: EnumWithThreeVariants) + 3: Call f(EnumWithThreeVariants): Ty0 + 4: Ret + +} +f(Arg0: EnumWithThreeVariants): Ty0 { +B0: + 0: ImmBorrowLoc[0](Arg0: EnumWithThreeVariants) + 1: VariantSwitch(VariantJumpTableIndex(0)) +B1: + 2: MoveLoc[0](Arg0: EnumWithThreeVariants) + 3: UnpackVariantGeneric(VariantInstantiationHandleIndex(0)) + 4: StLoc[1](loc0: Ty0) + 5: MoveLoc[1](loc0: Ty0) + 6: Ret +Jump tables: +[0]: variant_switch EnumWithThreeVariants { + Variant0 => jump 2 + Variant1 => jump 2 + Variant2 => jump 2 + } +} +} + +task 3 'run'. lines 101-101: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(3), 3)], +} + +task 4 'run'. lines 103-103: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(3), 3)], +} diff --git a/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_jump_same_label.mvir b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_jump_same_label.mvir new file mode 100644 index 0000000000000..72dbbebe69942 --- /dev/null +++ b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_jump_same_label.mvir @@ -0,0 +1,103 @@ +//# print-bytecode +module 0x1.Enums { + enum EnumWithThreeVariants { + One { }, + Two { x: T }, + Three { } + } + + public call_success(t: T): T { + let x: Self.EnumWithThreeVariants; + label b0: + x = EnumWithThreeVariants.Two { x: move(t) }; + return Self.f(move(x)); + } + + public call_fail_1(): T { + let x: Self.EnumWithThreeVariants; + label b0: + x = EnumWithThreeVariants.One { }; + return Self.f(move(x)); + } + + + public call_fail_3(): T { + let x: Self.EnumWithThreeVariants; + label b0: + x = EnumWithThreeVariants.Three { }; + return Self.f(move(x)); + } + + f(x: Self.EnumWithThreeVariants): T { + let y: T; + label b0: + variant_switch EnumWithThreeVariants (&x) { + One : b1, + Two : b1, + Three : b1, + }; + label b1: + EnumWithThreeVariants.Two { x: y } = move(x); + return move(y); + } +} + +//# publish +module 0x1.Enums { + enum EnumWithThreeVariants { + One { }, + Two { x: T }, + Three { } + } + + public call_success(t: T): T { + let x: Self.EnumWithThreeVariants; + label b0: + x = EnumWithThreeVariants.Two { x: move(t) }; + return Self.f(move(x)); + } + + public call_fail_1(): T { + let x: Self.EnumWithThreeVariants; + label b0: + x = EnumWithThreeVariants.One { }; + return Self.f(move(x)); + } + + + public call_fail_3(): T { + let x: Self.EnumWithThreeVariants; + label b0: + x = EnumWithThreeVariants.Three { }; + return Self.f(move(x)); + } + + f(x: Self.EnumWithThreeVariants): T { + let y: T; + label b0: + variant_switch EnumWithThreeVariants (&x) { + One : b1, + Two : b1, + Three : b1, + }; + label b1: + EnumWithThreeVariants.Two { x: y } = move(x); + return move(y); + } +} + +//# run +module 0x2.m { +import 0x1.Enums; +entry foo() { + let x: u64; + label b0: + x = Enums.call_success(42); + assert(move(x) == 42, 100); + return; +} +} + +//# run 0x1::Enums::call_fail_1 --type-args u64 + +//# run 0x1::Enums::call_fail_3 --type-args u64 diff --git a/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_tag_unpack_invalid.exp b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_tag_unpack_invalid.exp new file mode 100644 index 0000000000000..2e7faf4b8af90 --- /dev/null +++ b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_tag_unpack_invalid.exp @@ -0,0 +1,109 @@ +processed 14 tasks + +task 2 'run'. lines 222-222: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(4), 1)], +} + +task 3 'run'. lines 224-224: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(5), 1)], +} + +task 4 'run'. lines 226-226: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(3), 1)], +} + +task 5 'run'. lines 228-228: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(1), 1)], +} + +task 6 'run'. lines 230-230: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(2), 1)], +} + +task 7 'run'. lines 232-232: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(0), 1)], +} + +task 8 'run'. lines 234-234: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(10), 1)], +} + +task 9 'run'. lines 236-236: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(11), 1)], +} + +task 10 'run'. lines 238-238: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(9), 1)], +} + +task 11 'run'. lines 240-240: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(7), 1)], +} + +task 12 'run'. lines 242-242: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(8), 1)], +} + +task 13 'run'. lines 244-244: +Error: Function execution failed with VMError: { + major_status: VARIANT_TAG_MISMATCH, + sub_status: None, + location: 0x1::Enums, + indices: [], + offsets: [(FunctionDefinitionIndex(6), 1)], +} diff --git a/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_tag_unpack_invalid.mvir b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_tag_unpack_invalid.mvir new file mode 100644 index 0000000000000..4ea010e4a204a --- /dev/null +++ b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/enum_variant_tag_unpack_invalid.mvir @@ -0,0 +1,244 @@ +//# publish +module 0x1.Enums { + enum PolyEnum { + One { }, + Two { x: T }, + } + + enum MonoEnum { + One { }, + Two { x: u8 }, + } + + public poly_unpack_one(e: Self.PolyEnum) { + label b0: + PolyEnum.One { } = move(e); + return; + } + + public poly_unpack_one_mut_ref(e: &mut Self.PolyEnum) { + label b0: + &mut PolyEnum.One { } = move(e); + return; + } + + public poly_unpack_one_imm_ref(e: &Self.PolyEnum) { + label b0: + & PolyEnum.One { } = move(e); + return; + } + + public poly_unpack_two(e: Self.PolyEnum) { + let x: T; + label b0: + PolyEnum.Two { x: x } = move(e); + return; + } + + public poly_unpack_two_mut_ref(e: &mut Self.PolyEnum) { + let x: &mut T; + label b0: + &mut PolyEnum.Two { x: x } = move(e); + return; + } + + public poly_unpack_two_imm_ref(e: &Self.PolyEnum) { + let x: &T; + label b0: + & PolyEnum.Two { x: x } = move(e); + return; + } + + public mono_unpack_one(e: Self.MonoEnum) { + label b0: + MonoEnum.One { } = move(e); + return; + } + + public mono_unpack_one_mut_ref(e: &mut Self.MonoEnum) { + label b0: + &mut MonoEnum.One { } = move(e); + return; + } + + public mono_unpack_one_imm_ref(e: &Self.MonoEnum) { + label b0: + &MonoEnum.One { } = move(e); + return; + } + + public mono_unpack_two(e: Self.MonoEnum) { + let x: u8; + label b0: + MonoEnum.Two { x: x } = move(e); + return; + } + + public mono_unpack_two_mut_ref(e: &mut Self.MonoEnum) { + let x: &mut u8; + label b0: + &mut MonoEnum.Two { x: x } = move(e); + return; + } + + public mono_unpack_two_imm_ref(e: &Self.MonoEnum) { + let x: &u8; + label b0: + & MonoEnum.Two { x: x } = move(e); + return; + } + + public all_valid() { + let x1: Self.PolyEnum; + let y1: Self.MonoEnum; + + let x2: Self.PolyEnum; + let y2: Self.MonoEnum; + label b0: + x1 = PolyEnum.One {}; + y1 = MonoEnum.One {}; + + x2 = PolyEnum.Two {x: 0}; + y2 = MonoEnum.Two {x: 0u8}; + + Self.poly_unpack_one_mut_ref(&mut x1); + Self.poly_unpack_one_imm_ref(&x1); + Self.poly_unpack_one(move(x1)); + + Self.mono_unpack_one_mut_ref(&mut y1); + Self.mono_unpack_one_imm_ref(&y1); + Self.mono_unpack_one(move(y1)); + + Self.poly_unpack_two_mut_ref(&mut x2); + Self.poly_unpack_two_imm_ref(&x2); + Self.poly_unpack_two(move(x2)); + + Self.mono_unpack_two_mut_ref(&mut y2); + Self.mono_unpack_two_imm_ref(&y2); + Self.mono_unpack_two(move(y2)); + return; + } + + public poly_invalid1_mut_ref() { + let x1: Self.PolyEnum; + label b0: + x1 = PolyEnum.One {}; + Self.poly_unpack_two_mut_ref(&mut x1); + abort 0; + } + + public poly_invalid1_imm_ref() { + let x1: Self.PolyEnum; + label b0: + x1 = PolyEnum.One {}; + Self.poly_unpack_two_imm_ref(&x1); + abort 0; + } + + public poly_invalid1() { + let x1: Self.PolyEnum; + label b0: + x1 = PolyEnum.One {}; + Self.poly_unpack_two(move(x1)); + return; + } + + + public poly_invalid2_mut_ref() { + let x2: Self.PolyEnum; + label b0: + x2 = PolyEnum.Two {x: 0}; + Self.poly_unpack_one_mut_ref(&mut x2); + abort 0; + } + + public poly_invalid2_imm_ref() { + let x2: Self.PolyEnum; + label b0: + x2 = PolyEnum.Two {x: 0}; + Self.poly_unpack_one_imm_ref(&x2); + abort 0; + } + + public poly_invalid2() { + let x2: Self.PolyEnum; + label b0: + x2 = PolyEnum.Two {x: 0}; + Self.poly_unpack_one(move(x2)); + return; + } + + public mono_invalid1_mut_ref() { + let x1: Self.MonoEnum; + label b0: + x1 = MonoEnum.One {}; + Self.mono_unpack_two_mut_ref(&mut x1); + abort 0; + } + + public mono_invalid1_imm_ref() { + let x1: Self.MonoEnum; + label b0: + x1 = MonoEnum.One {}; + Self.mono_unpack_two_imm_ref(&x1); + abort 0; + } + + public mono_invalid1() { + let x1: Self.MonoEnum; + label b0: + x1 = MonoEnum.One {}; + Self.mono_unpack_two(move(x1)); + return; + } + + public mono_invalid2_mut_ref() { + let x2: Self.MonoEnum; + label b0: + x2 = MonoEnum.Two {x: 0u8}; + Self.mono_unpack_one_mut_ref(&mut x2); + abort 0; + } + + public mono_invalid2_imm_ref() { + let x2: Self.MonoEnum; + label b0: + x2 = MonoEnum.Two {x: 0u8}; + Self.mono_unpack_one_imm_ref(&x2); + abort 0; + } + + public mono_invalid2() { + let x2: Self.MonoEnum; + label b0: + x2 = MonoEnum.Two {x: 0u8}; + Self.mono_unpack_one(move(x2)); + return; + } +} + +//# run 0x1::Enums::all_valid + +//# run 0x1::Enums::poly_invalid1_mut_ref + +//# run 0x1::Enums::poly_invalid1_imm_ref + +//# run 0x1::Enums::poly_invalid1 + +//# run 0x1::Enums::poly_invalid2_mut_ref + +//# run 0x1::Enums::poly_invalid2_imm_ref + +//# run 0x1::Enums::poly_invalid2 + +//# run 0x1::Enums::mono_invalid1_mut_ref + +//# run 0x1::Enums::mono_invalid1_imm_ref + +//# run 0x1::Enums::mono_invalid1 + +//# run 0x1::Enums::mono_invalid2_mut_ref + +//# run 0x1::Enums::mono_invalid2_imm_ref + +//# run 0x1::Enums::mono_invalid2 diff --git a/external-crates/move/crates/move-vm-transactional-tests/tests/enums/unpack_mut_ref_alias.exp b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/unpack_mut_ref_alias.exp new file mode 100644 index 0000000000000..fc5a4436b29d4 --- /dev/null +++ b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/unpack_mut_ref_alias.exp @@ -0,0 +1 @@ +processed 3 tasks diff --git a/external-crates/move/crates/move-vm-transactional-tests/tests/enums/unpack_mut_ref_alias.mvir b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/unpack_mut_ref_alias.mvir new file mode 100644 index 0000000000000..a7f3191d0e69b --- /dev/null +++ b/external-crates/move/crates/move-vm-transactional-tests/tests/enums/unpack_mut_ref_alias.mvir @@ -0,0 +1,65 @@ +//# publish +module 0x1.o { + enum X has drop { + One { x: u64, y: u64 }, + Two { x: u64, y: u64}, + } + + // Tests that in this situation `x` and `x2` are aliases of each other + a(e: &mut Self.X) { + let x: &mut u64; + let x2: &mut u64; + let y: &mut u64; + label b0: + &mut X.One { x: x, y: y} = copy(e); + *move(y) = 0; + &mut X.One { x: x2, y: y} = move(e); + *move(x) = 0; + return; + } + + // Tests that in this situation `x` and `x2` are aliases of each other and can both be mutated + b(e: &mut Self.X) { + let x: &mut u64; + let x2: &mut u64; + let y: &mut u64; + label b0: + &mut X.One { x: x, y: y} = copy(e); + *move(y) = 0; + &mut X.One { x: x2, y: y} = move(e); + *move(x) = 0; + *move(x2) = 0; + return; + } + + public test1() { + let x: Self.X; + let x1: u64; + let x2: u64; + label b0: + x = X.One { x: 10, y: 20}; + Self.b(&mut x); + X.One { x: x1, y: x2} = move(x); + assert(move(x1) == 0, 1); + assert(move(x2) == 0, 2); + return; + } + + public test2() { + let x: Self.X; + let x1: u64; + let x2: u64; + label b0: + x = X.One { x: 10, y: 20}; + Self.a(&mut x); + X.One { x: x1, y: x2} = move(x); + assert(move(x1) == 0, 1); + assert(move(x2) == 0, 2); + return; + } + +} + +//# run 0x1::o::test1 + +//# run 0x1::o::test2