Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
SergioBenitez opened this issue Jan 31, 2020 · 2 comments

Comments

@SergioBenitez
Copy link
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.

@dtolnay
Copy link
Owner

dtolnay commented Jan 31, 2020

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
Copy link
Owner

dtolnay commented Feb 2, 2020

Fixed in rust-lang/rust#68737.

@dtolnay dtolnay closed this as completed Feb 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants