rust-lang/rust-clippy

question-mark introduces move error

matthiaskrgr opened this issue · 0 comments

Summary

this code is somehow cursed, when I tried to remove more functions the error went away :(

Lint Name

question-mark

Reproducer

I tried this code:

// run-rustfix
#![allow(unreachable_code)]
#![allow(clippy::unnecessary_wraps)]


fn some_func(a: Option<u32>) -> Option<u32> {
    if a.is_none() {
        return None;
    }

    a
}

fn some_other_func(a: Option<u32>) -> Option<u32> {
    if a.is_none() {
        return None;
    } else {
        return Some(0);
    }
    unreachable!()
}

pub enum SeemsOption<T> {
    Some(T),
    None,
}

impl<T> SeemsOption<T> {
    pub fn is_none(&self) -> bool {
        match *self {
            SeemsOption::None => true,
            SeemsOption::Some(_) => false,
        }
    }
}

fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
    if a.is_none() {
        return SeemsOption::None;
    }

    a
}

pub struct CopyStruct {
    pub opt: Option<u32>,
}

impl CopyStruct {
    #[rustfmt::skip]
    pub fn func(&self) -> Option<u32> {
        if (self.opt).is_none() {
            return None;
        }

        if self.opt.is_none() {
            return None
        }

        let _ = if self.opt.is_none() {
            return None;
        } else {
            self.opt
        };

        let _ = if let Some(x) = self.opt {
            x
        } else {
            return None;
        };

        self.opt
    }
}

#[derive(Clone)]
pub struct MoveStruct {
    pub opt: Option<Vec<u32>>,
}

impl MoveStruct {
    pub fn ref_func(&self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }

        self.opt.clone()
    }

    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }

        self.opt
    }

    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
        if self.opt.is_none() {
            return None;
        }
        Some(Vec::new())
    }

    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
        let v: &Vec<_> = if let Some(ref v) = self.opt {
            v
        } else {
            return None;
        };

        Some(v.clone())
    }

    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
        let v = if let Some(v) = self.opt {
            v
        } else {
            return None;
        };

        Some(v)
    }
}

fn func() -> Option<i32> {
    fn f() -> Option<String> {
        Some(String::new())
    }

    if f().is_none() {
        return None;
    }

    Some(0)
}

fn func_returning_result() -> Result<i32, String> {
    Ok(1)
}

fn result_func(x: Result<i32, String>) -> Result<i32, String> {
    let _ = if let Ok(x) = x { x } else { return x };

    if x.is_err() {
        return x;
    }

    // No warning
    let y = if let Ok(x) = x {
        x
    } else {
        return Err("some error".to_string());
    };

    // issue #7859
    // no warning
    let _ = if let Ok(x) = func_returning_result() {
        x
    } else {
        return Err("some error".to_string());
    };

    if func_returning_result().is_err() {
        return func_returning_result();
    }

    Ok(y)
}

fn main() {}

I saw this happen:


This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the `--broken-code` flag

The following errors were reported:
error[E0382]: use of moved value: `x`
   --> src/main.rs:118:23
    |
112 | fn result_func(x: Result<i32, String>) -> Result<i32, String> {
    |                - move occurs because `x` has type `std::result::Result<i32, std::string::String>`, which does not implement the `Copy` trait
113 |     let _ = x?;
    |             -- `x` moved due to this method call
...
118 |     let y = if let Ok(x) = x {
    |                       ^ value used here after move
    |
help: consider cloning the value if the performance cost is acceptable
    |
113 |     let _ = x.clone()?;
    |              ++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
Original diagnostics will follow.

Version

rustc 1.67.0-nightly (c97b539e4 2022-11-30)
binary: rustc
commit-hash: c97b539e408ea353f4fde2f9251d598291fec421
commit-date: 2022-11-30
host: x86_64-unknown-linux-gnu
release: 1.67.0-nightly
LLVM version: 15.0.4

Additional Labels

No response