Repository navigation
Description
Updated description
The following procedural macro:
#![feature(proc_macro)]
extern crate proc_macro;
use proc_macro::*;
#[proc_macro]
pub fn foo(input: TokenStream) -> TokenStream {
let mut body = Vec::<TokenTree>::new();
// input = `let a = 2;`
body.extend(input.into_iter());
// manually add `let b = a;`
body.push(Term::new("let", Span::call_site()).into());
body.push(Term::new("b", Span::call_site()).into());
body.push(Op::new('=', Spacing::Alone).into());
body.push(Term::new("a", Span::call_site()).into());
body.push(Op::new(';', Spacing::Alone).into());
// parse and add `let c = b;`
body.extend("let c = b;".parse::<TokenStream>().unwrap().into_iter());
let mut ret = Vec::<TokenTree>::new();
ret.push(Term::new("fn", Span::call_site()).into());
ret.push(Term::new("main", Span::call_site()).into());
ret.push(Group::new(Delimiter::Parenthesis, TokenStream::empty()).into());
ret.push(Group::new(Delimiter::Brace, body.into_iter().collect()).into());
ret.into_iter().collect()
}fails when invoked as:
#![feature(proc_macro)]
extern crate foo;
foo::foo! {
let a = 3;
}with the error message:
error[E0425]: cannot find value `b` in this scope
--> src/main.rs:6:1
|
6 | / foo::foo! {
7 | | let a = 3;
8 | | }
| |_^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.
Original description
Linking the futures-await crate and a crate that useserror-chain-derive together breaks the build. Here's a simple example: https://github.com/golddranks/test_futures_await_error_chain_derive Either of the two dependencies (futures-await and dotenv, which uses error-chain-derive) builds on its own (using the latest nightly), but together they refuse to build.
This seems to have something to do with the defsite hygiene: error-chain-derive is using derive macros 1.1, and the syntax for using it is as follows: (from https://github.com/purpliminal/rust-dotenv/blob/master/src/errors.rs )
#[derive(Debug, ErrorChain)]
#[cfg_attr(not(feature = "backtrace"), error_chain(backtrace = "false"))]
pub enum ErrorKind {
// generic error string, required by derive_error_chain
Msg(String),
#[error_chain(custom)]
#[error_chain(description = r#"|_| "Parsing Error""#)]
#[error_chain(display = r#"|l| write!(f, "Error parsing line: '{}'", l)"#)]
LineParse(String),
#[error_chain(foreign)]
Io(::std::io::Error),
#[error_chain(foreign)]
EnvVar(::std::env::VarError),
}
|l| write!(f, "Error parsing line: '{}'", l) breaks, because it can't find f: cannot find value f in this scope
It seems like just the presence of futures-await somehow affects how the Derive macros 1.1 hygiene works; however, the derive macros are stable, so this is an undesirable thing.
Activity
golddranks commentedon Apr 19, 2018
Looking at the symptoms, likely to be the same bug as #50061
golddranks commentedon May 1, 2018
This still happens on the latest nightly (
79252ff4e 2018-04-29), even after the patches #50152 and alexcrichton@e934873 landed.golddranks commentedon May 1, 2018
Ping @petrochenkov @alexcrichton
[-]Only the presence of futures-await regresses error-chain-derive[/-][+]TokenStream::parse does not resolve with Span::call_site()[/+]alexcrichton commentedon May 1, 2018
I've updated the OP and issue title to reflect the underlying issue, minimized at https://gist.github.com/alexcrichton/6b4c56549c6732e697eb0aa9986bf398.
The tl;dr; is that a
TokenStreamcreated throughTokenStream::from_str(aka parsing code) cannot refer to tokens with the spanSpan::call_site()(nor tokens input to the macro itself). This means that for whatever reason the hygienic context applied to tokens created through parsing strings is different than that ofSpan::call_site, exposing "oddness" of hygiene.@petrochenkov or @nrc, do y'all know where this might be occurring?
petrochenkov commentedon May 1, 2018
@alexcrichton
A guess: this may be a regression from changes in
src/libsyntax/ext/quote.rsin #49154 (DUMMY_SP->ident.spanforast::Identandast::Lifetime).Could you test whether reverting changes in those two lines fixes the regression?
If it doesn't, then I'll try to investigate further sometime during this week.
alexcrichton commentedon May 2, 2018
Sure yeah, I will test out that hypothesis tomorrow morning!
alexcrichton commentedon May 2, 2018
Ah unfortunately this diff on 5a662bf produced the same error:
jan-hudec commentedon May 9, 2018
@alexcrichton,
I am probably missing something, but to me it sounds about right. I would expect manually parsed code to be its own context. That's the hygiene. Similar to literal code in template macros, except proc macros don't have definition site, so the context is simply fresh. To refer to the symbol from the call site, you can replace it with the
Tokenfrom input or manually created withSpan::call_site(), no?alexcrichton commentedon May 9, 2018
@jan-hudec I think you're right yeah, but the problem is that we've been advocating Macros 1.1 and 1.2 as "hygiene comes later, we're just copy/pasting code". That seems to not be the case and there's actual hygiene involved, which is unintended currently
jan-hudec commentedon May 9, 2018
Except if
parse::<TokenStream>is now made unhygienic, making it hygienic later won't be backward compatible. So it can't be as easy as just copy/pasting code.alexcrichton commentedon May 9, 2018
@jan-hudec oh it was always the intention that stringifcation loses all hygiene information. The upcoming
proc_macroAPI is how we'll allow adding hygiene in the future (aka viaSpan)9 remaining items
petrochenkov commentedon May 21, 2018
If I won't be able to implement
MarkKind::Transparent(or something equivalent) quickly enough, I'll open a PR with that patch.alexcrichton commentedon May 21, 2018
Ok awesome, thanks @petrochenkov!
petrochenkov commentedon May 30, 2018
Status update: I started working on
MarkKind::Transparentand have more detailed understanding of how it should work now, but tomorrow I'm leaving on vacation so finishing this work is going to be postponed for 1-2 weeks.petrochenkov commentedon Jun 19, 2018
Some status update: I have an implementation for
MarkKind::Transparentand it works by itself and interacts with "opaque"/"modern" macros (declarativemacroor proceduralSpan::def_site()) correctly, but interactions withmacro_rulesare buggy.In particular stuff like this:
generates an "unresolved
x" error while it shouldn'tSo far it looks like I need to really dig into the core hygiene/resolution algorithms to fix this properly, perhaps by refactoring hygiene data in some way in which these opaque/transparent/semi-transparent interactions can be expressed more naturally than the current "syntax context transplantation" technique (see the large comment in
fn apply_mark).In the meantime I'll probably just sumbit a PR with the buggy version this weekend.
petrochenkov commentedon Jun 24, 2018
#51762 is submitted.
(It has the "transparent vs
macro_rules" issue mentioned in the previous comment fixed.)Rollup merge of rust-lang#51762 - petrochenkov:oh-hi-mark, r=oli-obk
SergioBenitez commentedon Jul 8, 2018
Is this fully fixed? We're still seeing issues on rwf2/Rocket#635, and I can also externally confirm that I'm seeing similar issues with other proc-macro/macro interactions.
petrochenkov commentedon Jul 8, 2018
@SergioBenitez
The issue as described in #50050 (comment) is fully fixed and the the snippet from the issue description now works.
There can be other issues, of course, please file a separate ticket with minimized reproduction if something looks like a bug.