diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-04-22 23:19:24 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-22 23:19:24 +0200 |
| commit | 0f806534c01ea906a2e178b31ea2733a92e4bc0a (patch) | |
| tree | 4e9e25f2d3c3a1d755c7852e9393dc24e4871d82 | |
| parent | 16be619c6aec0db952be61ebb45c63a1ebe4b1a5 (diff) | |
| parent | 3bd742ff4e61f6752d76a75f53c140170a117554 (diff) | |
| download | rust-0f806534c01ea906a2e178b31ea2733a92e4bc0a.tar.gz rust-0f806534c01ea906a2e178b31ea2733a92e4bc0a.zip | |
Rollup merge of #71400 - dtolnay:isavailable, r=petrochenkov
proc_macro::is_available() This PR adds `proc_macro::is_available() -> bool` to determine whether proc_macro has been made accessible to the currently running program. The proc_macro crate is only intended for use inside the implementation of procedural macros. All the functions in the crate panic if invoked from outside of a procedural macro, such as from a build script or unit test or ordinary Rust binary. Unfortunately those panics made it impossible for libraries that are designed to support both macro and non-macro use cases (e.g. Syn) to be used from binaries that are compiled with panic=abort. In panic=unwind mode we're able to attempt a proc macro call inside catch_unwind and use libproc_macro's result if it succeeds, otherwise fall back to a non-macro alternative implementation. But in panic=abort there was no way to determine which implementation needs to be used. r? @eddyb attn: @petrochenkov @adetaylor ref: https://github.com/dtolnay/cxx/issues/130
| -rw-r--r-- | src/libproc_macro/bridge/client.rs | 7 | ||||
| -rw-r--r-- | src/libproc_macro/lib.rs | 18 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/auxiliary/is-available.rs | 14 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/is-available.rs | 17 |
4 files changed, 56 insertions, 0 deletions
diff --git a/src/libproc_macro/bridge/client.rs b/src/libproc_macro/bridge/client.rs index 088db92253a..d2222d12623 100644 --- a/src/libproc_macro/bridge/client.rs +++ b/src/libproc_macro/bridge/client.rs @@ -290,6 +290,13 @@ impl BridgeState<'_> { } impl Bridge<'_> { + pub(crate) fn is_available() -> bool { + BridgeState::with(|state| match state { + BridgeState::Connected(_) | BridgeState::InUse => true, + BridgeState::NotConnected => false, + }) + } + fn enter<R>(self, f: impl FnOnce() -> R) -> R { // Hide the default panic output within `proc_macro` expansions. // NB. the server can't do this because it may use a different libstd. diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index a975ce93bb1..3cbe852de7b 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -45,6 +45,24 @@ use std::path::PathBuf; use std::str::FromStr; use std::{error, fmt, iter, mem}; +/// Determines whether proc_macro has been made accessible to the currently +/// running program. +/// +/// The proc_macro crate is only intended for use inside the implementation of +/// procedural macros. All the functions in this crate panic if invoked from +/// outside of a procedural macro, such as from a build script or unit test or +/// ordinary Rust binary. +/// +/// With consideration for Rust libraries that are designed to support both +/// macro and non-macro use cases, `proc_macro::is_available()` provides a +/// non-panicking way to detect whether the infrastructure required to use the +/// API of proc_macro is presently available. Returns true if invoked from +/// inside of a procedural macro, false if invoked from any other binary. +#[unstable(feature = "proc_macro_is_available", issue = "71436")] +pub fn is_available() -> bool { + bridge::Bridge::is_available() +} + /// The main type provided by this crate, representing an abstract stream of /// tokens, or, more specifically, a sequence of token trees. /// The type provide interfaces for iterating over those token trees and, conversely, diff --git a/src/test/ui/proc-macro/auxiliary/is-available.rs b/src/test/ui/proc-macro/auxiliary/is-available.rs new file mode 100644 index 00000000000..0caf186db1d --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/is-available.rs @@ -0,0 +1,14 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_is_available)] + +extern crate proc_macro; + +use proc_macro::{Literal, TokenStream, TokenTree}; + +#[proc_macro] +pub fn from_inside_proc_macro(_input: TokenStream) -> TokenStream { + proc_macro::is_available().to_string().parse().unwrap() +} diff --git a/src/test/ui/proc-macro/is-available.rs b/src/test/ui/proc-macro/is-available.rs new file mode 100644 index 00000000000..943d9fe797a --- /dev/null +++ b/src/test/ui/proc-macro/is-available.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(proc_macro_hygiene, proc_macro_is_available)] + +extern crate proc_macro; + +// aux-build:is-available.rs +extern crate is_available; + +fn main() { + let a = proc_macro::is_available(); + let b = is_available::from_inside_proc_macro!(); + let c = proc_macro::is_available(); + assert!(!a); + assert!(b); + assert!(!c); +} |
