diff --git a/Cargo.lock b/Cargo.lock index ce72a8bf02..dc2fbb0c8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3295,6 +3295,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.18", + "quote 1.0.7", + "syn 1.0.33", +] + [[package]] name = "rusty-fork" version = "0.2.2" @@ -3824,6 +3835,7 @@ dependencies = [ "num-derive 0.3.0", "num-traits", "rand 0.7.3", + "rustversion", "solana-logger", "solana-runtime", "solana-sdk 1.2.11", @@ -4667,6 +4679,8 @@ dependencies = [ "pbkdf2", "rand 0.7.3", "rand_chacha 0.2.2", + "rustc_version", + "rustversion", "serde", "serde_bytes", "serde_derive", @@ -4704,6 +4718,7 @@ dependencies = [ "bs58 0.3.1", "proc-macro2 1.0.18", "quote 1.0.7", + "rustversion", "syn 1.0.33", ] diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 56151ae013..aa6c724aa2 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -1235,6 +1235,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.5" @@ -1670,6 +1680,8 @@ dependencies = [ "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "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.114 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1688,6 +1700,7 @@ dependencies = [ "bs58 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (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.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2445,6 +2458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +"checksum rustversion 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "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 bf3d65e7f2..31d5c937a6 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -23,6 +23,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 905abf0a41..3f445b7f5c 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -297,6 +297,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 d9f35a7b48..fb77f118a4 100644 --- a/programs/librapay/Cargo.lock +++ b/programs/librapay/Cargo.lock @@ -2095,6 +2095,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" @@ -2489,6 +2499,8 @@ dependencies = [ "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "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.114 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2507,6 +2519,7 @@ dependencies = [ "bs58 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (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.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3909,6 +3922,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.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" diff --git a/programs/move_loader/Cargo.lock b/programs/move_loader/Cargo.lock index 2b28fb6b2d..e795a2983e 100644 --- a/programs/move_loader/Cargo.lock +++ b/programs/move_loader/Cargo.lock @@ -2257,6 +2257,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" @@ -2586,6 +2597,8 @@ dependencies = [ "pbkdf2", "rand 0.7.3", "rand_chacha 0.2.2", + "rustc_version", + "rustversion", "serde", "serde_bytes", "serde_derive", @@ -2604,6 +2617,7 @@ dependencies = [ "bs58 0.3.1", "proc-macro2 1.0.18", "quote 1.0.7", + "rustversion", "syn 1.0.33", ] diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 2d91e808f5..7b8622145c 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -54,9 +54,13 @@ ed25519-dalek = { version = "=1.0.0-pre.3", optional = true } solana-crate-features = { path = "../crate-features", version = "1.2.11", optional = true } solana-logger = { path = "../logger", version = "1.2.11", optional = true } solana-sdk-macro = { path = "macro", version = "1.2.11" } +rustversion = "1.0.3" [dev-dependencies] tiny-bip39 = "0.7.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +rustc_version = "0.2" diff --git a/sdk/build.rs b/sdk/build.rs new file mode 100644 index 0000000000..c9550c1c5c --- /dev/null +++ b/sdk/build.rs @@ -0,0 +1,27 @@ +extern crate rustc_version; +use rustc_version::{version_meta, Channel}; + +fn main() { + // Copied and adapted from + // https://github.com/Kimundi/rustc-version-rs/blob/1d692a965f4e48a8cb72e82cda953107c0d22f47/README.md#example + // Licensed under Apache-2.0 + MIT + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=RUSTC_WITHOUT_SPECIALIZATION"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=RUSTC_WITHOUT_SPECIALIZATION"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=RUSTC_WITH_SPECIALIZATION"); + } + 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 036c653e3a..15d6419dc2 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 e58d9b4319..5146f3ed30 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 278a5214f8..4e0c63e722 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 292ec51092..6b4cbda66d 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -1,3 +1,5 @@ +#![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; @@ -60,6 +62,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;