Skip to content

The &mut/& split makes a same-array mem_copy unrepresentable in Rust, where C expresses it #3404

Description

@gHashTag

Found by adversarial review of #3403. Latent: population 0 in todays emitted Rust. Filed so it is not discovered later as a surprise.

The shape

specs/isa/ternary_memory.t27:226:

fn mem_copy(dst: []TernaryWord, dst_addr: u32, src: []TernaryWord, src_addr: u32, count: usize) -> bool

Its body carries an explicit two-branch overlap handler — "Handle overlap (copy direction matters)" — forward when dst_addr < src_addr, backward otherwise. That branch exists for exactly one situation: dst and src are the same array. And the spec exercises it that way, twice:

  • line 388, test mem_block_copy_overlapmem_copy(memory, 0, memory, 1, 2)
  • line 472, invariant mem_copy_handles_overlapmem_copy(memory, 0, memory, 1, 2)

What #3403 does to it

dst is index-assigned so the fixpoint marks it; src is not. The emitted signature becomes

pub fn mem_copy(dst: &mut [TernaryWord], dst_addr: u32, src: &[TernaryWord], src_addr: u32, count: usize) -> bool

and the spec own call is then unrepresentable in safe Rust:

error[E0502]: cannot borrow `memory` as immutable because it is also borrowed as mutable
  mem_copy(&mut memory, 0, &memory, 1, 2)

The backward-copy branch becomes dead by type. C takes two pointers and can express the call; Verilog can too. So this is a place where the four backends do not agree about what the spec means — the property the project exists to hold.

Why it is not urgent, stated precisely

It becomes live the moment tests or invariants are lowered to Rust — which is a direction this project wants to go, so the cost is deferred rather than avoided.

Options, none of them free

  1. Refuse the shape. When one function has both a written slice parameter and a read slice parameter of the same element type, the &mut/& split cannot express a same-array call. Leave that function parameters as they were and declare it on the existing NOT LOWERED BY THIS BACKEND header line, so the omission is disclosed rather than silent.
  2. Lower it as one slice plus indices, matching what slice::copy_within does. That changes the spec surface, not just the backend.
  3. Accept it and say so in the spec, marking mem_copy as a construct whose Rust lowering is weaker than its C and Verilog lowerings.

Option 1 is the one that keeps the honesty property this repository already has a mechanism for. Which of the three is the owner call.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions