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

decl_macro: imports don't work in cross-crate invocations #42337

Closed
tikue opened this issue May 31, 2017 · 3 comments
Closed

decl_macro: imports don't work in cross-crate invocations #42337

tikue opened this issue May 31, 2017 · 3 comments
Assignees
Labels
A-macros-2.0 Area: Declarative macros 2.0 (#39412) C-bug Category: This is a bug.

Comments

@tikue
Copy link
Contributor

tikue commented May 31, 2017

Minimal reproduction:

// src/lib.rs
#![feature(decl_macro)]

pub macro use_fmt {
    () => {
        use std::fmt;
    }
}

// examples/test.rs
#![feature(use_extern_macros)]

extern crate macro_test;

use macro_test::use_fmt;

use_fmt!();

fn main() {}
The error:
$ cargo build --example test
   Compiling macro-test v0.1.0 (file:///.../macro-test)
error[E0432]: unresolved import `std::fmt`
 --> examples/test.rs:7:1
  |
7 | use_fmt!();
  | ^^^^^^^^^^^ Could not find `std` in `{{root}}`
  |
  = note: this error originates in a macro outside of the current crate

error: aborting due to previous error(s)

error: Could not compile `macro-test`.

Invoking the macro in the same crate as it's defined works as expected.

cc @jseyfried

@jseyfried jseyfried self-assigned this May 31, 2017
@Mark-Simulacrum Mark-Simulacrum added the A-macros-2.0 Area: Declarative macros 2.0 (#39412) label Jun 23, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 27, 2017
@jseyfried
Copy link
Contributor

Sorry for the delay getting to this. Fixed in #46419.

@antoyo
Copy link
Contributor

antoyo commented Dec 9, 2017

I don't know if it is the same issue (and if the PR fixed it), but I get the same error with proc_macro.
Here's a minimal example to reproduce this issue.
Is it the same issue?
When I run cargo build, I get the following errors:

error[E0433]: failed to resolve. Could not find `postgres` in `{{root}}`
 --> src/lib.rs:9:17
  |
9 | #[derive(Debug, SqlTable)]
  |                 ^^^^^^^^ Could not find `postgres` in `{{root}}`

error[E0433]: failed to resolve. Could not find `std` in `{{root}}`
 --> src/lib.rs:9:17
  |
9 | #[derive(Debug, SqlTable)]
  |                 ^^^^^^^^ Could not find `std` in `{{root}}`

error[E0412]: cannot find type `Table` in this scope
 --> src/lib.rs:9:17
  |
9 | #[derive(Debug, SqlTable)]
  |                 ^^^^^^^^ not found in this scope
help: possible candidate is found in another module, you can import it into scope
  |
3 | use Table;
  |

Is there any workaround for this issue?
Thank you.

bors added a commit that referenced this issue Dec 13, 2017
Record all imports (`use`, `extern crate`) in the crate metadata

This PR adds non-`pub` `use` and `extern crate` imports in the crate metadata since hygienic macros invoked in other crates may use them. We already include all other non-`pub` items in the crate metadata. This improves import suggestions in some cases.

Fixes #42337.

r? @nrc
@jseyfried
Copy link
Contributor

jseyfried commented Dec 17, 2017

@antoyo This is a consequence of hygiene.

Since ::postgres::types::Type is at the proc-macro definition, it resolve in the scope of the macro definition. In particular, it will resolve the same no matter where the macro is invoked.

There is no extern crate postgres; at the proc-macro crate root, so you get a resolution error. Just adding extern crate postgres; to the proc-macro crate root isn't sufficient either, however, since proc-macro dependencies are compiled for the host platform (phase 0), not the target platform (phase 1) and so the expansion can't see them.

The solution here is to add target dependencies to proc-macro crates as described in #45934 (comment).

For now, you need to put an extern crate postgres; in the macro expansion. Due to hygiene, this won't conflict with anything named postgres at the invocation site, won't effect the resolution of the macro's arguments, etc. For example:

            quote! {
                extern crate std;
                extern crate postgres;
                use std::io::Write;
                use postgres::types::{IsNull, ToSql, Type};

                impl ToSql for #table_ident {
                    fn to_sql<W: Write + ?Sized>(&self, ty: &Type, out: &mut W) -> postgres::Result<IsNull> {
                        self.#primary_key_ident.to_sql(ty, out)
                    }

                    fn accepts(ty: &Type) -> bool {
                        match *ty {
                            Type::Int4 => true,
                            _ => false,
                        }
                    }

                    fn to_sql_checked(&self, ty: &Type, out: &mut Write) -> postgres::Result<IsNull> {
                        if !<Self as ToSql>::accepts(ty) {
                            return Err(postgres::error::Error::WrongType(ty.clone()));
                        }
                        self.to_sql(ty, out)
                    }
                }
            }

Alternatively, you can make ::postgres::types::Type resolve at the call site (unhygienically) by giving it Span::call_site() (tokens from quote! have Span::def_site() by default). Soon, spanned_quote!(span, tokens...) will make this easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros-2.0 Area: Declarative macros 2.0 (#39412) C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants