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

Unexpected compilation error via a combination of binary dependencies, proc macros, crate features, and the target key #10525

Closed
Tracked by #10061
bstrie opened this issue Mar 30, 2022 · 2 comments · Fixed by #11478
Labels
A-features2 Area: issues specifically related to the v2 feature resolver C-bug Category: bug Z-bindeps Nightly: binary artifact dependencies

Comments

@bstrie
Copy link
Contributor

bstrie commented Mar 30, 2022

Here's a tricky failure distilled from a real-world codebase. I've aggressively minimized the reproduction (including each of the individual dependencies; no remote dependencies remain); everything remaining is seemingly necessary to reproduce the failure (crate, item, and feature names have been preserved for easy comparison with the original).

Overview of the minimized dependency graph:

flowchart TD
    mycrate-- "artifact = #quot;bin#quot;\ntarget = #quot;x86_64-unknown-linux-gnu#quot;" -->mybindep
    mycrate-->A["structopt-derive\n(proc macro)"]
    mybindep-->B["clap_derive\n(proc macro)"]
    B["clap_derive\n(proc macro)"]-->proc-macro-error
    A["structopt-derive\n(proc macro)"]-- "features = [#quot;parsing#quot;]" -->syn
    A["structopt-derive\n(proc macro)"]-->proc-macro-error
    proc-macro-error-->syn

I've published the minimized repo here: https://github.com/bstrie/bindeperror1 .

For completeness, here's a branch with the maximized reproduction in the original codebase: https://github.com/bstrie/enarx/tree/bindeperror1 (revert the last commit to observe the code compiles properly; if testing fixes against this branch be sure to remove the rust-toolchain file).

For posterity I've inlined the minimized repo at the bottom of this issue.

The code in question should compile. Instead, cargo build produces the following error:

error[E0599]: the method `unwrap_or_abort` exists for enum `Result<(), syn::Error>`, but its trait bounds were not satisfied
   --> structopt-derive/src/lib.rs:4:30
    |
4   |     Ok::<(), syn::Error>(()).unwrap_or_abort()
    |                              ^^^^^^^^^^^^^^^
    |
   ::: /home/ben/code/scrap/bindeperror1/syn/src/lib.rs:1:1
    |
1   | pub struct Error;
    | ----------------- doesn't satisfy `syn::Error: Into<proc_macro_error::Diagnostic>`
    |
   ::: /home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:504:1
    |
504 | pub enum Result<T, E> {
    | --------------------- doesn't satisfy `Result<(), syn::Error>: ResultExt<()>`
    |
    = note: the following trait bounds were not satisfied:
            `syn::Error: Into<proc_macro_error::Diagnostic>`
            which is required by `Result<(), syn::Error>: ResultExt<()>`

warning: unused import: `proc_macro_error::ResultExt`
 --> structopt-derive/src/lib.rs:1:5
  |
1 | use proc_macro_error::ResultExt;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

For more information about this error, try `rustc --explain E0599`.

Interestingly, all of the following will cause the code to compile successfully:

  1. Removing the target key in mycrate's Cargo.toml, i.e.:
    - mybindep = { path = "mybindep", artifact = "bin", target = "x86_64-unknown-linux-gnu" }
    + mybindep = { path = "mybindep", artifact = "bin" }
    causes the code to compile. This is extremely curious because the host machine is x86_64-unknown-linux-gnu, so conceptually this should be a no-op. Furthermore, since these crates are proc macros, they should already be targeting the host regardless of the value of the target field. Any other value in the target field (e.g. x86_64-unknown-linux-musl) produces the same error, so it is the presence of this key that is essential.
  2. Removing the features key in structopt-derive's Cargo.toml, i.e.:
    - syn = { path = "../syn", features = ["parsing"] }
    + syn = { path = "../syn" }
    causes the code to compile. Note that in our minimized syn crate this feature is completely vestigial and has no behavior at all.
  3. Making both mycrate and mybindep rely on the same proc macro crate. This demonstrates that there's nothing problematic about structopt-derive or clap_derive in isolation, and that this error only occurs when they're both present.

Output of cargo version --verbose:

cargo 1.61.0-nightly (109bfbd 2022-03-17)
release: 1.61.0-nightly
commit-hash: 109bfbd055325ef87a6e7f63d67da7e838f8300b
commit-date: 2022-03-17
host: x86_64-unknown-linux-gnu
libgit2: 1.4.2 (sys:0.14.2 vendored)
libcurl: 7.80.0-DEV (sys:0.4.51+curl-7.80.0 vendored ssl:OpenSSL/1.1.1m)
os: Pop!_OS 21.10 (impish) [64-bit]

cc @Byron

Code for reference:


# Cargo.toml
[package]
name = "mycrate"
version = "0.0.0"
edition = "2021"

[dependencies]
structopt-derive = { path = "structopt-derive" }
mybindep = { path = "mybindep", artifact = "bin", target = "x86_64-unknown-linux-gnu" }
// src/main.rs
fn main() {
    env!("CARGO_BIN_FILE_MYBINDEP");
}
# mybindep/Cargo.toml
[package]
name = "mybindep"
version = "0.0.0"
edition = "2021"

[dependencies]
clap_derive = { path = "../clap_derive" }
// mybindep/src/main.rs
fn main() {}
# clap_derive/Cargo.toml
[package]
name = "clap_derive"
version = "0.0.0"
edition = "2021"

[dependencies]
proc-macro-error = { path = "../proc-macro-error" }

[lib]
proc-macro = true
// clap_derive/src/lib.rs
# structopt-derive/Cargo.toml
[package]
name = "structopt-derive"
version = "0.0.0"
edition = "2021"

[dependencies]
syn = { path = "../syn", features = ["parsing"] }
proc-macro-error = { path = "../proc-macro-error" }

[lib]
proc-macro = true
// structopt-derive/src/lib.rs
use proc_macro_error::ResultExt;

fn _parse_structopt_attributes() {
    Ok::<(), syn::Error>(()).unwrap_or_abort()
}
# proc-macro-error/Cargo.toml
[package]
name = "proc-macro-error"
version = "0.0.0"
edition = "2021"

[dependencies]
syn = { path = "../syn" }
// proc-macro-error/src/lib.rs
pub trait ResultExt<T> {
    fn unwrap_or_abort(self) -> T;
}

impl<T, E: Into<Diagnostic>> ResultExt<T> for Result<T, E> {
    fn unwrap_or_abort(self) -> T {
        panic!()
    }
}

pub struct Diagnostic;

impl From<syn::Error> for Diagnostic {
    fn from(_: syn::Error) -> Self {
        panic!()
    }
}
# syn/Cargo.toml
[package]
name = "syn"
version = "0.0.0"
edition = "2021"

[features]
parsing = []
// syn/src/lib.rs
pub struct Error;

@ehuss ehuss added the Z-bindeps Nightly: binary artifact dependencies label Mar 30, 2022
@bstrie bstrie changed the title Unexpected compilation error via a combination of binary dependencies, proc macros, crate features, and the "target" key Unexpected compilation error via a combination of binary dependencies, proc macros, crate features, and the target key Mar 31, 2022
@Aaron1011
Copy link
Member

The compile error appears to be caused by multiple versions of syn being loaded when compiling structopt-derive:

INFO rustc_metadata::locator rmeta reading metadata from: /home/aaron/repos/issues-rust/bindeperror1/target/debug/deps/libsyn-2b1591d12268f0b6.rmeta
INFO rustc_metadata::locator rlib reading metadata from: /home/aaron/repos/issues-rust/bindeperror1/target/debug/deps/libsyn-c1e6239ec3cf07e2.rlib

One syn::Error gets used when trying to resolve syn::Error: Into<proc_macro_error::Diagnostic>, but the other syn::Error is used in the corresponding impl - therefore, they don't match.

@bstrie
Copy link
Contributor Author

bstrie commented Jul 9, 2022

Anyone interested in this should note that I've just discovered another bug that's similar, yet different in a few key ways: #10837

@weihanglo weihanglo added C-bug Category: bug A-features2 Area: issues specifically related to the v2 feature resolver labels Oct 4, 2022
bstrie added a commit to bstrie/cargo that referenced this issue Dec 15, 2022
bstrie added a commit to bstrie/cargo that referenced this issue Dec 15, 2022
bstrie added a commit to bstrie/cargo that referenced this issue Dec 15, 2022
rvolosatovs pushed a commit to rvolosatovs/cargo that referenced this issue Dec 16, 2022
rvolosatovs pushed a commit to rvolosatovs/cargo that referenced this issue Dec 19, 2022
rvolosatovs added a commit to rvolosatovs/cargo that referenced this issue Dec 19, 2022
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs added a commit to rvolosatovs/cargo that referenced this issue Dec 19, 2022
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs added a commit to rvolosatovs/cargo that referenced this issue Dec 19, 2022
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs added a commit to rvolosatovs/cargo that referenced this issue Dec 19, 2022
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs pushed a commit to rvolosatovs/cargo that referenced this issue Dec 22, 2022
rvolosatovs added a commit to rvolosatovs/cargo that referenced this issue Dec 22, 2022
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
@bors bors closed this as completed in 2381cbd Dec 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-features2 Area: issues specifically related to the v2 feature resolver C-bug Category: bug Z-bindeps Nightly: binary artifact dependencies
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants