1- use rustc_ast:: token:: { self , Delimiter , IdentIsRaw } ;
1+ use rustc_ast:: token:: { self , Delimiter , IdentIsRaw , Lit , Token , TokenKind } ;
22use rustc_ast:: tokenstream:: { RefTokenTreeCursor , TokenStream , TokenTree } ;
33use rustc_ast:: { LitIntType , LitKind } ;
44use rustc_ast_pretty:: pprust;
55use rustc_errors:: { Applicability , PResult } ;
66use rustc_macros:: { Decodable , Encodable } ;
77use rustc_session:: parse:: ParseSess ;
88use rustc_span:: symbol:: Ident ;
9- use rustc_span:: Span ;
9+ use rustc_span:: { Span , Symbol } ;
1010
1111pub ( crate ) const RAW_IDENT_ERR : & str = "`${concat(..)}` currently does not support raw identifiers" ;
12+ pub ( crate ) const UNSUPPORTED_CONCAT_ELEM_ERR : & str = "expected identifier or string literal" ;
1213
1314/// A meta-variable expression, for expansions based on properties of meta-variables.
1415#[ derive( Debug , PartialEq , Encodable , Decodable ) ]
@@ -51,11 +52,26 @@ impl MetaVarExpr {
5152 let mut result = Vec :: new ( ) ;
5253 loop {
5354 let is_var = try_eat_dollar ( & mut iter) ;
54- let element_ident = parse_ident ( & mut iter, psess, outer_span) ?;
55+ let token = parse_token ( & mut iter, psess, outer_span) ?;
5556 let element = if is_var {
56- MetaVarExprConcatElem :: Var ( element_ident)
57+ MetaVarExprConcatElem :: Var ( parse_ident_from_token ( psess, token) ?)
58+ } else if let TokenKind :: Literal ( Lit {
59+ kind : token:: LitKind :: Str ,
60+ symbol,
61+ suffix : None ,
62+ } ) = token. kind
63+ {
64+ MetaVarExprConcatElem :: Literal ( symbol)
5765 } else {
58- MetaVarExprConcatElem :: Ident ( element_ident)
66+ match parse_ident_from_token ( psess, token) {
67+ Err ( err) => {
68+ err. cancel ( ) ;
69+ return Err ( psess
70+ . dcx ( )
71+ . struct_span_err ( token. span , UNSUPPORTED_CONCAT_ELEM_ERR ) ) ;
72+ }
73+ Ok ( elem) => MetaVarExprConcatElem :: Ident ( elem) ,
74+ }
5975 } ;
6076 result. push ( element) ;
6177 if iter. look_ahead ( 0 ) . is_none ( ) {
@@ -105,11 +121,13 @@ impl MetaVarExpr {
105121
106122#[ derive( Debug , Decodable , Encodable , PartialEq ) ]
107123pub ( crate ) enum MetaVarExprConcatElem {
108- /// There is NO preceding dollar sign, which means that this identifier should be interpreted
109- /// as a literal.
124+ /// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be
125+ /// interpreted as a literal.
110126 Ident ( Ident ) ,
111- /// There is a preceding dollar sign, which means that this identifier should be expanded
112- /// and interpreted as a variable.
127+ /// For example, a number or a string.
128+ Literal ( Symbol ) ,
129+ /// Identifier WITH a preceding dollar sign, which means that this identifier should be
130+ /// expanded and interpreted as a variable.
113131 Var ( Ident ) ,
114132}
115133
@@ -158,7 +176,7 @@ fn parse_depth<'psess>(
158176 span : Span ,
159177) -> PResult < ' psess , usize > {
160178 let Some ( tt) = iter. next ( ) else { return Ok ( 0 ) } ;
161- let TokenTree :: Token ( token :: Token { kind : token :: TokenKind :: Literal ( lit) , .. } , _) = tt else {
179+ let TokenTree :: Token ( Token { kind : TokenKind :: Literal ( lit) , .. } , _) = tt else {
162180 return Err ( psess
163181 . dcx ( )
164182 . struct_span_err ( span, "meta-variable expression depth must be a literal" ) ) ;
@@ -180,12 +198,14 @@ fn parse_ident<'psess>(
180198 psess : & ' psess ParseSess ,
181199 fallback_span : Span ,
182200) -> PResult < ' psess , Ident > {
183- let Some ( tt) = iter. next ( ) else {
184- return Err ( psess. dcx ( ) . struct_span_err ( fallback_span, "expected identifier" ) ) ;
185- } ;
186- let TokenTree :: Token ( token, _) = tt else {
187- return Err ( psess. dcx ( ) . struct_span_err ( tt. span ( ) , "expected identifier" ) ) ;
188- } ;
201+ let token = parse_token ( iter, psess, fallback_span) ?;
202+ parse_ident_from_token ( psess, token)
203+ }
204+
205+ fn parse_ident_from_token < ' psess > (
206+ psess : & ' psess ParseSess ,
207+ token : & Token ,
208+ ) -> PResult < ' psess , Ident > {
189209 if let Some ( ( elem, is_raw) ) = token. ident ( ) {
190210 if let IdentIsRaw :: Yes = is_raw {
191211 return Err ( psess. dcx ( ) . struct_span_err ( elem. span , RAW_IDENT_ERR ) ) ;
@@ -205,10 +225,24 @@ fn parse_ident<'psess>(
205225 Err ( err)
206226}
207227
228+ fn parse_token < ' psess , ' t > (
229+ iter : & mut RefTokenTreeCursor < ' t > ,
230+ psess : & ' psess ParseSess ,
231+ fallback_span : Span ,
232+ ) -> PResult < ' psess , & ' t Token > {
233+ let Some ( tt) = iter. next ( ) else {
234+ return Err ( psess. dcx ( ) . struct_span_err ( fallback_span, UNSUPPORTED_CONCAT_ELEM_ERR ) ) ;
235+ } ;
236+ let TokenTree :: Token ( token, _) = tt else {
237+ return Err ( psess. dcx ( ) . struct_span_err ( tt. span ( ) , UNSUPPORTED_CONCAT_ELEM_ERR ) ) ;
238+ } ;
239+ Ok ( token)
240+ }
241+
208242/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
209243/// iterator is not modified and the result is `false`.
210244fn try_eat_comma ( iter : & mut RefTokenTreeCursor < ' _ > ) -> bool {
211- if let Some ( TokenTree :: Token ( token :: Token { kind : token:: Comma , .. } , _) ) = iter. look_ahead ( 0 ) {
245+ if let Some ( TokenTree :: Token ( Token { kind : token:: Comma , .. } , _) ) = iter. look_ahead ( 0 ) {
212246 let _ = iter. next ( ) ;
213247 return true ;
214248 }
@@ -218,8 +252,7 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
218252/// Tries to move the iterator forward returning `true` if there is a dollar sign. If not, then the
219253/// iterator is not modified and the result is `false`.
220254fn try_eat_dollar ( iter : & mut RefTokenTreeCursor < ' _ > ) -> bool {
221- if let Some ( TokenTree :: Token ( token:: Token { kind : token:: Dollar , .. } , _) ) = iter. look_ahead ( 0 )
222- {
255+ if let Some ( TokenTree :: Token ( Token { kind : token:: Dollar , .. } , _) ) = iter. look_ahead ( 0 ) {
223256 let _ = iter. next ( ) ;
224257 return true ;
225258 }
@@ -232,8 +265,7 @@ fn eat_dollar<'psess>(
232265 psess : & ' psess ParseSess ,
233266 span : Span ,
234267) -> PResult < ' psess , ( ) > {
235- if let Some ( TokenTree :: Token ( token:: Token { kind : token:: Dollar , .. } , _) ) = iter. look_ahead ( 0 )
236- {
268+ if let Some ( TokenTree :: Token ( Token { kind : token:: Dollar , .. } , _) ) = iter. look_ahead ( 0 ) {
237269 let _ = iter. next ( ) ;
238270 return Ok ( ( ) ) ;
239271 }
0 commit comments