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

Cargo fix generates broken code for type names passed to derives #67373

Open
sgrif opened this issue Dec 17, 2019 · 6 comments
Open

Cargo fix generates broken code for type names passed to derives #67373

sgrif opened this issue Dec 17, 2019 · 6 comments
Labels
A-edition-2018-lints Area: lints supporting the 2018 edition A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. C-bug Category: This is a bug. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sgrif
Copy link
Contributor

sgrif commented Dec 17, 2019

When a type is given to a proc macro as a string, such as in https://github.com/diesel-rs/diesel/blob/6e2d467d131030dc0bbce4e4801c7bee7bcbf0dd/diesel/src/type_impls/primitives.rs#L20, cargo fix --edition will incorrectly generate crate::"::old_type::Path". If there are nested types inside, such as https://github.com/diesel-rs/diesel/blob/6e2d467d131030dc0bbce4e4801c7bee7bcbf0dd/diesel/src/type_impls/primitives.rs#L42, they won't be touched at all.

@ehuss ehuss transferred this issue from rust-lang/cargo Dec 17, 2019
@ehuss
Copy link
Contributor

ehuss commented Dec 17, 2019

Moved to rust-lang/rust, as the fix suggestions are generated by rustc.

It might help to include a minimal reproduction, along with details about what the before and after looks like. Diesel is quite large, and it can be difficult to untangle what is going on from what you linked.

@estebank estebank added A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 17, 2019
@sgrif
Copy link
Contributor Author

sgrif commented Dec 17, 2019

Thanks, @ehuss! A minimal reproduction would be this:

#[derive(diesel::AsExpression)]
#[sql_type = "::Bar"]
struct Foo;

struct Bar;

cargo fix --edition will turn that into:

#[derive(diesel::AsExpression)]
#[sql_type = crate::"::Bar"]
struct Foo;

struct Bar;

and it can be difficult to untangle what is going on from what you linked.

I suspect the problem here is that we are parsing the given string as a type (since that's the only type that could be used to reference a type in a meta attribute), keeping the span of the original string. It appears as though it's just naively putting crate:: in front of whatever the span points to. There could be some special casing here, but the problem is worse when generics are involved.

#[derive(diesel::AsExpression)]
#[sql_type = "Option<::Bar>"]
struct Foo;

struct Bar;

gets the same treatment:

#[derive(diesel::AsExpression)]
#[sql_type = crate::"Option<::Bar>"]
struct Foo;

struct Bar;

Since the APIs on Span for us to only point at the relevant characters don't exist, cargo fix should probably be bailing if the tokens pointed to aren't a valid type.

@ehuss ehuss added the A-edition-2018-lints Area: lints supporting the 2018 edition label Dec 17, 2019
@ehuss
Copy link
Contributor

ehuss commented Dec 17, 2019

I was thinking of something more along the lines of not using diesel, since there's a lot of machinery there. Something like this:

// A proc-macro crate named "pmf".
extern crate proc_macro;
extern crate syn;
extern crate quote;
use proc_macro::TokenStream;
use quote::quote;

#[proc_macro_derive(Foo, attributes(helper))]
pub fn foo(tokens: TokenStream) -> TokenStream {
    let s = syn::parse_macro_input!(tokens as syn::DeriveInput);
    let helper = s.attrs.iter().filter(|attr| attr.path.is_ident("helper")).next().unwrap();
    let name = match helper.parse_meta().unwrap() {
        syn::Meta::NameValue(v) => v.lit,
        _ => panic!("expected helper=lit"),
    };
    let name_str = match name {
        syn::Lit::Str(s) => s,
        _ => panic!("expected string"),
    };
    let ty: syn::Type = name_str.parse().unwrap();  // KEY POINT HERE
    let ts = quote!{
        impl Foo for #ty {}
    };
    TokenStream::from(ts)
}
// A 2015-edition crate using the proc-macro "pmf".
#![warn(absolute_paths_not_starting_with_crate)]
extern crate pmf;

pub trait Foo {}

#[derive(pmf::Foo)]
#[helper = "::Bar"]
pub struct S;

pub struct Bar;

Results in:

warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
 --> tests/t1.rs:7:12
  |
7 | #[helper = "::Bar"]
  |            ^^^^^^^ help: use `crate`: `crate::"::Bar"`
  |

I think the key part here is that diesel is using syn to convert a token from a string to a Type, which is probably confusing rustc. I don't fully understand edition hygiene, so I'll leave it up to someone else to provide more detail. This seems like an unusual circumstance, and I really don't know how rustc should handle it.

@ehuss
Copy link
Contributor

ehuss commented Dec 17, 2019

should probably be bailing if the tokens pointed to aren't a valid type.

That's certainly an option, but the code will still be broken (because the string "::Bar" is still the wrong path in 2018), so cargo fix --edition would still fail.

@sgrif
Copy link
Contributor Author

sgrif commented Dec 17, 2019

Sure, but IMO leaving broken code is preferable to generating even more broken code

@sgrif
Copy link
Contributor Author

sgrif commented Dec 17, 2019

I can try to produce a more minimal repro if you'd like -- I opted not to upon reporting because it seems the root cause is pretty clear just from the behavior alone. (Granted it seems like your last comment has it, thank you!)

@JohnTitor JohnTitor added the C-bug Category: This is a bug. label Jan 19, 2020
@estebank estebank added the E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example label Mar 15, 2023
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Mar 16, 2023
Do not provide suggestions when the spans come from expanded code that doesn't point at user code

Hide invalid proc-macro suggestions and track spans
coming from proc-macros pointing at attribute.

Effectively, unless the proc-macro keeps user spans,
suggestions will not be produced for the code they
produce.

r? `@ghost`

Fix rust-lang#107113, fix rust-lang#107976, fix rust-lang#107977, fix rust-lang#108748, fix rust-lang#106720, fix rust-lang#90557.

Could potentially address rust-lang#50141, rust-lang#67373, rust-lang#55146, rust-lang#78862, rust-lang#74043, rust-lang#88514, rust-lang#83320, rust-lang#91520, rust-lang#104071. CC rust-lang#50122, rust-lang#76360.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Mar 17, 2023
Do not provide suggestions when the spans come from expanded code that doesn't point at user code

Hide invalid proc-macro suggestions and track spans
coming from proc-macros pointing at attribute.

Effectively, unless the proc-macro keeps user spans,
suggestions will not be produced for the code they
produce.

r? ``@ghost``

Fix rust-lang#107113, fix rust-lang#107976, fix rust-lang#107977, fix rust-lang#108748, fix rust-lang#106720, fix rust-lang#90557.

Could potentially address rust-lang#50141, rust-lang#67373, rust-lang#55146, rust-lang#78862, rust-lang#74043, rust-lang#88514, rust-lang#83320, rust-lang#91520, rust-lang#104071. CC rust-lang#50122, rust-lang#76360.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-edition-2018-lints Area: lints supporting the 2018 edition A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. C-bug Category: This is a bug. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants