rust-clippy icon indicating copy to clipboard operation
rust-clippy copied to clipboard

False "missing_const_in_fn" for a function that consumes `self`

Open ppentchev opened this issue 2 years ago • 4 comments

Summary

Hi,

First of all, thanks a lot for working on Rust and the related tools and crates!

Clippy seems to report a "missing_const_in_fn" for a function that replaces a field in a struct. If I add "const" to the function, rustc says "constant functions cannot evaluate destructors". It is quite possible that, just like e.g. #4041, this is actually a bug in rustc's parser, AST builder, code analyzer, etc; apologies if it has been reported already.

Since the source file is a bit on the large side, I have put the mini-"crate" up in a Git repository at https://gitlab.com/ppentchev/rust-bug-missing-const

Lint Name

clippy::missing_const_for_fn

Reproducer

I tried this code (it uses expect-exit 0.4.2):

/*
 * Copyright (c) 2022  Peter Pentchev <[email protected]>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
//! Demonstrate a false `clippy::missing_const_for_fn` positive.

#![deny(missing_docs)]
// Activate most of the clippy::restriction lints that we've encountered...
#![warn(clippy::pattern_type_mismatch)]
#![warn(clippy::missing_docs_in_private_items)]
#![warn(clippy::print_stdout)]
// ...except for these ones.
#![allow(clippy::implicit_return)]
// Activate some of the clippy::nursery lints...
#![warn(clippy::missing_const_for_fn)]

use std::env;

/// Runtime configuration for the bug-missing-const tool.
#[derive(Debug, PartialEq)]
#[non_exhaustive]
struct Config {
    /// The current program name.
    program: String,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            program: "(unspecified)".to_owned(),
        }
    }
}

impl Config {
    /// Specify the program name.
    fn with_program(self, program: String) -> Self {
        Self { program, ..self }
    }
}

/// Parse the command-line arguments into a configuration structure.
fn parse_args() -> Config {
    let args: Vec<String> = env::args().collect();
    match *args {
        [] => expect_exit::exit("Not even a program name?"),
        [ref program] => Config::default().with_program(program.clone()),
        _ => expect_exit::exit("Usage: bug-missing-const"),
    }
}

#[cfg(test)]
mod tests {
    use super::Config;

    #[test]
    fn test_config_default() {
        assert!(
            Config::default()
                == Config {
                    program: "(unspecified)".to_owned()
                }
        );
    }

    #[test]
    fn test_config_with_program() {
        assert!(
            Config::default().with_program("616".to_owned())
                == Config {
                    program: "616".to_owned()
                }
        );
    }
}

#[allow(clippy::print_stdout)]
fn main() {
    let cfg = parse_args();
    println!("Program name: {}", cfg.program);
}

I saw this happen:

    Checking bug-missing-const v0.1.0 (/home/roam/lang/rust/misc/bug-missing-const)
warning: this could be a `const fn`
  --> src/main.rs:58:5
   |
58 | /     fn with_program(self, program: String) -> Self {
59 | |         Self { program, ..self }
60 | |     }
   | |_____^

I expected to see no warnings at all.

Version

rustc 1.61.0 (fe5b13d68 2022-05-18)
binary: rustc
commit-hash: fe5b13d681f25ee6474be29d748c65adcd91f69e
commit-date: 2022-05-18
host: x86_64-unknown-linux-gnu
release: 1.61.0
LLVM version: 14.0.0

Additional Labels

No response

ppentchev avatar May 23 '22 09:05 ppentchev

I'm also experiencing this issue - the code that triggers it follows:

pub enum Either<A, B> {
    Left(A),
    Right(B)
}

impl<A> Either<A, A> {
    pub fn unwrap (self) -> A {
        match self {
            Self::Left(a) => a,
            Self::Right(b) => b
        }
    }
} 

error as follows:

warning: this could be a `const fn`
  --> src\either.rs:16:5
   |
16 | /     pub fn unwrap (self) -> A {
17 | |         match self {
18 | |             Self::Left(a) => a,
19 | |             Self::Right(b) => b
20 | |         }
21 | |     }
   | |_____^

Error line is incorrect due to removed code - not clippy's fault.

BurntNail avatar Jul 14 '22 14:07 BurntNail

I can also pitch in with my experience.

I have a struct with a generic:

pub struct Response<V> {
    ok: bool,
    value: Option<V>,
}

Which implements the following function:

fn value(self) -> Option<V> {
    self.value
}

Clippy suggests making the function a const fn but when i do so, the compiler tells me the following:

error[E0493]: destructor of `core::response::Response<V>` cannot be evaluated at compile-time
  --> src/core/response.rs:82:20
   |
82 |     const fn value(self) -> Option<V> {
   |                    ^^^^ the destructor for this type cannot be evaluated in constant functions
83 |         self.value
84 |     }
   |     - value is dropped here

Note: The struct has other fields and more implementations, but the above is the "minimal" example of the issue. If more is needed, i will happily provide it.

madser123 avatar Jul 04 '23 17:07 madser123

I believe this was already fixed in #10891.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=7c430738d1e182a7bbb03c1ba398d1da

Centri3 avatar Jul 04 '23 17:07 Centri3

I believe this was already fixed in #10891.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=7c430738d1e182a7bbb03c1ba398d1da

When using Rust 1.75, I still see this clippy warning on a straightforward builder pattern and clippy::nursery.

johnperry-math avatar Jan 16 '24 01:01 johnperry-math