@@ -22,10 +22,14 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
22
22
use syntax:: ext:: tt:: macro_rules;
23
23
use syntax:: parse:: token:: intern;
24
24
use syntax:: util:: lev_distance:: find_best_match_for_name;
25
+ use syntax_pos:: { Span , DUMMY_SP } ;
25
26
26
27
// FIXME(jseyfried) Merge with `::NameBinding`.
27
28
pub struct NameBinding {
28
- ext : Rc < SyntaxExtension > ,
29
+ pub ext : Rc < SyntaxExtension > ,
30
+ pub expansion : Mark ,
31
+ pub shadowing : bool ,
32
+ pub span : Span ,
29
33
}
30
34
31
35
#[ derive( Clone ) ]
@@ -69,24 +73,26 @@ impl<'a> base::Resolver for Resolver<'a> {
69
73
fn visit_expansion ( & mut self , mark : Mark , expansion : & Expansion ) {
70
74
self . collect_def_ids ( mark, expansion) ;
71
75
self . current_module = self . expansion_data [ & mark] . module ;
72
- expansion. visit_with ( & mut BuildReducedGraphVisitor { resolver : self } ) ;
76
+ expansion. visit_with ( & mut BuildReducedGraphVisitor { resolver : self , expansion : mark } ) ;
73
77
}
74
78
75
79
fn add_macro ( & mut self , scope : Mark , mut def : ast:: MacroDef ) {
76
80
if & def. ident . name . as_str ( ) == "macro_rules" {
77
81
self . session . span_err ( def. span , "user-defined macros may not be named `macro_rules`" ) ;
78
82
}
79
83
if def. use_locally {
80
- self . macro_names . insert ( def. ident . name ) ;
81
- let ext = macro_rules:: compile ( & self . session . parse_sess , & def) ;
82
-
83
- let mut module = self . expansion_data [ & scope] . module ;
84
+ let ExpansionData { mut module, backtrace, .. } = self . expansion_data [ & scope] ;
84
85
while module. macros_escape {
85
86
module = module. parent . unwrap ( ) ;
86
87
}
87
- module. macros . borrow_mut ( ) . insert ( def. ident . name , NameBinding {
88
- ext : Rc :: new ( ext) ,
89
- } ) ;
88
+ let binding = NameBinding {
89
+ ext : Rc :: new ( macro_rules:: compile ( & self . session . parse_sess , & def) ) ,
90
+ expansion : backtrace. data ( ) . prev_ctxt . data ( ) . outer_mark ,
91
+ shadowing : self . resolve_macro_name ( scope, def. ident . name , false ) . is_some ( ) ,
92
+ span : def. span ,
93
+ } ;
94
+ module. macros . borrow_mut ( ) . insert ( def. ident . name , binding) ;
95
+ self . macro_names . insert ( def. ident . name ) ;
90
96
}
91
97
if def. export {
92
98
def. id = self . next_node_id ( ) ;
@@ -100,6 +106,9 @@ impl<'a> base::Resolver for Resolver<'a> {
100
106
}
101
107
self . graph_root . macros . borrow_mut ( ) . insert ( ident. name , NameBinding {
102
108
ext : ext,
109
+ expansion : Mark :: root ( ) ,
110
+ shadowing : false ,
111
+ span : DUMMY_SP ,
103
112
} ) ;
104
113
}
105
114
@@ -138,7 +147,7 @@ impl<'a> base::Resolver for Resolver<'a> {
138
147
InvocationKind :: Attr { ref attr, .. } => ( intern ( & * attr. name ( ) ) , attr. span ) ,
139
148
} ;
140
149
141
- self . resolve_macro_name ( scope, name) . or_else ( || {
150
+ self . resolve_macro_name ( scope, name, true ) . or_else ( || {
142
151
let mut err =
143
152
self . session . struct_span_err ( span, & format ! ( "macro undefined: '{}!'" , name) ) ;
144
153
self . suggest_macro_name ( & name. as_str ( ) , & mut err) ;
@@ -153,10 +162,28 @@ impl<'a> base::Resolver for Resolver<'a> {
153
162
}
154
163
155
164
impl < ' a > Resolver < ' a > {
156
- fn resolve_macro_name ( & mut self , scope : Mark , name : ast:: Name ) -> Option < Rc < SyntaxExtension > > {
157
- let mut module = self . expansion_data [ & scope] . module ;
165
+ pub fn resolve_macro_name ( & mut self , scope : Mark , name : ast:: Name , record_used : bool )
166
+ -> Option < Rc < SyntaxExtension > > {
167
+ let ExpansionData { mut module, backtrace, .. } = self . expansion_data [ & scope] ;
158
168
loop {
159
169
if let Some ( binding) = module. macros . borrow ( ) . get ( & name) {
170
+ let mut backtrace = backtrace. data ( ) ;
171
+ while binding. expansion != backtrace. outer_mark {
172
+ if backtrace. outer_mark != Mark :: root ( ) {
173
+ backtrace = backtrace. prev_ctxt . data ( ) ;
174
+ continue
175
+ }
176
+
177
+ if record_used && binding. shadowing &&
178
+ self . macro_shadowing_errors . insert ( binding. span ) {
179
+ let msg = format ! ( "`{}` is already in scope" , name) ;
180
+ self . session . struct_span_err ( binding. span , & msg)
181
+ . note ( "macro-expanded `macro_rules!`s and `#[macro_use]`s \
182
+ may not shadow existing macros (see RFC 1560)")
183
+ . emit ( ) ;
184
+ }
185
+ break
186
+ }
160
187
return Some ( binding. ext . clone ( ) ) ;
161
188
}
162
189
match module. parent {
0 commit comments