@@ -23,46 +23,47 @@ use syntax::{attr, visit};
2323use syntax:: ast;
2424use syntax:: ast:: { Attribute , Block , Crate , DefId , FnDecl , NodeId , Variant } ;
2525use syntax:: ast:: { Item , Generics , StructField } ;
26- use syntax:: ast_util:: is_local;
26+ use syntax:: ast_util:: { is_local, local_def } ;
2727use syntax:: attr:: { Stability , AttrMetaMethods } ;
2828use syntax:: visit:: { FnKind , Visitor } ;
2929use syntax:: feature_gate:: emit_feature_err;
30- use util:: nodemap:: { NodeMap , DefIdMap , FnvHashSet , FnvHashMap } ;
30+ use util:: nodemap:: { DefIdMap , FnvHashSet , FnvHashMap } ;
3131use util:: ppaux:: Repr ;
3232
3333use std:: mem:: replace;
3434
3535/// 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 >
4343}
4444
4545// 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 > ,
5050 export_map : & ' a PublicItems ,
5151}
5252
53- impl < ' a > Annotator < ' a > {
53+ impl < ' a , ' tcx : ' a > Annotator < ' a , ' tcx > {
5454 // Determine the stability for a node based on its attributes and inherited
5555 // stability. The stability is recorded in the index and used as the parent.
5656 fn annotate < F > ( & mut self , id : NodeId , use_parent : bool ,
5757 attrs : & Vec < Attribute > , item_sp : Span , f : F , required : bool ) where
5858 F : FnOnce ( & mut Annotator ) ,
5959 {
60- if self . index . staged_api {
60+ if self . index . staged_api [ & ast :: LOCAL_CRATE ] {
6161 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) {
6363 Some ( stab) => {
6464 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) ) ;
6667
6768 // Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
6869 if stab. level != attr:: Stable {
@@ -77,13 +78,14 @@ impl<'a> Annotator<'a> {
7778 debug ! ( "annotate: not found, use_parent = {:?}, parent = {:?}" ,
7879 use_parent, self . parent) ;
7980 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
8384 && 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") ;
8789 }
8890 }
8991 f ( self ) ;
@@ -95,7 +97,7 @@ impl<'a> Annotator<'a> {
9597 let tag = attr. name ( ) ;
9698 if tag == "unstable" || tag == "stable" || tag == "deprecated" {
9799 attr:: mark_used ( attr) ;
98- self . sess . span_err ( attr. span ( ) ,
100+ self . tcx . sess . span_err ( attr. span ( ) ,
99101 "stability attributes may not be used outside \
100102 of the standard library") ;
101103 }
@@ -105,7 +107,7 @@ impl<'a> Annotator<'a> {
105107 }
106108}
107109
108- impl < ' a , ' v > Visitor < ' v > for Annotator < ' a > {
110+ impl < ' a , ' tcx , ' v > Visitor < ' v > for Annotator < ' a , ' tcx > {
109111 fn visit_item ( & mut self , i : & Item ) {
110112 // FIXME (#18969): the following is a hack around the fact
111113 // that we cannot currently annotate the stability of
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
168170 }
169171}
170172
171- impl Index {
173+ impl < ' tcx > Index < ' tcx > {
172174 /// 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 ) {
174176 let mut annotator = Annotator {
175- sess : sess ,
177+ tcx : tcx ,
176178 index : self ,
177179 parent : None ,
178180 export_map : export_map,
@@ -182,22 +184,23 @@ impl Index {
182184 }
183185
184186 pub fn new ( krate : & Crate ) -> Index {
185- let mut staged_api = false ;
187+ let mut is_staged_api = false ;
186188 for attr in & krate. attrs {
187189 if & attr. name ( ) [ ..] == "staged_api" {
188190 match attr. node . value . node {
189191 ast:: MetaWord ( _) => {
190192 attr:: mark_used ( attr) ;
191- staged_api = true ;
193+ is_staged_api = true ;
192194 }
193195 _ => ( /*pass*/ )
194196 }
195197 }
196198 }
199+ let mut staged_api = FnvHashMap ( ) ;
200+ staged_api. insert ( ast:: LOCAL_CRATE , is_staged_api) ;
197201 Index {
198202 staged_api : staged_api,
199- local : NodeMap ( ) ,
200- extern_cache : DefIdMap ( )
203+ map : DefIdMap ( ) ,
201204 }
202205 }
203206}
@@ -232,13 +235,13 @@ struct Checker<'a, 'tcx: 'a> {
232235}
233236
234237impl < ' 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 > ) {
236239 // Only the cross-crate scenario matters when checking unstable APIs
237240 let cross_crate = !is_local ( id) ;
238241 if !cross_crate { return }
239242
240243 match * stab {
241- Some ( Stability { level : attr:: Unstable , ref feature, ref reason, .. } ) => {
244+ Some ( & Stability { level : attr:: Unstable , ref feature, ref reason, .. } ) => {
242245 self . used_features . insert ( feature. clone ( ) , attr:: Unstable ) ;
243246
244247 if !self . active_features . contains ( feature) {
@@ -252,7 +255,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
252255 & feature, span, & msg) ;
253256 }
254257 }
255- Some ( Stability { level, ref feature, .. } ) => {
258+ Some ( & Stability { level, ref feature, .. } ) => {
256259 self . used_features . insert ( feature. clone ( ) , level) ;
257260
258261 // 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> {
312315
313316/// Helper for discovering nodes to check for stability
314317pub 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 > ) ) {
316319 match item. node {
317320 ast:: ItemExternCrate ( _) => {
318321 // 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,
349352
350353/// Helper for discovering nodes to check for stability
351354pub 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 > ) ) {
353356 let span;
354357 let id = match e. node {
355358 ast:: ExprMethodCall ( i, _, _) => {
@@ -458,7 +461,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
458461}
459462
460463pub 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 > ) ) {
462465 match tcx. def_map . borrow ( ) . get ( & id) . map ( |d| d. full_def ( ) ) {
463466 Some ( def:: DefPrimTy ( ..) ) => { }
464467 Some ( def) => {
@@ -470,7 +473,7 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
470473}
471474
472475pub 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 > ) ) {
474477 debug ! ( "check_pat(pat = {:?})" , pat) ;
475478 if is_internal ( tcx, pat. span ) { return ; }
476479
@@ -511,7 +514,7 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
511514}
512515
513516fn 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 > ) ) {
515518 if !is_staged_api ( tcx, id) { return }
516519 if is_internal ( tcx, span) { return }
517520 let ref stability = lookup ( tcx, id) ;
@@ -528,20 +531,27 @@ fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool {
528531 if trait_method_id != id => {
529532 is_staged_api ( tcx, trait_method_id)
530533 }
531- _ if is_local ( id) => {
532- tcx. stability . borrow ( ) . staged_api
533- }
534534 _ => {
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 ) )
536537 }
537538 }
538539}
539540
540541/// Lookup the stability for a node, loading external crate
541542/// 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) ) ;
545555
546556 // is this definition the implementation of a trait method?
547557 match ty:: trait_item_of_item ( tcx, id) {
@@ -553,25 +563,23 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
553563 }
554564
555565 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
557567 } 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) )
562569 } ;
563570
564571 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+ }
574581 }
582+ None
575583 } )
576584}
577585
0 commit comments