diff --git a/Cargo.lock b/Cargo.lock index 5933b08b76b932..89088220dfc61b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3250,6 +3250,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustversion" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" +dependencies = [ + "proc-macro2 1.0.17", + "quote 1.0.6", + "syn 1.0.27", +] + [[package]] name = "rusty-fork" version = "0.2.2" @@ -3772,6 +3783,7 @@ dependencies = [ "num-derive 0.3.0", "num-traits", "rand 0.7.3", + "rustversion", "solana-runtime", "solana-sdk 1.3.0", "solana_rbpf", @@ -4639,6 +4651,7 @@ dependencies = [ "rand 0.7.3", "rand_chacha 0.2.2", "rustc_version", + "rustversion", "serde", "serde_bytes", "serde_derive", @@ -4671,6 +4684,7 @@ dependencies = [ "bs58 0.3.1", "proc-macro2 1.0.17", "quote 1.0.6", + "rustversion", "syn 1.0.27", ] diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 555a93cbe27c3c..253b4470c081c8 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -1278,6 +1278,16 @@ dependencies = [ "webpki 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustversion" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ryu" version = "1.0.4" @@ -1710,6 +1720,7 @@ dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1729,6 +1740,7 @@ dependencies = [ "bs58 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2554,6 +2566,7 @@ dependencies = [ "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1" +"checksum rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" "checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index b31039a9146fea..74eb549e991856 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -21,6 +21,7 @@ thiserror = "1.0" [dev-dependencies] rand = "0.7.3" +rustversion = "1.0.3" [lib] crate-type = ["lib", "cdylib"] diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 456f516db04170..41d48d0c02ce5d 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -340,6 +340,14 @@ mod tests { } } + #[rustversion::since(1.46.0)] + #[test] + fn test_bpf_loader_same_crate() { + // Ensure that we can invoke this macro from the same crate + // where it is defined. + solana_bpf_loader_program!(); + } + #[test] #[should_panic(expected = "ExceededMaxInstructions(10)")] fn test_bpf_loader_non_terminating_program() { diff --git a/programs/librapay/Cargo.lock b/programs/librapay/Cargo.lock index ea54971512251d..4924e39c3c5bf0 100644 --- a/programs/librapay/Cargo.lock +++ b/programs/librapay/Cargo.lock @@ -2139,6 +2139,16 @@ dependencies = [ "webpki 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustversion" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rusty-fork" version = "0.2.2" @@ -2540,6 +2550,7 @@ dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2559,6 +2570,7 @@ dependencies = [ "bs58 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4040,6 +4052,7 @@ dependencies = [ "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1" +"checksum rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" "checksum rusty-fork 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" "checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" diff --git a/programs/move_loader/Cargo.lock b/programs/move_loader/Cargo.lock index fa1ed3d20d5060..0368dc0883ba70 100644 --- a/programs/move_loader/Cargo.lock +++ b/programs/move_loader/Cargo.lock @@ -2214,6 +2214,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustversion" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" +dependencies = [ + "proc-macro2 1.0.17", + "quote 1.0.6", + "syn 1.0.27", +] + [[package]] name = "rusty-fork" version = "0.2.2" @@ -2532,6 +2543,7 @@ dependencies = [ "rand 0.7.3", "rand_chacha 0.2.2", "rustc_version", + "rustversion", "serde", "serde_bytes", "serde_derive", @@ -2551,6 +2563,7 @@ dependencies = [ "bs58 0.3.1", "proc-macro2 1.0.17", "quote 1.0.6", + "rustversion", "syn 1.0.27", ] diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index f17dc4de4a030f..cb1dc7dfe91308 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -55,6 +55,7 @@ solana-crate-features = { path = "../crate-features", version = "1.3.0", optiona solana-logger = { path = "../logger", version = "1.3.0", optional = true } solana-sdk-macro = { path = "macro", version = "1.3.0" } solana-sdk-macro-frozen-abi = { path = "macro-frozen-abi", version = "1.3.0" } +rustversion = "1.0.3" [dev-dependencies] tiny-bip39 = "0.7.0" diff --git a/sdk/build.rs b/sdk/build.rs index e17ca70cb4718b..c9550c1c5c4f22 100644 --- a/sdk/build.rs +++ b/sdk/build.rs @@ -17,6 +17,11 @@ fn main() { } Channel::Dev => { println!("cargo:rustc-cfg=RUSTC_WITH_SPECIALIZATION"); + // 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"); } } } diff --git a/sdk/macro/Cargo.toml b/sdk/macro/Cargo.toml index 50c8234974f0d2..839e88f842db7e 100644 --- a/sdk/macro/Cargo.toml +++ b/sdk/macro/Cargo.toml @@ -16,6 +16,7 @@ bs58 = "0.3.0" proc-macro2 = "1.0" quote = "1.0" syn = { version = "1.0", features = ["full", "extra-traits"] } +rustversion = "1.0.3" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/sdk/macro/src/lib.rs b/sdk/macro/src/lib.rs index e58d9b4319f679..5146f3ed301484 100644 --- a/sdk/macro/src/lib.rs +++ b/sdk/macro/src/lib.rs @@ -5,7 +5,7 @@ extern crate proc_macro; use proc_macro::TokenStream; -use proc_macro2::Span; +use proc_macro2::{Delimiter, Span, TokenTree}; use quote::{quote, ToTokens}; use std::convert::TryFrom; use syn::{ @@ -14,7 +14,7 @@ use syn::{ parse_macro_input, punctuated::Punctuated, token::Bracket, - Expr, Ident, LitByte, LitStr, Token, + Expr, Ident, LitByte, LitStr, Path, Token, }; struct Id(proc_macro2::TokenStream); @@ -63,6 +63,75 @@ impl ToTokens for Id { } } +#[allow(dead_code)] // `respan` may be compiled out +struct RespanInput { + to_respan: Path, + respan_using: Span, +} + +impl Parse for RespanInput { + fn parse(input: ParseStream) -> Result { + let to_respan: Path = input.parse()?; + let _comma: Token![,] = input.parse()?; + let respan_tree: TokenTree = input.parse()?; + match respan_tree { + TokenTree::Group(g) if g.delimiter() == Delimiter::None => { + let ident: Ident = syn::parse2(g.stream())?; + Ok(RespanInput { + to_respan, + respan_using: ident.span(), + }) + } + val => Err(syn::Error::new_spanned( + val, + "expected None-delimited group", + )), + } + } +} + +/// A proc-macro which respans the tokens in its first argument (a `Path`) +/// to be resolved at the tokens of its second argument. +/// For internal use only. +/// +/// There must be exactly one comma in the input, +/// which is used to separate the two arguments. +/// The second argument should be exactly one token. +/// +/// For example, `respan!($crate::foo, with_span)` +/// produces the tokens `$crate::foo`, but resolved +/// at the span of `with_span`. +/// +/// The input to this function should be very short - +/// its only purpose is to override the span of a token +/// sequence containing `$crate`. For all other purposes, +/// a more general proc-macro should be used. +#[rustversion::since(1.46.0)] // `Span::resolved_at` is stable in 1.46.0 and above +#[proc_macro] +pub fn respan(input: TokenStream) -> TokenStream { + // Obtain the `Path` we are going to respan, and the ident + // whose span we will be using. + let RespanInput { + to_respan, + respan_using, + } = parse_macro_input!(input as RespanInput); + // Respan all of the tokens in the `Path` + let to_respan: proc_macro2::TokenStream = to_respan + .into_token_stream() + .into_iter() + .map(|mut t| { + // Combine the location of the token with the resolution behavior of `respan_using` + // Note: `proc_macro2::Span::resolved_at` is currently gated with cfg(procmacro2_semver_exempt) + // Once this gate is removed, we will no longer need to use 'unwrap()' to call + // the underling `proc_macro::Span::resolved_at` method. + let new_span: Span = t.span().unwrap().resolved_at(respan_using.unwrap()).into(); + t.set_span(new_span); + t + }) + .collect(); + TokenStream::from(to_respan) +} + #[proc_macro] pub fn declare_id(input: TokenStream) -> TokenStream { let id = parse_macro_input!(input as Id); diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index 04ecd3b0d64fdb..c0a100aefc10fd 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -30,6 +30,63 @@ pub type LoaderEntrypoint = unsafe extern "C" fn( invoke_context: &dyn InvokeContext, ) -> Result<(), InstructionError>; +#[rustversion::since(1.46.0)] +#[macro_export] +macro_rules! declare_name { + ($name:ident) => { + #[macro_export] + macro_rules! $name { + () => { + // Subtle: + // The outer `declare_name!` macro may be expanded in another + // crate, causing the macro `$name!` to be defined in that + // crate. We want to emit a call to `$crate::id()`, and have + // `$crate` be resolved in the crate where `$name!` gets defined, + // *not* in this crate (where `declare_name! is defined). + // + // When a macro_rules! macro gets expanded, any $crate tokens + // in its output will be 'marked' with the crate they were expanded + // from. This includes nested macros like our macro `$name` - even + // though it looks like a separate macro, Rust considers it to be + // just another part of the output of `declare_program!`. + // + // We pass `$name` as the second argument to tell `respan!` to + // apply use the `Span` of `$name` when resolving `$crate::id`. + // This causes `$crate` to behave as though it was written + // at the same location as the `$name` value passed + // to `declare_name!` (e.g. the 'foo' in + // `declare_name(foo)` + // + // See the `respan!` macro for more details. + // This should use `crate::respan!` once + // https://github.com/rust-lang/rust/pull/72121 is merged: + // see https://github.com/solana-labs/solana/issues/10933. + // For now, we need to use `::solana_sdk` + // + // `respan!` respans the path `$crate::id`, which we then call (hence the extra + // parens) + ( + stringify!($name).to_string(), + ::solana_sdk::respan!($crate::id, $name)(), + ) + }; + } + }; +} + +#[rustversion::not(since(1.46.0))] +#[macro_export] +macro_rules! declare_name { + ($name:ident) => { + #[macro_export] + macro_rules! $name { + () => { + (stringify!($name).to_string(), $crate::id()) + }; + } + }; +} + /// Convenience macro to declare a native program /// /// bs58_string: bs58 string representation the program's id @@ -102,13 +159,7 @@ pub type LoaderEntrypoint = unsafe extern "C" fn( macro_rules! declare_program( ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( $crate::declare_id!($bs58_string); - - #[macro_export] - macro_rules! $name { - () => { - (stringify!($name).to_string(), $crate::id()) - }; - } + $crate::declare_name!($name); #[no_mangle] pub extern "C" fn $name( @@ -126,13 +177,9 @@ macro_rules! declare_program( macro_rules! declare_loader( ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( $crate::declare_id!($bs58_string); + $crate::declare_name!($name); + - #[macro_export] - macro_rules! $name { - () => { - (stringify!($name).to_string(), $crate::id()) - }; - } #[no_mangle] pub extern "C" fn $name( diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 99c3b7098f9e21..12fbe3909aec1c 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(specialization))] +#![cfg_attr(RUSTC_NEEDS_PROC_MACRO_HYGIENE, feature(proc_macro_hygiene))] // Allows macro expansion of `use ::solana_sdk::*` to work within this crate extern crate self as solana_sdk; @@ -67,6 +68,8 @@ pub mod timing; /// ``` pub use solana_sdk_macro::declare_id; pub use solana_sdk_macro::pubkeys; +#[rustversion::since(1.46.0)] +pub use solana_sdk_macro::respan; // On-chain program specific modules pub mod account_info;