Skip to content

Commit 72500ff

Browse files
committed
Auto merge of rust-lang#87264 - mystor:expand_literal, r=petrochenkov
proc_macro: Add an expand_expr method to TokenStream This feature is aimed at giving proc macros access to powers similar to those used by builtin macros such as `format_args!` or `concat!`. These macros are able to accept macros in place of string literal parameters, such as the format string, as they perform recursive macro expansion while being expanded. This can be especially useful in many cases thanks to helper macros like `concat!`, `stringify!` and `include_str!` which are often used to construct string literals at compile-time in user code. For now, this method only allows expanding macros which produce literals, although more expressions will be supported before the method is stabilized. In earlier versions of this PR, this method exclusively returned `Literal`, and spans on returned literals were stripped of expansion context before being returned to be as conservative as possible about permission leakage. The method's naming has been generalized to eventually support arbitrary expressions, and the context stripping has been removed (rust-lang#87264 (comment)), which should allow for more general APIs like "format_args_implicits" (rust-lang#67984) to be supported as well. ## API Surface ```rust impl TokenStream { pub fn expand_expr(&self) -> Result<TokenStream, ExpandError>; } #[non_exhaustive] pub struct ExpandError; impl Debug for ExpandError { ... } impl Display for ExpandError { ... } impl Error for ExpandError {} impl !Send for ExpandError {} impl !Sync for ExpandError {} ```
2 parents 6a48cd5 + 37da417 commit 72500ff

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

proc_macro/src/bridge/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ macro_rules! with_api {
6262
fn clone($self: &$S::TokenStream) -> $S::TokenStream;
6363
fn new() -> $S::TokenStream;
6464
fn is_empty($self: &$S::TokenStream) -> bool;
65+
fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
6566
fn from_str(src: &str) -> $S::TokenStream;
6667
fn to_string($self: &$S::TokenStream) -> String;
6768
fn from_token_tree(

proc_macro/src/lib.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,6 @@ impl !Sync for TokenStream {}
8888
#[derive(Debug)]
8989
pub struct LexError;
9090

91-
impl LexError {
92-
fn new() -> Self {
93-
LexError
94-
}
95-
}
96-
9791
#[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")]
9892
impl fmt::Display for LexError {
9993
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -109,6 +103,28 @@ impl !Send for LexError {}
109103
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
110104
impl !Sync for LexError {}
111105

106+
/// Error returned from `TokenStream::expand_expr`.
107+
#[unstable(feature = "proc_macro_expand", issue = "90765")]
108+
#[non_exhaustive]
109+
#[derive(Debug)]
110+
pub struct ExpandError;
111+
112+
#[unstable(feature = "proc_macro_expand", issue = "90765")]
113+
impl fmt::Display for ExpandError {
114+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115+
f.write_str("macro expansion failed")
116+
}
117+
}
118+
119+
#[unstable(feature = "proc_macro_expand", issue = "90765")]
120+
impl error::Error for ExpandError {}
121+
122+
#[unstable(feature = "proc_macro_expand", issue = "90765")]
123+
impl !Send for ExpandError {}
124+
125+
#[unstable(feature = "proc_macro_expand", issue = "90765")]
126+
impl !Sync for ExpandError {}
127+
112128
impl TokenStream {
113129
/// Returns an empty `TokenStream` containing no token trees.
114130
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
@@ -121,6 +137,24 @@ impl TokenStream {
121137
pub fn is_empty(&self) -> bool {
122138
self.0.is_empty()
123139
}
140+
141+
/// Parses this `TokenStream` as an expression and attempts to expand any
142+
/// macros within it. Returns the expanded `TokenStream`.
143+
///
144+
/// Currently only expressions expanding to literals will succeed, although
145+
/// this may be relaxed in the future.
146+
///
147+
/// NOTE: In error conditions, `expand_expr` may leave macros unexpanded,
148+
/// report an error, failing compilation, and/or return an `Err(..)`. The
149+
/// specific behavior for any error condition, and what conditions are
150+
/// considered errors, is unspecified and may change in the future.
151+
#[unstable(feature = "proc_macro_expand", issue = "90765")]
152+
pub fn expand_expr(&self) -> Result<TokenStream, ExpandError> {
153+
match bridge::client::TokenStream::expand_expr(&self.0) {
154+
Ok(stream) => Ok(TokenStream(stream)),
155+
Err(_) => Err(ExpandError),
156+
}
157+
}
124158
}
125159

126160
/// Attempts to break the string into tokens and parse those tokens into a token stream.
@@ -1211,7 +1245,7 @@ impl FromStr for Literal {
12111245
fn from_str(src: &str) -> Result<Self, LexError> {
12121246
match bridge::client::Literal::from_str(src) {
12131247
Ok(literal) => Ok(Literal(literal)),
1214-
Err(()) => Err(LexError::new()),
1248+
Err(()) => Err(LexError),
12151249
}
12161250
}
12171251
}

0 commit comments

Comments
 (0)