@@ -430,7 +430,8 @@ impl<'a> Parser<'a> {
430430 }
431431
432432 fn parse_use_item ( & mut self ) -> PResult < ' a , ItemKind > {
433- let tree = self . parse_use_tree ( ) ?;
433+ let use_token_span = self . prev_token . span ;
434+ let tree = self . parse_use_tree ( use_token_span, None ) ?;
434435 if let Err ( mut e) = self . expect_semi ( ) {
435436 match tree. kind {
436437 UseTreeKind :: Glob ( _) => {
@@ -1291,7 +1292,11 @@ impl<'a> Parser<'a> {
12911292 /// PATH `::` `{` USE_TREE_LIST `}` |
12921293 /// PATH [`as` IDENT]
12931294 /// ```
1294- fn parse_use_tree ( & mut self ) -> PResult < ' a , UseTree > {
1295+ fn parse_use_tree < ' b > (
1296+ & mut self ,
1297+ use_token_span : Span ,
1298+ use_path : Option < & ' b UsePathList < ' b > > ,
1299+ ) -> PResult < ' a , UseTree > {
12951300 let lo = self . token . span ;
12961301
12971302 let mut prefix =
@@ -1306,13 +1311,14 @@ impl<'a> Parser<'a> {
13061311 . push ( PathSegment :: path_root ( lo. shrink_to_lo ( ) . with_ctxt ( mod_sep_ctxt) ) ) ;
13071312 }
13081313
1309- self . parse_use_tree_glob_or_nested ( ) ?
1314+ self . parse_use_tree_glob_or_nested ( use_token_span , use_path ) ?
13101315 } else {
13111316 // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`
13121317 prefix = self . parse_path ( PathStyle :: Mod ) ?;
13131318
13141319 if self . eat_path_sep ( ) {
1315- self . parse_use_tree_glob_or_nested ( ) ?
1320+ let use_path = UsePathList { element : & prefix. segments , prev : use_path } ;
1321+ self . parse_use_tree_glob_or_nested ( use_token_span, Some ( & use_path) ) ?
13161322 } else {
13171323 // Recover from using a colon as path separator.
13181324 while self . eat_noexpect ( & token:: Colon ) {
@@ -1332,13 +1338,17 @@ impl<'a> Parser<'a> {
13321338 }
13331339
13341340 /// Parses `*` or `{...}`.
1335- fn parse_use_tree_glob_or_nested ( & mut self ) -> PResult < ' a , UseTreeKind > {
1341+ fn parse_use_tree_glob_or_nested < ' b > (
1342+ & mut self ,
1343+ use_token_span : Span ,
1344+ use_path : Option < & ' b UsePathList < ' b > > ,
1345+ ) -> PResult < ' a , UseTreeKind > {
13361346 Ok ( if self . eat ( exp ! ( Star ) ) {
13371347 UseTreeKind :: Glob ( self . prev_token . span )
13381348 } else {
13391349 let lo = self . token . span ;
13401350 UseTreeKind :: Nested {
1341- items : self . parse_use_tree_list ( ) ?,
1351+ items : self . parse_use_tree_list ( use_token_span , use_path ) ?,
13421352 span : lo. to ( self . prev_token . span ) ,
13431353 }
13441354 } )
@@ -1349,14 +1359,119 @@ impl<'a> Parser<'a> {
13491359 /// ```text
13501360 /// USE_TREE_LIST = ∅ | (USE_TREE `,`)* USE_TREE [`,`]
13511361 /// ```
1352- fn parse_use_tree_list ( & mut self ) -> PResult < ' a , ThinVec < ( UseTree , ast:: NodeId ) > > {
1362+ fn parse_use_tree_list < ' b > (
1363+ & mut self ,
1364+ use_token_span : Span ,
1365+ prefix : Option < & ' b UsePathList < ' b > > ,
1366+ ) -> PResult < ' a , ThinVec < ( UseTree , ast:: NodeId ) > > {
13531367 self . parse_delim_comma_seq ( exp ! ( OpenBrace ) , exp ! ( CloseBrace ) , |p| {
13541368 p. recover_vcs_conflict_marker ( ) ;
1355- Ok ( ( p. parse_use_tree ( ) ?, DUMMY_NODE_ID ) )
1369+ let recovered = p. recover_attr_in_use_tree ( ) ;
1370+ let use_tree = p. parse_use_tree ( use_token_span, prefix) ?;
1371+ if let Some ( attr_span) = recovered {
1372+ p. emit_error_attr_in_use_tree ( use_token_span, prefix, use_tree. span ( ) , attr_span) ;
1373+ }
1374+
1375+ Ok ( ( use_tree, DUMMY_NODE_ID ) )
13561376 } )
13571377 . map ( |( r, _) | r)
13581378 }
13591379
1380+ /// Consumes the tokens that constitute the attribute and returns them.
1381+ ///
1382+ /// /!\ Always emit an error if this function returns `Some(_)`.
1383+ fn recover_attr_in_use_tree ( & mut self ) -> Option < Span > {
1384+ if self . check_noexpect ( & TokenKind :: Pound )
1385+ && ( self . look_ahead ( 1 , |tok| matches ! ( tok. kind, TokenKind :: OpenBracket ) ) // `#[`
1386+ || ( self . look_ahead ( 1 , |tok| matches ! ( tok. kind, TokenKind :: Bang ) )
1387+ && self . look_ahead ( 2 , |tok| matches ! ( tok. kind, TokenKind :: OpenBracket ) ) ) )
1388+ {
1389+ let start_pos = self . token . span ;
1390+ // `#`
1391+ self . bump ( ) ;
1392+
1393+ if self . token . kind == TokenKind :: Bang {
1394+ // `!`
1395+ self . bump ( ) ;
1396+ }
1397+
1398+ // We checked that there is a `[` right ahead. This should always return `Some(_)`.
1399+ let delim = self . parse_delim_args_inner ( ) . unwrap ( ) ;
1400+
1401+ let end_pos = delim. dspan . close ;
1402+ let attr_span = start_pos. to ( end_pos) ;
1403+
1404+ Some ( attr_span)
1405+ } else {
1406+ None
1407+ }
1408+ }
1409+
1410+ fn emit_error_attr_in_use_tree < ' b > (
1411+ & self ,
1412+ use_token_span : Span ,
1413+ prefix : Option < & ' b UsePathList < ' b > > ,
1414+ use_tree_span : Span ,
1415+ attr_span : Span ,
1416+ ) {
1417+ {
1418+ let mut prefix = prefix;
1419+ let attr = self
1420+ . psess
1421+ . source_map ( )
1422+ . span_to_source ( attr_span, |s, start, end| Ok ( s[ start..end] . to_string ( ) ) )
1423+ . unwrap ( ) ;
1424+
1425+ let prefix = {
1426+ let mut tmp = Vec :: new ( ) ;
1427+ while let Some ( prefix_) = prefix {
1428+ tmp. push ( prefix_. element ) ;
1429+ prefix = prefix_. prev ;
1430+ }
1431+ tmp. reverse ( ) ;
1432+ tmp
1433+ } ;
1434+
1435+ let prefix = prefix
1436+ . iter ( )
1437+ . flat_map ( |segments| segments. iter ( ) . map ( |segment| segment. ident . name . as_str ( ) ) )
1438+ . collect :: < Vec < _ > > ( )
1439+ . join ( "::" ) ;
1440+
1441+ let mut comma_reached = false ;
1442+ let tree_span = self
1443+ . psess
1444+ . source_map ( )
1445+ . span_extend_while ( use_tree_span, |c| {
1446+ if comma_reached {
1447+ return false ;
1448+ }
1449+ comma_reached = c == ',' ;
1450+ c. is_whitespace ( ) || comma_reached
1451+ } )
1452+ . unwrap ( ) ;
1453+
1454+ let use_tree = self
1455+ . psess
1456+ . source_map ( )
1457+ . span_to_source ( use_tree_span, |s, start, end| Ok ( s[ start..end] . to_string ( ) ) )
1458+ . unwrap ( ) ;
1459+
1460+ let code = format ! ( "{attr}\n use {prefix}::{use_tree};\n " ) ;
1461+
1462+ let err = crate :: errors:: AttrInUseTree {
1463+ attr_span,
1464+ sub : Some ( crate :: errors:: AttrInUseTreeSugg {
1465+ use_lo : use_token_span. shrink_to_lo ( ) ,
1466+ attr_span,
1467+ tree_span,
1468+ code,
1469+ } ) ,
1470+ } ;
1471+ self . dcx ( ) . emit_err ( err) ;
1472+ }
1473+ }
1474+
13601475 fn parse_rename ( & mut self ) -> PResult < ' a , Option < Ident > > {
13611476 if self . eat_keyword ( exp ! ( As ) ) {
13621477 self . parse_ident_or_underscore ( ) . map ( Some )
@@ -3657,3 +3772,8 @@ pub(super) enum FrontMatterParsingMode {
36573772 /// For function pointer types, the `const` and `async` keywords are not permitted.
36583773 FunctionPtrType ,
36593774}
3775+
3776+ struct UsePathList < ' a > {
3777+ element : & ' a [ ast:: PathSegment ] ,
3778+ prev : Option < & ' a Self > ,
3779+ }
0 commit comments