@@ -10,7 +10,7 @@ use either::Either;
10
10
use hir_expand:: {
11
11
name:: { AsName , Name } ,
12
12
span_map:: { ExpansionSpanMap , SpanMap } ,
13
- InFile ,
13
+ InFile , MacroDefId ,
14
14
} ;
15
15
use intern:: { sym, Interned , Symbol } ;
16
16
use rustc_hash:: FxHashMap ;
@@ -39,16 +39,16 @@ use crate::{
39
39
FormatPlaceholder , FormatSign , FormatTrait ,
40
40
} ,
41
41
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 ,
44
44
} ,
45
45
item_scope:: BuiltinShadowMode ,
46
46
lang_item:: LangItem ,
47
47
lower:: LowerCtx ,
48
48
nameres:: { DefMap , MacroSubNs } ,
49
49
path:: { GenericArgs , Path } ,
50
50
type_ref:: { Mutability , Rawness , TypeRef } ,
51
- AdtId , BlockId , BlockLoc , ConstBlockLoc , DefWithBodyId , ModuleDefId , UnresolvedMacro ,
51
+ AdtId , BlockId , BlockLoc , ConstBlockLoc , DefWithBodyId , MacroId , ModuleDefId , UnresolvedMacro ,
52
52
} ;
53
53
54
54
type FxIndexSet < K > = indexmap:: IndexSet < K , std:: hash:: BuildHasherDefault < rustc_hash:: FxHasher > > ;
@@ -88,6 +88,7 @@ pub(super) fn lower(
88
88
current_binding_owner : None ,
89
89
awaitable_context : None ,
90
90
current_span_map : span_map,
91
+ current_block_legacy_macro_defs_count : FxHashMap :: default ( ) ,
91
92
}
92
93
. collect ( params, body, is_async_fn)
93
94
}
@@ -104,6 +105,10 @@ struct ExprCollector<'a> {
104
105
105
106
is_lowering_coroutine : bool ,
106
107
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
+
107
112
current_span_map : Option < Arc < ExpansionSpanMap > > ,
108
113
109
114
current_try_block_label : Option < LabelId > ,
@@ -124,31 +129,27 @@ struct ExprCollector<'a> {
124
129
#[ derive( Clone , Debug ) ]
125
130
struct LabelRib {
126
131
kind : RibKind ,
127
- // Once we handle macro hygiene this will need to be a map
128
- label : Option < ( Name , LabelId , HygieneId ) > ,
129
132
}
130
133
131
134
impl LabelRib {
132
135
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 }
137
137
}
138
138
}
139
139
140
- #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
140
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
141
141
enum RibKind {
142
- Normal ,
142
+ Normal ( Name , LabelId , HygieneId ) ,
143
143
Closure ,
144
144
Constant ,
145
+ MacroDef ( Box < MacroDefId > ) ,
145
146
}
146
147
147
148
impl RibKind {
148
149
/// This rib forbids referring to labels defined in upwards ribs.
149
- fn is_label_barrier ( self ) -> bool {
150
+ fn is_label_barrier ( & self ) -> bool {
150
151
match self {
151
- RibKind :: Normal => false ,
152
+ RibKind :: Normal ( .. ) | RibKind :: MacroDef ( _ ) => false ,
152
153
RibKind :: Closure | RibKind :: Constant => true ,
153
154
}
154
155
}
@@ -1350,10 +1351,46 @@ impl ExprCollector<'_> {
1350
1351
statements. push ( Statement :: Expr { expr, has_semi } ) ;
1351
1352
}
1352
1353
}
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 ) ) ,
1354
1380
}
1355
1381
}
1356
1382
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
+
1357
1394
fn collect_block ( & mut self , block : ast:: BlockExpr ) -> ExprId {
1358
1395
self . collect_block_ ( block, |id, statements, tail| Expr :: Block {
1359
1396
id,
@@ -1399,6 +1436,7 @@ impl ExprCollector<'_> {
1399
1436
} ;
1400
1437
let prev_def_map = mem:: replace ( & mut self . def_map , def_map) ;
1401
1438
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 ) ;
1402
1440
1403
1441
let mut statements = Vec :: new ( ) ;
1404
1442
block. statements ( ) . for_each ( |s| self . collect_stmt ( & mut statements, s) ) ;
@@ -1421,6 +1459,7 @@ impl ExprCollector<'_> {
1421
1459
1422
1460
self . def_map = prev_def_map;
1423
1461
self . expander . module = prev_local_module;
1462
+ self . current_block_legacy_macro_defs_count = prev_legacy_macros_count;
1424
1463
expr_id
1425
1464
}
1426
1465
@@ -1780,21 +1819,51 @@ impl ExprCollector<'_> {
1780
1819
lifetime : Option < ast:: Lifetime > ,
1781
1820
) -> Result < Option < LabelId > , BodyDiagnostic > {
1782
1821
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
+ } ;
1784
1835
let name = Name :: new_lifetime ( & lifetime) ;
1785
1836
1786
1837
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
+ }
1797
1865
}
1866
+ _ => { }
1798
1867
}
1799
1868
}
1800
1869
@@ -1808,10 +1877,17 @@ impl ExprCollector<'_> {
1808
1877
!self . label_ribs [ rib_index + 1 ..] . iter ( ) . any ( |rib| rib. kind . is_label_barrier ( ) )
1809
1878
}
1810
1879
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
+
1811
1887
fn with_label_rib < T > ( & mut self , kind : RibKind , f : impl FnOnce ( & mut Self ) -> T ) -> T {
1812
1888
self . label_ribs . push ( LabelRib :: new ( kind) ) ;
1813
1889
let res = f ( self ) ;
1814
- self . label_ribs . pop ( ) ;
1890
+ self . pop_label_rib ( ) ;
1815
1891
res
1816
1892
}
1817
1893
@@ -1821,9 +1897,13 @@ impl ExprCollector<'_> {
1821
1897
hygiene : HygieneId ,
1822
1898
f : impl FnOnce ( & mut Self ) -> T ,
1823
1899
) -> 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
+ ) ) ) ;
1825
1905
let res = f ( self ) ;
1826
- self . label_ribs . pop ( ) ;
1906
+ self . pop_label_rib ( ) ;
1827
1907
res
1828
1908
}
1829
1909
0 commit comments