Ownership and moving in match statement with and without `return` keyword

⚓ Rust    📅 2025-06-30    👤 surdeus    👁️ 6      

surdeus

Warning

This post was published 38 days ago. The information described in this article may have changed.

I am writing a function to perform semantic analysis over a simple assembly language instruction I am implementing for a simple computer model. I use some match expressions to acheive this, and upon detecting errors I return a custom error type. The error type takes owned data, so the algorithm conditionally moves values into the error.

I found that on the branches where I construct this error, if I use the return keyword the compiler understands this conditional move ends the function, and lets me use the variables after the match, but if I wait until the end of the expression and use ?, it considers the variable moved and I cannot use them later. Here's some code illustrating this:

// ensure the destination is not Immediate or a condition bit
            match &dest {
                // construct error, but do not use `return`
                Operand::Immediate(_) | Operand::ConditionBit(_) => Err(
                    OsiacSemanticError::IllegalDestinationAddressingMode(dest, op.to_string()),
                ),
                _ => Ok(()),
            }?;

            return Ok(Instruction::DoubleOperand { op, src, dest });

This code results in this Rust compiler error message:

error[E0382]: use of moved value: `dest`
// ensure the destination is not Immediate or a condition bit
            match &dest {
                // construct and directly return error
                Operand::Immediate(_) | Operand::ConditionBit(_) => return Err(
                    OsiacSemanticError::IllegalDestinationAddressingMode(dest, op.to_string()),
                ),
                _ => Ok(()),
            }?;

            return Ok(Instruction::DoubleOperand { op, src, dest });

This results in no compiler error.

I want to understand better why this is the case. I suspect because without the return statement, the match statement scope ends before the ? operator is used, meaning it compiles as a scope where the value might move, therefore the compiler treats it as moved. With the return statement my guess is that the compiler recognizes the immediately returning branch and that using the value after that must be safe as if it moved execution would not reach there anyway.

Sorry for rambling, just here to learn. Thanks all!

3 posts - 3 participants

Read full topic

🏷️ rust_feed