-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Fix hygiene issues in declare_program!
and declare_loader!
#10905
Conversation
You can test this code with the upcoming hygiene changes as follows:
|
cc @jackcmay: It looks like you originally wrote the |
Thanks @Aaron1011 I'll take a look! |
It looks like CI doesn't like the FIXME comment I added. Should I open an issue to track switching to |
That would be great, thanks @Aaron1011 Btw, what brought our issue into your radar? |
@jackcmay: I've opened #10933 to track switching to
This crate regressed in a crater run when I was working on rust-lang/rust#72121. Fixing this crate should allow the rustc change to land with a minimum of ecosystem breakage. |
@Aaron1011 FYI, this PR should fix the CI failures: Aaron1011#1 |
@jackcmay: I've merged your PR |
The |
Which nightly do you suggest?
|
The most recent one as of today should be fine. If you'd like, I can find the earliest one that will work. |
We aren't picky about which nightly to depend on generally. If there's a known one that works we can just update https://github.com/solana-labs/solana/tree/master/ci/docker-rust-nightly to use it |
And https://github.com/solana-labs/solana/blob/master/ci/rust-version.sh @Aaron1011 you want to try one out in your PR? |
I've bumped CI to the latest nightly - that should allow this PR to compile on both the latest stable and nightly. |
@Aaron1011 FYI: Bumping our rust nightly involes releasing a new docker image. I'm in the process of that now, will ping you when ready. |
@Aaron1011 When bumping to 2020-07-08 nightly I see the following error: error: variable does not need to be mutable
--> runtime/src/message_processor.rs:1357:13
|
1357 | let mut accounts = vec![
| ----^^^^^^^^
| |
| help: remove this `mut`
|
= note: `-D unused-mut` implied by `-D warnings`
error: aborting due to previous error
error: could not compile `solana-runtime`. Source code is here: solana/runtime/src/message_processor.rs Line 1357 in f1c1152
Broken nightly? |
The nightly looks correct - it still compiles without We should be able to add |
75a5ba3
to
f2f7b69
Compare
I've fixed all local issues I've found (by running the CI script manually) |
automerge label removed due to a CI failure |
@jackcmay - check out the stable-perf build failure, do we need an update for xargo or some other bpf-sdk component?
|
Probably, upgrade of rust-bpf or we can modify our bpf sysroot. Or maybe do as the message suggests and add the crate attribute? |
This allows the rust-bpf-builder toolchain to build the sdk
I've conditionally applied |
It looks like the |
Yeah, it seems that.... @mvines Ok to merge this? Or should I wait to investigate something? |
Ah crap, Travis CI is being silly again. They continually flag PRs from new contributors as "abuse" because we're a blockchain and therefore must be trying to mine BTC/ETH on their CI machines 📉 Thanks so much for this PR @Aaron1011 |
This will need to be backported to the 1.2 and 1.1 branches if they are to continue compiling once the rustc change is merged. Should I open additional PRs, or is there a standard backporting process? |
@Aaron1011 - I think it's ok if 1.1 don't support the latest nightly, it'll be EOLed at the end of the month. v1.2 will live on for another couple months so that backport to that branch be useful, I initiated a backport |
…0905) (#11073) * Fix hygiene issues in `declare_program!` and `declare_loader!` The `declare_program!` and `declare_loader!` macros both expand to new macro definitions (based on the `$name` argument). These 'inner' macros make use of the special `$crate` metavariable to access items in the crate where the 'inner' macros is defined. However, this only works due to a bug in rustc. When a macro is expanded, all `$crate` tokens in its output are 'marked' as being resolved in the defining crate of that macro. An inner macro (including the body of its arms) is 'just' another set of tokens that appears in the body of the outer macro, so any `$crate` identifiers used there are resolved relative to the 'outer' macro. For example, consider the following code: ```rust macro_rules! outer { () => { macro_rules! inner { () => { $crate::Foo } } } } ``` The path `$crate::Foo` will be resolved relative to the crate that defines `outer`, **not** the crate which defines `inner`. However, rustc currently loses this extra resolution information (referred to as 'hygiene' information) when a crate is serialized. In the above example, this means that the macro `inner` (which gets defined in whatever crate invokes `outer!`) will behave differently depending on which crate it is invoked from: When `inner` is invoked from the same crate in which it is defined, the hygiene information will still be available, which will cause `$crate::Foo` to be resolved in the crate which defines 'outer'. When `inner` is invoked from a different crate, it will be loaded from the metadata of the crate which defines 'inner'. Since the hygiene information is currently lost, rust will 'forget' that `$crate::Foo` is supposed to be resolved in the context of 'outer'. Instead, it will be resolved relative to the crate which defines 'inner', which can cause incorrect code to compile. This bug will soon be fixed in rust (see rust-lang/rust#72121), which will break `declare_program!` and `declare_loader!`. Fortunately, it's possible to obtain the desired behavior (`$crate` resolving in the context of the 'inner' macro) by use of a procedural macro. This commit adds a `respan!` proc-macro to the `sdk/macro` crate. Using the newly-stabilized (on Nightly) `Span::resolved_at` method, the `$crate` identifier can be made to be resolved in the context of the proper crate. Since `Span::resolved_at` is only stable on the latest nightly, referencing it on an earlier version of Rust will cause a compilation error. This requires the `rustversion` crate to be used, which allows conditionally compiling code epending on the Rust compiler version in use. Since this method is already stabilized in the latest nightly, there will never be a situation where the hygiene bug is fixed (e.g. rust-lang/rust#72121) is merged but we are unable to call `Span::resolved_at`. (cherry picked from commit 05445c7) # Conflicts: # Cargo.lock # sdk/Cargo.toml * Replace FIXME with an issue link (cherry picked from commit b0cb2b0) * Update lock files (cherry picked from commit 42f8848) # Conflicts: # programs/bpf/Cargo.lock # programs/librapay/Cargo.lock # programs/move_loader/Cargo.lock * Split comment over multiple lines Due to rust-lang/rustfmt#4325, leaving this as one line causes rustfmt to add extra indentation to the surrounding code. (cherry picked from commit fed69e9) * Fix clippy lints (cherry picked from commit e7387f6) * Apply #![feature(proc_macro_hygiene)] when needed This allows the rust-bpf-builder toolchain to build the sdk (cherry picked from commit 95490ff) # Conflicts: # sdk/build.rs # sdk/src/lib.rs * Update Cargo.toml * Update lib.rs * Add rustc_version * lock file updates Co-authored-by: Aaron Hill <[email protected]> Co-authored-by: Jack May <[email protected]> Co-authored-by: Michael Vines <[email protected]>
// See https://github.com/solana-labs/solana/issues/11055 | ||
// We may be running the custom `rust-bpf-builder` toolchain, | ||
// which currently needs `#![feature(proc_macro_hygiene)]` to | ||
// be applied. | ||
println!("cargo:rustc-cfg=RUSTC_NEEDS_PROC_MACRO_HYGIENE"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here (context: anza-xyz#109 (comment))
The
declare_program!
anddeclare_loader!
macros both expand tonew macro definitions (based on the
$name
argument). These 'inner'macros make use of the special
$crate
metavariable to access items inthe crate where the 'inner' macros is defined.
However, this only works due to a bug in rustc. When a macro is
expanded, all
$crate
tokens in its output are 'marked' as beingresolved in the defining crate of that macro. An inner macro (including
the body of its arms) is 'just' another set of tokens that appears in
the body of the outer macro, so any
$crate
identifiers used there areresolved relative to the 'outer' macro.
For example, consider the following code:
The path
$crate::Foo
will be resolved relative to the crate that definesouter
,not the crate which defines
inner
.However, rustc currently loses this extra resolution information
(referred to as 'hygiene' information) when a crate is serialized.
In the above example, this means that the macro
inner
(which getsdefined in whatever crate invokes
outer!
) will behave differentlydepending on which crate it is invoked from:
When
inner
is invoked from the same crate in which it is defined,the hygiene information will still be available,
which will cause
$crate::Foo
to be resolved in the crate which defines 'outer'.When
inner
is invoked from a different crate, it will be loaded fromthe metadata of the crate which defines 'inner'. Since the hygiene
information is currently lost, rust will 'forget' that
$crate::Foo
issupposed to be resolved in the context of 'outer'. Instead, it will be
resolved relative to the crate which defines 'inner', which can cause
incorrect code to compile.
This bug will soon be fixed in rust (see rust-lang/rust#72121),
which will break
declare_program!
anddeclare_loader!
. Fortunately,it's possible to obtain the desired behavior (
$crate
resolving in thecontext of the 'inner' macro) by use of a procedural macro.
This commit adds a
respan!
proc-macro to thesdk/macro
crate.Using the newly-stabilized (on Nightly)
Span::resolved_at
method,the
$crate
identifier can be made to be resolved in the context of theproper crate.
Since
Span::resolved_at
is only stable on the latest nightly,referencing it on an earlier version of Rust will cause a compilation error.
This requires the
rustversion
crate to be used, which allows conditionallycompiling code epending on the Rust compiler version in use. Since this method is already
stabilized in the latest nightly, there will never be a situation where
the hygiene bug is fixed (e.g. rust-lang/rust#72121)
is merged but we are unable to call
Span::resolved_at
.