Skip to content

Commit 0fcad9c

Browse files
committed
Add backwards-compat hack for certain '$name' tokens
See issue #74616
1 parent cd24aee commit 0fcad9c

File tree

8 files changed

+103
-8
lines changed

8 files changed

+103
-8
lines changed

src/librustc_ast/token.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ use crate::tokenstream::TokenTree;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1212
use rustc_data_structures::sync::Lrc;
1313
use rustc_macros::HashStable_Generic;
14+
use rustc_span::hygiene::ExpnKind;
15+
use rustc_span::source_map::SourceMap;
1416
use rustc_span::symbol::{kw, sym};
1517
use rustc_span::symbol::{Ident, Symbol};
16-
use rustc_span::{self, Span, DUMMY_SP};
18+
use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP};
1719
use std::borrow::Cow;
1820
use std::{fmt, mem};
1921

@@ -808,6 +810,31 @@ impl Nonterminal {
808810
}
809811
false
810812
}
813+
814+
// See issue #74616 for details
815+
pub fn ident_name_compatibility_hack(
816+
&self,
817+
orig_span: Span,
818+
source_map: &SourceMap,
819+
) -> Option<(Ident, bool)> {
820+
if let NtIdent(ident, is_raw) = self {
821+
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
822+
let filename = source_map.span_to_filename(orig_span);
823+
if let FileName::Real(RealFileName::Named(path)) = filename {
824+
if (path.ends_with("time-macros-impl/src/lib.rs")
825+
&& macro_name == sym::impl_macros)
826+
|| (path.ends_with("js-sys/src/lib.rs") && macro_name == sym::arrays)
827+
{
828+
let snippet = source_map.span_to_snippet(orig_span);
829+
if snippet.as_deref() == Ok("$name") {
830+
return Some((*ident, *is_raw));
831+
}
832+
}
833+
}
834+
}
835+
}
836+
None
837+
}
811838
}
812839

813840
impl PartialEq for Nonterminal {

src/librustc_expand/proc_macro_server.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,19 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
173173
}
174174

175175
Interpolated(nt) => {
176-
let stream = nt_to_tokenstream(&nt, sess, span);
177-
TokenTree::Group(Group {
178-
delimiter: Delimiter::None,
179-
stream,
180-
span: DelimSpan::from_single(span),
181-
flatten: nt.pretty_printing_compatibility_hack(),
182-
})
176+
if let Some((name, is_raw)) =
177+
nt.ident_name_compatibility_hack(span, sess.source_map())
178+
{
179+
TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
180+
} else {
181+
let stream = nt_to_tokenstream(&nt, sess, span);
182+
TokenTree::Group(Group {
183+
delimiter: Delimiter::None,
184+
stream,
185+
span: DelimSpan::from_single(span),
186+
flatten: nt.pretty_printing_compatibility_hack(),
187+
})
188+
}
183189
}
184190

185191
OpenDelim(..) | CloseDelim(..) => unreachable!(),

src/librustc_span/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ symbols! {
258258
arith_offset,
259259
arm_target_feature,
260260
array,
261+
arrays,
261262
as_str,
262263
asm,
263264
assert,
@@ -571,6 +572,7 @@ symbols! {
571572
ignore,
572573
impl_header_lifetime_elision,
573574
impl_lint_pass,
575+
impl_macros,
574576
impl_trait_in_bindings,
575577
import_shadowing,
576578
in_band_lifetimes,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
4+
#![crate_type = "proc-macro"]
5+
6+
extern crate proc_macro;
7+
use proc_macro::TokenStream;
8+
9+
#[proc_macro_attribute]
10+
pub fn my_macro(_attr: TokenStream, input: TokenStream) -> TokenStream {
11+
println!("Called proc_macro_hack with {:?}", input);
12+
input
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// check-pass
2+
// aux-build:group-compat-hack.rs
3+
// compile-flags: -Z span-debug
4+
5+
#![no_std] // Don't load unnecessary hygiene information from std
6+
extern crate std;
7+
8+
#[macro_use] extern crate group_compat_hack;
9+
10+
// Tests the backwards compatibility hack added for certain macros
11+
// When an attribute macro named `proc_macro_hack` or `wasm_bindgen`
12+
// has an `NtIdent` named `$name`, we pass a plain `Ident` token in
13+
// place of a `None`-delimited group. This allows us to maintain
14+
// backwards compatibility for older versions of these crates.
15+
16+
include!("js-sys/src/lib.rs");
17+
include!("time-macros-impl/src/lib.rs");
18+
19+
macro_rules! other {
20+
($name:ident) => {
21+
#[my_macro] struct Three($name);
22+
}
23+
}
24+
25+
fn main() {
26+
struct Foo;
27+
impl_macros!(Foo);
28+
arrays!(Foo);
29+
other!(Foo);
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#5) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#5) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#5) }]
2+
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#9) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#9) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#9) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#9) }]
3+
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:21: 21:27 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:28: 21:33 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:34: 21:39 (#13) }], span: $DIR/group-compat-hack.rs:21:33: 21:40 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:40: 21:41 (#13) }]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// ignore-test this is not a test
2+
3+
macro_rules! arrays {
4+
($name:ident) => {
5+
#[my_macro] struct Two($name);
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// ignore-test this is not a test
2+
3+
macro_rules! impl_macros {
4+
($name:ident) => {
5+
#[my_macro] struct One($name);
6+
}
7+
}

0 commit comments

Comments
 (0)