@@ -10,7 +10,7 @@ use either::Either;
1010use hir_expand:: {
1111 name:: { AsName , Name } ,
1212 span_map:: { ExpansionSpanMap , SpanMap } ,
13- InFile ,
13+ InFile , MacroDefId ,
1414} ;
1515use intern:: { sym, Interned , Symbol } ;
1616use rustc_hash:: FxHashMap ;
@@ -39,16 +39,16 @@ use crate::{
3939 FormatPlaceholder , FormatSign , FormatTrait ,
4040 } ,
4141 Array , Binding , BindingAnnotation , BindingId , BindingProblems , CaptureBy , ClosureKind ,
42- Expr , ExprId , Label , LabelId , Literal , LiteralOrConst , MatchArm , Movability , OffsetOf , Pat ,
43- PatId , RecordFieldPat , RecordLitField , Statement ,
42+ Expr , ExprId , Item , Label , LabelId , Literal , LiteralOrConst , MatchArm , Movability ,
43+ OffsetOf , Pat , PatId , RecordFieldPat , RecordLitField , Statement ,
4444 } ,
4545 item_scope:: BuiltinShadowMode ,
4646 lang_item:: LangItem ,
4747 lower:: LowerCtx ,
4848 nameres:: { DefMap , MacroSubNs } ,
4949 path:: { GenericArgs , Path } ,
5050 type_ref:: { Mutability , Rawness , TypeRef } ,
51- AdtId , BlockId , BlockLoc , ConstBlockLoc , DefWithBodyId , ModuleDefId , UnresolvedMacro ,
51+ AdtId , BlockId , BlockLoc , ConstBlockLoc , DefWithBodyId , MacroId , ModuleDefId , UnresolvedMacro ,
5252} ;
5353
5454type FxIndexSet < K > = indexmap:: IndexSet < K , std:: hash:: BuildHasherDefault < rustc_hash:: FxHasher > > ;
@@ -88,6 +88,7 @@ pub(super) fn lower(
8888 current_binding_owner : None ,
8989 awaitable_context : None ,
9090 current_span_map : span_map,
91+ current_block_legacy_macro_defs_count : FxHashMap :: default ( ) ,
9192 }
9293 . collect ( params, body, is_async_fn)
9394}
@@ -104,6 +105,10 @@ struct ExprCollector<'a> {
104105
105106 is_lowering_coroutine : bool ,
106107
108+ /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,
109+ /// and we need to find the current definition. So we track the number of definitions we saw.
110+ current_block_legacy_macro_defs_count : FxHashMap < Name , usize > ,
111+
107112 current_span_map : Option < Arc < ExpansionSpanMap > > ,
108113
109114 current_try_block_label : Option < LabelId > ,
@@ -124,31 +129,27 @@ struct ExprCollector<'a> {
124129#[ derive( Clone , Debug ) ]
125130struct LabelRib {
126131 kind : RibKind ,
127- // Once we handle macro hygiene this will need to be a map
128- label : Option < ( Name , LabelId , HygieneId ) > ,
129132}
130133
131134impl LabelRib {
132135 fn new ( kind : RibKind ) -> Self {
133- LabelRib { kind, label : None }
134- }
135- fn new_normal ( label : ( Name , LabelId , HygieneId ) ) -> Self {
136- LabelRib { kind : RibKind :: Normal , label : Some ( label) }
136+ LabelRib { kind }
137137 }
138138}
139139
140- #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
140+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
141141enum RibKind {
142- Normal ,
142+ Normal ( Name , LabelId , HygieneId ) ,
143143 Closure ,
144144 Constant ,
145+ MacroDef ( Box < MacroDefId > ) ,
145146}
146147
147148impl RibKind {
148149 /// This rib forbids referring to labels defined in upwards ribs.
149- fn is_label_barrier ( self ) -> bool {
150+ fn is_label_barrier ( & self ) -> bool {
150151 match self {
151- RibKind :: Normal => false ,
152+ RibKind :: Normal ( .. ) | RibKind :: MacroDef ( _ ) => false ,
152153 RibKind :: Closure | RibKind :: Constant => true ,
153154 }
154155 }
@@ -1350,10 +1351,46 @@ impl ExprCollector<'_> {
13501351 statements. push ( Statement :: Expr { expr, has_semi } ) ;
13511352 }
13521353 }
1353- ast:: Stmt :: Item ( _item) => statements. push ( Statement :: Item ) ,
1354+ ast:: Stmt :: Item ( ast:: Item :: MacroDef ( macro_) ) => {
1355+ let Some ( name) = macro_. name ( ) else {
1356+ statements. push ( Statement :: Item ( Item :: Other ) ) ;
1357+ return ;
1358+ } ;
1359+ let name = name. as_name ( ) ;
1360+ let macro_id = self . def_map . modules [ DefMap :: ROOT ] . scope . get ( & name) . take_macros ( ) ;
1361+ self . collect_macro_def ( statements, macro_id) ;
1362+ }
1363+ ast:: Stmt :: Item ( ast:: Item :: MacroRules ( macro_) ) => {
1364+ let Some ( name) = macro_. name ( ) else {
1365+ statements. push ( Statement :: Item ( Item :: Other ) ) ;
1366+ return ;
1367+ } ;
1368+ let name = name. as_name ( ) ;
1369+ let macro_defs_count =
1370+ self . current_block_legacy_macro_defs_count . entry ( name. clone ( ) ) . or_insert ( 0 ) ;
1371+ let macro_id = self . def_map . modules [ DefMap :: ROOT ]
1372+ . scope
1373+ . get_legacy_macro ( & name)
1374+ . and_then ( |it| it. get ( * macro_defs_count) )
1375+ . copied ( ) ;
1376+ * macro_defs_count += 1 ;
1377+ self . collect_macro_def ( statements, macro_id) ;
1378+ }
1379+ ast:: Stmt :: Item ( _item) => statements. push ( Statement :: Item ( Item :: Other ) ) ,
13541380 }
13551381 }
13561382
1383+ fn collect_macro_def ( & mut self , statements : & mut Vec < Statement > , macro_id : Option < MacroId > ) {
1384+ let Some ( macro_id) = macro_id else {
1385+ never ! ( "def map should have macro definition, but it doesn't" ) ;
1386+ statements. push ( Statement :: Item ( Item :: Other ) ) ;
1387+ return ;
1388+ } ;
1389+ let macro_id = self . db . macro_def ( macro_id) ;
1390+ statements. push ( Statement :: Item ( Item :: MacroDef ( Box :: new ( macro_id) ) ) ) ;
1391+ self . label_ribs . push ( LabelRib :: new ( RibKind :: MacroDef ( Box :: new ( macro_id) ) ) ) ;
1392+ }
1393+
13571394 fn collect_block ( & mut self , block : ast:: BlockExpr ) -> ExprId {
13581395 self . collect_block_ ( block, |id, statements, tail| Expr :: Block {
13591396 id,
@@ -1399,6 +1436,7 @@ impl ExprCollector<'_> {
13991436 } ;
14001437 let prev_def_map = mem:: replace ( & mut self . def_map , def_map) ;
14011438 let prev_local_module = mem:: replace ( & mut self . expander . module , module) ;
1439+ let prev_legacy_macros_count = mem:: take ( & mut self . current_block_legacy_macro_defs_count ) ;
14021440
14031441 let mut statements = Vec :: new ( ) ;
14041442 block. statements ( ) . for_each ( |s| self . collect_stmt ( & mut statements, s) ) ;
@@ -1421,6 +1459,7 @@ impl ExprCollector<'_> {
14211459
14221460 self . def_map = prev_def_map;
14231461 self . expander . module = prev_local_module;
1462+ self . current_block_legacy_macro_defs_count = prev_legacy_macros_count;
14241463 expr_id
14251464 }
14261465
@@ -1780,21 +1819,51 @@ impl ExprCollector<'_> {
17801819 lifetime : Option < ast:: Lifetime > ,
17811820 ) -> Result < Option < LabelId > , BodyDiagnostic > {
17821821 let Some ( lifetime) = lifetime else { return Ok ( None ) } ;
1783- let hygiene = self . hygiene_id_for ( lifetime. syntax ( ) . text_range ( ) . start ( ) ) ;
1822+ let ( mut hygiene_id, mut hygiene_info) = match & self . current_span_map {
1823+ None => ( HygieneId :: ROOT , None ) ,
1824+ Some ( span_map) => {
1825+ let span = span_map. span_at ( lifetime. syntax ( ) . text_range ( ) . start ( ) ) ;
1826+ let ctx = self . db . lookup_intern_syntax_context ( span. ctx ) ;
1827+ let hygiene_id = HygieneId :: new ( ctx. opaque_and_semitransparent ) ;
1828+ let hygiene_info = ctx. outer_expn . map ( |expansion| {
1829+ let expansion = self . db . lookup_intern_macro_call ( expansion) ;
1830+ ( ctx. parent , expansion. def )
1831+ } ) ;
1832+ ( hygiene_id, hygiene_info)
1833+ }
1834+ } ;
17841835 let name = Name :: new_lifetime ( & lifetime) ;
17851836
17861837 for ( rib_idx, rib) in self . label_ribs . iter ( ) . enumerate ( ) . rev ( ) {
1787- if let Some ( ( label_name, id, label_hygiene) ) = & rib. label {
1788- if * label_name == name && * label_hygiene == hygiene {
1789- return if self . is_label_valid_from_rib ( rib_idx) {
1790- Ok ( Some ( * id) )
1791- } else {
1792- Err ( BodyDiagnostic :: UnreachableLabel {
1793- name,
1794- node : self . expander . in_file ( AstPtr :: new ( & lifetime) ) ,
1795- } )
1796- } ;
1838+ match & rib. kind {
1839+ RibKind :: Normal ( label_name, id, label_hygiene) => {
1840+ if * label_name == name && * label_hygiene == hygiene_id {
1841+ return if self . is_label_valid_from_rib ( rib_idx) {
1842+ Ok ( Some ( * id) )
1843+ } else {
1844+ Err ( BodyDiagnostic :: UnreachableLabel {
1845+ name,
1846+ node : self . expander . in_file ( AstPtr :: new ( & lifetime) ) ,
1847+ } )
1848+ } ;
1849+ }
1850+ }
1851+ RibKind :: MacroDef ( macro_id) => {
1852+ if let Some ( ( parent_ctx, label_macro_id) ) = hygiene_info {
1853+ if label_macro_id == * * macro_id {
1854+ // A macro is allowed to refer to labels from before its declaration.
1855+ // Therefore, if we got to the rib of its declaration, give up its hygiene
1856+ // and use its parent expansion.
1857+ let parent_ctx = self . db . lookup_intern_syntax_context ( parent_ctx) ;
1858+ hygiene_id = HygieneId :: new ( parent_ctx. opaque_and_semitransparent ) ;
1859+ hygiene_info = parent_ctx. outer_expn . map ( |expansion| {
1860+ let expansion = self . db . lookup_intern_macro_call ( expansion) ;
1861+ ( parent_ctx. parent , expansion. def )
1862+ } ) ;
1863+ }
1864+ }
17971865 }
1866+ _ => { }
17981867 }
17991868 }
18001869
@@ -1808,10 +1877,17 @@ impl ExprCollector<'_> {
18081877 !self . label_ribs [ rib_index + 1 ..] . iter ( ) . any ( |rib| rib. kind . is_label_barrier ( ) )
18091878 }
18101879
1880+ fn pop_label_rib ( & mut self ) {
1881+ // We need to pop all macro defs, plus one rib.
1882+ while let Some ( LabelRib { kind : RibKind :: MacroDef ( _) } ) = self . label_ribs . pop ( ) {
1883+ // Do nothing.
1884+ }
1885+ }
1886+
18111887 fn with_label_rib < T > ( & mut self , kind : RibKind , f : impl FnOnce ( & mut Self ) -> T ) -> T {
18121888 self . label_ribs . push ( LabelRib :: new ( kind) ) ;
18131889 let res = f ( self ) ;
1814- self . label_ribs . pop ( ) ;
1890+ self . pop_label_rib ( ) ;
18151891 res
18161892 }
18171893
@@ -1821,9 +1897,13 @@ impl ExprCollector<'_> {
18211897 hygiene : HygieneId ,
18221898 f : impl FnOnce ( & mut Self ) -> T ,
18231899 ) -> T {
1824- self . label_ribs . push ( LabelRib :: new_normal ( ( self . body [ label] . name . clone ( ) , label, hygiene) ) ) ;
1900+ self . label_ribs . push ( LabelRib :: new ( RibKind :: Normal (
1901+ self . body [ label] . name . clone ( ) ,
1902+ label,
1903+ hygiene,
1904+ ) ) ) ;
18251905 let res = f ( self ) ;
1826- self . label_ribs . pop ( ) ;
1906+ self . pop_label_rib ( ) ;
18271907 res
18281908 }
18291909
0 commit comments