@@ -23,46 +23,47 @@ use syntax::{attr, visit};
23
23
use syntax:: ast;
24
24
use syntax:: ast:: { Attribute , Block , Crate , DefId , FnDecl , NodeId , Variant } ;
25
25
use syntax:: ast:: { Item , Generics , StructField } ;
26
- use syntax:: ast_util:: is_local;
26
+ use syntax:: ast_util:: { is_local, local_def } ;
27
27
use syntax:: attr:: { Stability , AttrMetaMethods } ;
28
28
use syntax:: visit:: { FnKind , Visitor } ;
29
29
use syntax:: feature_gate:: emit_feature_err;
30
- use util:: nodemap:: { NodeMap , DefIdMap , FnvHashSet , FnvHashMap } ;
30
+ use util:: nodemap:: { DefIdMap , FnvHashSet , FnvHashMap } ;
31
31
use util:: ppaux:: Repr ;
32
32
33
33
use std:: mem:: replace;
34
34
35
35
/// A stability index, giving the stability level for items and methods.
36
- pub struct Index {
37
- // Indicates whether this crate has #![feature(staged_api)]
38
- staged_api : bool ,
39
- // stability for crate-local items; unmarked stability == no entry
40
- local : NodeMap < Stability > ,
41
- // cache for extern- crate items; unmarked stability == entry with None
42
- extern_cache : DefIdMap < Option < Stability > >
36
+ pub struct Index < ' tcx > {
37
+ /// This is mostly a cache, except the stabilities of local items
38
+ /// are filled by the annotator.
39
+ map : DefIdMap < Option < & ' tcx Stability > > ,
40
+
41
+ /// Maps for each crate whether it is part of the staged API.
42
+ staged_api : FnvHashMap < ast :: CrateNum , bool >
43
43
}
44
44
45
45
// A private tree-walker for producing an Index.
46
- struct Annotator < ' a > {
47
- sess : & ' a Session ,
48
- index : & ' a mut Index ,
49
- parent : Option < Stability > ,
46
+ struct Annotator < ' a , ' tcx : ' a > {
47
+ tcx : & ' a ty :: ctxt < ' tcx > ,
48
+ index : & ' a mut Index < ' tcx > ,
49
+ parent : Option < & ' tcx Stability > ,
50
50
export_map : & ' a PublicItems ,
51
51
}
52
52
53
- impl < ' a > Annotator < ' a > {
53
+ impl < ' a , ' tcx : ' a > Annotator < ' a , ' tcx > {
54
54
// Determine the stability for a node based on its attributes and inherited
55
55
// stability. The stability is recorded in the index and used as the parent.
56
56
fn annotate < F > ( & mut self , id : NodeId , use_parent : bool ,
57
57
attrs : & Vec < Attribute > , item_sp : Span , f : F , required : bool ) where
58
58
F : FnOnce ( & mut Annotator ) ,
59
59
{
60
- if self . index . staged_api {
60
+ if self . index . staged_api [ & ast :: LOCAL_CRATE ] {
61
61
debug ! ( "annotate(id = {:?}, attrs = {:?})" , id, attrs) ;
62
- match attr:: find_stability ( self . sess . diagnostic ( ) , attrs, item_sp) {
62
+ match attr:: find_stability ( self . tcx . sess . diagnostic ( ) , attrs, item_sp) {
63
63
Some ( stab) => {
64
64
debug ! ( "annotate: found {:?}" , stab) ;
65
- self . index . local . insert ( id, stab. clone ( ) ) ;
65
+ let stab = self . tcx . intern_stability ( stab) ;
66
+ self . index . map . insert ( local_def ( id) , Some ( stab) ) ;
66
67
67
68
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
68
69
if stab. level != attr:: Stable {
@@ -77,13 +78,14 @@ impl<'a> Annotator<'a> {
77
78
debug ! ( "annotate: not found, use_parent = {:?}, parent = {:?}" ,
78
79
use_parent, self . parent) ;
79
80
if use_parent {
80
- if let Some ( stab) = self . parent . clone ( ) {
81
- self . index . local . insert ( id , stab) ;
82
- } else if self . index . staged_api && required
81
+ if let Some ( stab) = self . parent {
82
+ self . index . map . insert ( local_def ( id ) , Some ( stab) ) ;
83
+ } else if self . index . staged_api [ & ast :: LOCAL_CRATE ] && required
83
84
&& self . export_map . contains ( & id)
84
- && !self . sess . opts . test {
85
- self . sess . span_err ( item_sp,
86
- "This node does not have a stability attribute" ) ;
85
+ && !self . tcx . sess . opts . test {
86
+ self . tcx . sess . span_err ( item_sp,
87
+ "This node does not \
88
+ have a stability attribute") ;
87
89
}
88
90
}
89
91
f ( self ) ;
@@ -95,7 +97,7 @@ impl<'a> Annotator<'a> {
95
97
let tag = attr. name ( ) ;
96
98
if tag == "unstable" || tag == "stable" || tag == "deprecated" {
97
99
attr:: mark_used ( attr) ;
98
- self . sess . span_err ( attr. span ( ) ,
100
+ self . tcx . sess . span_err ( attr. span ( ) ,
99
101
"stability attributes may not be used outside \
100
102
of the standard library") ;
101
103
}
@@ -105,7 +107,7 @@ impl<'a> Annotator<'a> {
105
107
}
106
108
}
107
109
108
- impl < ' a , ' v > Visitor < ' v > for Annotator < ' a > {
110
+ impl < ' a , ' tcx , ' v > Visitor < ' v > for Annotator < ' a , ' tcx > {
109
111
fn visit_item ( & mut self , i : & Item ) {
110
112
// FIXME (#18969): the following is a hack around the fact
111
113
// that we cannot currently annotate the stability of
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
168
170
}
169
171
}
170
172
171
- impl Index {
173
+ impl < ' tcx > Index < ' tcx > {
172
174
/// Construct the stability index for a crate being compiled.
173
- pub fn build ( & mut self , sess : & Session , krate : & Crate , export_map : & PublicItems ) {
175
+ pub fn build ( & mut self , tcx : & ty :: ctxt < ' tcx > , krate : & Crate , export_map : & PublicItems ) {
174
176
let mut annotator = Annotator {
175
- sess : sess ,
177
+ tcx : tcx ,
176
178
index : self ,
177
179
parent : None ,
178
180
export_map : export_map,
@@ -182,22 +184,23 @@ impl Index {
182
184
}
183
185
184
186
pub fn new ( krate : & Crate ) -> Index {
185
- let mut staged_api = false ;
187
+ let mut is_staged_api = false ;
186
188
for attr in & krate. attrs {
187
189
if & attr. name ( ) [ ..] == "staged_api" {
188
190
match attr. node . value . node {
189
191
ast:: MetaWord ( _) => {
190
192
attr:: mark_used ( attr) ;
191
- staged_api = true ;
193
+ is_staged_api = true ;
192
194
}
193
195
_ => ( /*pass*/ )
194
196
}
195
197
}
196
198
}
199
+ let mut staged_api = FnvHashMap ( ) ;
200
+ staged_api. insert ( ast:: LOCAL_CRATE , is_staged_api) ;
197
201
Index {
198
202
staged_api : staged_api,
199
- local : NodeMap ( ) ,
200
- extern_cache : DefIdMap ( )
203
+ map : DefIdMap ( ) ,
201
204
}
202
205
}
203
206
}
@@ -232,13 +235,13 @@ struct Checker<'a, 'tcx: 'a> {
232
235
}
233
236
234
237
impl < ' a , ' tcx > Checker < ' a , ' tcx > {
235
- fn check ( & mut self , id : ast:: DefId , span : Span , stab : & Option < Stability > ) {
238
+ fn check ( & mut self , id : ast:: DefId , span : Span , stab : & Option < & Stability > ) {
236
239
// Only the cross-crate scenario matters when checking unstable APIs
237
240
let cross_crate = !is_local ( id) ;
238
241
if !cross_crate { return }
239
242
240
243
match * stab {
241
- Some ( Stability { level : attr:: Unstable , ref feature, ref reason, .. } ) => {
244
+ Some ( & Stability { level : attr:: Unstable , ref feature, ref reason, .. } ) => {
242
245
self . used_features . insert ( feature. clone ( ) , attr:: Unstable ) ;
243
246
244
247
if !self . active_features . contains ( feature) {
@@ -252,7 +255,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
252
255
& feature, span, & msg) ;
253
256
}
254
257
}
255
- Some ( Stability { level, ref feature, .. } ) => {
258
+ Some ( & Stability { level, ref feature, .. } ) => {
256
259
self . used_features . insert ( feature. clone ( ) , level) ;
257
260
258
261
// Stable APIs are always ok to call and deprecated APIs are
@@ -312,7 +315,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
312
315
313
316
/// Helper for discovering nodes to check for stability
314
317
pub fn check_item ( tcx : & ty:: ctxt , item : & ast:: Item , warn_about_defns : bool ,
315
- cb : & mut FnMut ( ast:: DefId , Span , & Option < Stability > ) ) {
318
+ cb : & mut FnMut ( ast:: DefId , Span , & Option < & Stability > ) ) {
316
319
match item. node {
317
320
ast:: ItemExternCrate ( _) => {
318
321
// compiler-generated `extern crate` items have a dummy span.
@@ -349,7 +352,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
349
352
350
353
/// Helper for discovering nodes to check for stability
351
354
pub fn check_expr ( tcx : & ty:: ctxt , e : & ast:: Expr ,
352
- cb : & mut FnMut ( ast:: DefId , Span , & Option < Stability > ) ) {
355
+ cb : & mut FnMut ( ast:: DefId , Span , & Option < & Stability > ) ) {
353
356
let span;
354
357
let id = match e. node {
355
358
ast:: ExprMethodCall ( i, _, _) => {
@@ -458,7 +461,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
458
461
}
459
462
460
463
pub fn check_path ( tcx : & ty:: ctxt , path : & ast:: Path , id : ast:: NodeId ,
461
- cb : & mut FnMut ( ast:: DefId , Span , & Option < Stability > ) ) {
464
+ cb : & mut FnMut ( ast:: DefId , Span , & Option < & Stability > ) ) {
462
465
match tcx. def_map . borrow ( ) . get ( & id) . map ( |d| d. full_def ( ) ) {
463
466
Some ( def:: DefPrimTy ( ..) ) => { }
464
467
Some ( def) => {
@@ -470,7 +473,7 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
470
473
}
471
474
472
475
pub fn check_pat ( tcx : & ty:: ctxt , pat : & ast:: Pat ,
473
- cb : & mut FnMut ( ast:: DefId , Span , & Option < Stability > ) ) {
476
+ cb : & mut FnMut ( ast:: DefId , Span , & Option < & Stability > ) ) {
474
477
debug ! ( "check_pat(pat = {:?})" , pat) ;
475
478
if is_internal ( tcx, pat. span ) { return ; }
476
479
@@ -511,7 +514,7 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
511
514
}
512
515
513
516
fn maybe_do_stability_check ( tcx : & ty:: ctxt , id : ast:: DefId , span : Span ,
514
- cb : & mut FnMut ( ast:: DefId , Span , & Option < Stability > ) ) {
517
+ cb : & mut FnMut ( ast:: DefId , Span , & Option < & Stability > ) ) {
515
518
if !is_staged_api ( tcx, id) { return }
516
519
if is_internal ( tcx, span) { return }
517
520
let ref stability = lookup ( tcx, id) ;
@@ -528,20 +531,27 @@ fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool {
528
531
if trait_method_id != id => {
529
532
is_staged_api ( tcx, trait_method_id)
530
533
}
531
- _ if is_local ( id) => {
532
- tcx. stability . borrow ( ) . staged_api
533
- }
534
534
_ => {
535
- csearch:: is_staged_api ( & tcx. sess . cstore , id)
535
+ * tcx. stability . borrow_mut ( ) . staged_api . entry ( id. krate ) . or_insert_with (
536
+ || csearch:: is_staged_api ( & tcx. sess . cstore , id. krate ) )
536
537
}
537
538
}
538
539
}
539
540
540
541
/// Lookup the stability for a node, loading external crate
541
542
/// metadata as necessary.
542
- pub fn lookup ( tcx : & ty:: ctxt , id : DefId ) -> Option < Stability > {
543
- debug ! ( "lookup(id={})" ,
544
- id. repr( tcx) ) ;
543
+ pub fn lookup < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , id : DefId ) -> Option < & ' tcx Stability > {
544
+ if let Some ( st) = tcx. stability . borrow ( ) . map . get ( & id) {
545
+ return * st;
546
+ }
547
+
548
+ let st = lookup_uncached ( tcx, id) ;
549
+ tcx. stability . borrow_mut ( ) . map . insert ( id, st) ;
550
+ st
551
+ }
552
+
553
+ fn lookup_uncached < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , id : DefId ) -> Option < & ' tcx Stability > {
554
+ debug ! ( "lookup(id={})" , id. repr( tcx) ) ;
545
555
546
556
// is this definition the implementation of a trait method?
547
557
match ty:: trait_item_of_item ( tcx, id) {
@@ -553,25 +563,23 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
553
563
}
554
564
555
565
let item_stab = if is_local ( id) {
556
- tcx . stability . borrow ( ) . local . get ( & id . node ) . cloned ( )
566
+ None // The stability cache is filled partially lazily
557
567
} else {
558
- let stab = csearch:: get_stability ( & tcx. sess . cstore , id) ;
559
- let mut index = tcx. stability . borrow_mut ( ) ;
560
- ( * index) . extern_cache . insert ( id, stab. clone ( ) ) ;
561
- stab
568
+ csearch:: get_stability ( & tcx. sess . cstore , id) . map ( |st| tcx. intern_stability ( st) )
562
569
} ;
563
570
564
571
item_stab. or_else ( || {
565
- if let Some ( trait_id ) = ty:: trait_id_of_impl ( tcx, id) {
566
- // FIXME (#18969): for the time being, simply use the
567
- // stability of the trait to determine the stability of any
568
- // unmarked impls for it. See FIXME above for more details.
569
-
570
- debug ! ( "lookup: trait_id={:?}" , trait_id ) ;
571
- lookup ( tcx , trait_id)
572
- } else {
573
- None
572
+ if ty:: is_impl ( tcx, id) {
573
+ if let Some ( trait_id ) = ty :: trait_id_of_impl ( tcx , id ) {
574
+ // FIXME (#18969): for the time being, simply use the
575
+ // stability of the trait to determine the stability of any
576
+ // unmarked impls for it. See FIXME above for more details.
577
+
578
+ debug ! ( "lookup: trait_id={:?}" , trait_id) ;
579
+ return lookup ( tcx , trait_id ) ;
580
+ }
574
581
}
582
+ None
575
583
} )
576
584
}
577
585
0 commit comments