Skip to content

False positive dead code warning #102190

Description

@alexkazik

When code is generated via a proc macro there is a case which creates a false positive for the dead code warning.

Proc macro (src/lib.rs):

use proc_macro2::Span;
use quote::quote;
use syn::spanned::Spanned;
use syn::{parse_macro_input, DeriveInput, Ident};

#[proc_macro_derive(Test)]
pub fn proc_dead_code_test(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(tokens as DeriveInput);
    let repr = Ident::new("i8", input.span());
    let repr_call_size = Ident::new("i8", Span::call_site());
    let vis = input.vis;
    quote! {
        impl MyEnum {
            #vis fn false_positive(self) -> #repr {
                self as i8
            }
            pub(crate) fn ok_1(self) -> #repr {
                self as i8
            }
            #vis fn ok_2(self) -> i8 {
                self as i8
            }
            #vis fn ok_3(self) -> #repr_call_size {
                self as i8
            }
        }
    }
    .into()
}

Test (tests/all.rs):

use proc_dead_code_test::Test;

#[allow(dead_code)]
#[derive(Test)]
#[repr(i8)]
pub(crate) enum MyEnum {
    MyValue,
}

The current output is:

warning: associated function `false_positive` is never used
 --> tests/all.rs:4:10
  |
4 | #[derive(Test)]
  |          ^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: `proc_dead_code_test` (test "all") generated 1 warning

The generated code for all four functions are identical (except the name, obviusly), tested with cargo expand.

One is reported as dead code, though no report should be given since #[allow(dead_code)] is used.

On 1.63.0 this is not a warning, but with 1.65.0-beta.1 it is.

I'm aware that this is a very special case and I don't mind if it doesn't get fixed but I thought I'll report it anyway.

For a quick copy-and-paste run here the Cargo.toml:

[package]
name = "proc_dead_code_test"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
syn = { version = "1.0.99", features = ["derive", "parsing", "extra-traits"] }
quote = "1.0.21"
proc-macro2 = "1.0.43"

(I don't know how to setup play.rust-lang.org to create a proc-macro and a real test, thats why it's missing.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-proc-macrosArea: Procedural macrosC-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.L-dead_codeLint: dead_codeT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions