@@ -16,6 +16,10 @@ use rustc_span::Span;
16
16
const VALID_FRAGMENT_NAMES_MSG : & str = "valid fragment specifiers are \
17
17
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
18
18
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
19
+ const VALID_FRAGMENT_NAMES_MSG_2021 : & str = "valid fragment specifiers are \
20
+ `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \
21
+ `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
22
+ `item` and `vis`";
19
23
20
24
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
21
25
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
@@ -63,35 +67,60 @@ pub(super) fn parse(
63
67
Some ( tokenstream:: TokenTree :: Token ( token, _) ) => match token. ident ( ) {
64
68
Some ( ( fragment, _) ) => {
65
69
let span = token. span . with_lo ( start_sp. lo ( ) ) ;
66
-
70
+ let edition = || {
71
+ // FIXME(#85708) - once we properly decode a foreign
72
+ // crate's `SyntaxContext::root`, then we can replace
73
+ // this with just `span.edition()`. A
74
+ // `SyntaxContext::root()` from the current crate will
75
+ // have the edition of the current crate, and a
76
+ // `SyntaxContext::root()` from a foreign crate will
77
+ // have the edition of that crate (which we manually
78
+ // retrieve via the `edition` parameter).
79
+ if !span. from_expansion ( ) {
80
+ edition
81
+ } else {
82
+ span. edition ( )
83
+ }
84
+ } ;
67
85
let kind =
68
- token:: NonterminalKind :: from_symbol ( fragment. name , || {
69
- // FIXME(#85708) - once we properly decode a foreign
70
- // crate's `SyntaxContext::root`, then we can replace
71
- // this with just `span.edition()`. A
72
- // `SyntaxContext::root()` from the current crate will
73
- // have the edition of the current crate, and a
74
- // `SyntaxContext::root()` from a foreign crate will
75
- // have the edition of that crate (which we manually
76
- // retrieve via the `edition` parameter).
77
- if !span. from_expansion ( ) {
78
- edition
79
- } else {
80
- span. edition ( )
81
- }
82
- } )
83
- . unwrap_or_else (
84
- || {
86
+ token:: NonterminalKind :: from_symbol ( fragment. name , edition)
87
+ . unwrap_or_else ( || {
88
+ let help = match fragment. name {
89
+ sym:: expr_2021 => {
90
+ format ! (
91
+ "fragment specifier `expr_2021` \
92
+ requires Rust 2021 or later\n \
93
+ {VALID_FRAGMENT_NAMES_MSG}"
94
+ )
95
+ }
96
+ _ if edition ( ) . at_least_rust_2021 ( )
97
+ && features
98
+ . expr_fragment_specifier_2024 =>
99
+ {
100
+ VALID_FRAGMENT_NAMES_MSG_2021 . into ( )
101
+ }
102
+ _ => VALID_FRAGMENT_NAMES_MSG . into ( ) ,
103
+ } ;
85
104
sess. dcx ( ) . emit_err (
86
105
errors:: InvalidFragmentSpecifier {
87
106
span,
88
107
fragment,
89
- help : VALID_FRAGMENT_NAMES_MSG . into ( ) ,
108
+ help,
90
109
} ,
91
110
) ;
92
111
token:: NonterminalKind :: Ident
93
- } ,
94
- ) ;
112
+ } ) ;
113
+ if kind == token:: NonterminalKind :: Expr2021
114
+ && !features. expr_fragment_specifier_2024
115
+ {
116
+ rustc_session:: parse:: feature_err (
117
+ sess,
118
+ sym:: expr_fragment_specifier_2024,
119
+ span,
120
+ "fragment specifier `expr_2021` is unstable" ,
121
+ )
122
+ . emit ( ) ;
123
+ }
95
124
result. push ( TokenTree :: MetaVarDecl ( span, ident, Some ( kind) ) ) ;
96
125
continue ;
97
126
}
0 commit comments