Skip to content

Attribute drops (some) attributes inside trait function implementations #63

@SergioBenitez

Description

@SergioBenitez
Contributor

When attributes appear inside of a function in a trait implementation decorated with #[async_trait], those attributes can be dropped depending on what they're decorating. In particular, attributes decorating fields are dropped entirely.

Consider the following example:

#[async_trait::async_trait]
trait Foo: Sized {
    fn g(&self);
}

struct K { field: usize }

#[async_trait::async_trait]
impl Foo for K {
    fn g(&self) {
        let _ = K {
            #[cfg(debug_assertions)]
            field: 0,
            #[cfg(not(debug_assertions))]
            field: 1,
        };
    }
}

This impl expand to:

impl Foo for K {
    fn g(&self) {
        let _ = K { field: 0, field: 1, };
    }
}

Which results in the (incorrect) compile-time error:

error[E0062]: field `field` specified more than once

error: aborting due to previous error

Note that span information appears to be lost as well.

Activity

dtolnay

dtolnay commented on Jan 31, 2020

@dtolnay
Owner

This is a compiler bug. Based on adding the following to the macro,

eprintln!("{}", input);
eprintln!("{:#?}", input);

rustc is passing in:

impl Foo for K {
    fn g(&self) { let _ = K{field: 0, field: 1,}; }
}
TokenStream [
    Ident {
        ident: "impl",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "Foo",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "for",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "K",
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Ident {
                ident: "fn",
                span: #0 bytes(0..0),
            },
            Ident {
                ident: "g",
                span: #0 bytes(0..0),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Punct {
                        ch: '&',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "self",
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
            Group {
                delimiter: Brace,
                stream: TokenStream [
                    Ident {
                        ident: "let",
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "_",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '=',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "K",
                        span: #0 bytes(0..0),
                    },
                    Group {
                        delimiter: Brace,
                        stream: TokenStream [
                            Ident {
                                ident: "field",
                                span: #0 bytes(0..0),
                            },
                            Punct {
                                ch: ':',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Literal { lit: Lit { kind: Integer, symbol: "0", suffix: None }, span: Span { lo: BytePos(0), hi: BytePos(0), ctxt: #0 } },
                            Punct {
                                ch: ',',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Ident {
                                ident: "field",
                                span: #0 bytes(0..0),
                            },
                            Punct {
                                ch: ':',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Literal { lit: Lit { kind: Integer, symbol: "1", suffix: None }, span: Span { lo: BytePos(0), hi: BytePos(0), ctxt: #0 } },
                            Punct {
                                ch: ',',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                        ],
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: ';',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
        ],
        span: #0 bytes(0..0),
    },
]
dtolnay

dtolnay commented on Feb 2, 2020

@dtolnay
Owner
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @SergioBenitez@dtolnay

        Issue actions

          Attribute drops (some) attributes inside trait function implementations · Issue #63 · dtolnay/async-trait