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

`clippy::vec_init_then_push` can't be ignored

Open xobs opened this issue 5 months ago • 2 comments

Summary

I'm trying to come up with a configuration array that takes objects that are of a given type. The items in this global list can vary depending on compilation settings. As a result, I'm constructing the values in a LazyLock.

The items that are added to the vec depend on feature flags. As a result, I can't construct a vec![] as it suggests. Additionally, I can't seem to be able to turn them off in the obvious way.

Lint Name

vec_init_then_push

Reproducer

I tried this code:

#![allow(unexpected_cfgs)]
use std::sync::RwLock;
use std::sync::LazyLock;

trait ExampleTrait: Send + Sync {
    fn value(&self) -> u32;
}

struct Object {
    val: u32,
}

impl ExampleTrait for Object {
    fn value(&self) -> u32 {
        self.val
    }
}

fn init_object(val: u32) -> Object {
    Object { val }
}

static OBJECTS: LazyLock<RwLock<Vec<Box<dyn ExampleTrait>>>> = LazyLock::new(|| {
    #[allow(clippy::vec_init_then_push)]
    let mut v: Vec<Box<dyn ExampleTrait>> = vec![];
    
    #[allow(clippy::vec_init_then_push)]
    v.push(Box::new(init_object(1)));

    #[cfg(feature = "other-feature")]
    #[allow(clippy::vec_init_then_push)]
    v.push(Box::new(init_object(2)));
    
    RwLock::new(v)
});

fn main() {
    let test_list = &*OBJECTS.read().unwrap();
    for val in test_list {
        println!("Val: {}", val.value());
    }
}

I saw this happen:

warning: calls to `push` immediately after creation
  --> src/main.rs:25:5
   |
25 | /     let mut v: Vec<Box<dyn ExampleTrait>> = vec![];
26 | |     
27 | |     #[allow(clippy::vec_init_then_push)]
28 | |     v.push(Box::new(init_object(1)));
   | |_____________________________________^ help: consider using the `vec![]` macro: `let v: Vec<Box<dyn ExampleTrait>> = vec![..];`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#vec_init_then_push
   = note: `#[warn(clippy::vec_init_then_push)]` on by default

I expected to see this happen:

No output, especially since I ignored the lint immediately above.

Version

rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: x86_64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1

Additional Labels

No response

xobs avatar Jun 17 '25 08:06 xobs

The way the lint is currently implemented, the #[allow] attribute needs to go on the block (or since that's unstable, putting it on the static itself should work too). Accepting lint level attrs at any of the push() calls could maybe work, but it would probably get messy with #[expect]

y21 avatar Jun 17 '25 08:06 y21

It's a bit incongruous to see the allow(..) in the warning, and took me longer than I'd like to figure out how to turn it off.

Is there another way this should be done to avoid the warning? Or is there a way to hint how it expects the warning to be disabled?

xobs avatar Jun 17 '25 08:06 xobs

#![allow(unexpected_cfgs)]
#![deny(clippy::vec_init_then_push)]
use std::sync::RwLock;
use std::sync::LazyLock;

trait ExampleTrait: Send + Sync {
    fn value(&self) -> u32;
}

struct Object {
    val: u32,
}

impl ExampleTrait for Object {
    fn value(&self) -> u32 {
        self.val
    }
}

fn init_object(val: u32) -> Object {
    Object { val }
}

// TODO(you): rename this function
#[allow(clippy::vec_init_then_push)]
fn x() -> RwLock<Vec<Box<dyn ExampleTrait>>> {
    let mut v: Vec<Box<dyn ExampleTrait>> = vec![];
    
    v.push(Box::new(init_object(1)));

    #[cfg(feature = "other-feature")]
    v.push(Box::new(init_object(2)));
    
    RwLock::new(v)
}

static OBJECTS: LazyLock<RwLock<Vec<Box<dyn ExampleTrait>>>> = LazyLock::new(x);

fn main() {
    let test_list = &*OBJECTS.read().unwrap();
    for val in test_list {
        println!("Val: {}", val.value());
    }
}

this should work (playground).

KisaragiEffective avatar Sep 08 '25 08:09 KisaragiEffective