@@ -36,11 +36,32 @@ use rustc_back::slice;
3636use hir;
3737use hir:: intravisit:: { self , Visitor , NestedVisitorMap } ;
3838
39+ /// The origin of a named lifetime definition.
40+ ///
41+ /// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax.
42+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , RustcEncodable , RustcDecodable , Debug ) ]
43+ pub enum LifetimeDefOrigin {
44+ // Explicit binders like `fn foo<'a>(x: &'a u8)`
45+ Explicit ,
46+ // In-band declarations like `fn foo(x: &'a u8)`
47+ InBand ,
48+ }
49+
50+ impl LifetimeDefOrigin {
51+ fn from_is_in_band ( is_in_band : bool ) -> Self {
52+ if is_in_band {
53+ LifetimeDefOrigin :: InBand
54+ } else {
55+ LifetimeDefOrigin :: Explicit
56+ }
57+ }
58+ }
59+
3960#[ derive( Clone , Copy , PartialEq , Eq , Hash , RustcEncodable , RustcDecodable , Debug ) ]
4061pub enum Region {
4162 Static ,
42- EarlyBound ( /* index */ u32 , /* lifetime decl */ DefId ) ,
43- LateBound ( ty:: DebruijnIndex , /* lifetime decl */ DefId ) ,
63+ EarlyBound ( /* index */ u32 , /* lifetime decl */ DefId , LifetimeDefOrigin ) ,
64+ LateBound ( ty:: DebruijnIndex , /* lifetime decl */ DefId , LifetimeDefOrigin ) ,
4465 LateBoundAnon ( ty:: DebruijnIndex , /* anon index */ u32 ) ,
4566 Free ( DefId , /* lifetime decl */ DefId ) ,
4667}
@@ -52,14 +73,16 @@ impl Region {
5273 let i = * index;
5374 * index += 1 ;
5475 let def_id = hir_map. local_def_id ( def. lifetime . id ) ;
76+ let origin = LifetimeDefOrigin :: from_is_in_band ( def. in_band ) ;
5577 debug ! ( "Region::early: index={} def_id={:?}" , i, def_id) ;
56- ( def. lifetime . name , Region :: EarlyBound ( i, def_id) )
78+ ( def. lifetime . name , Region :: EarlyBound ( i, def_id, origin ) )
5779 }
5880
5981 fn late ( hir_map : & Map , def : & hir:: LifetimeDef ) -> ( hir:: LifetimeName , Region ) {
6082 let depth = ty:: DebruijnIndex :: new ( 1 ) ;
6183 let def_id = hir_map. local_def_id ( def. lifetime . id ) ;
62- ( def. lifetime . name , Region :: LateBound ( depth, def_id) )
84+ let origin = LifetimeDefOrigin :: from_is_in_band ( def. in_band ) ;
85+ ( def. lifetime . name , Region :: LateBound ( depth, def_id, origin) )
6386 }
6487
6588 fn late_anon ( index : & Cell < u32 > ) -> Region {
@@ -74,16 +97,16 @@ impl Region {
7497 Region :: Static |
7598 Region :: LateBoundAnon ( ..) => None ,
7699
77- Region :: EarlyBound ( _, id) |
78- Region :: LateBound ( _, id) |
100+ Region :: EarlyBound ( _, id, _ ) |
101+ Region :: LateBound ( _, id, _ ) |
79102 Region :: Free ( _, id) => Some ( id)
80103 }
81104 }
82105
83106 fn shifted ( self , amount : u32 ) -> Region {
84107 match self {
85- Region :: LateBound ( depth, id) => {
86- Region :: LateBound ( depth. shifted ( amount) , id)
108+ Region :: LateBound ( depth, id, origin ) => {
109+ Region :: LateBound ( depth. shifted ( amount) , id, origin )
87110 }
88111 Region :: LateBoundAnon ( depth, index) => {
89112 Region :: LateBoundAnon ( depth. shifted ( amount) , index)
@@ -94,10 +117,10 @@ impl Region {
94117
95118 fn from_depth ( self , depth : u32 ) -> Region {
96119 match self {
97- Region :: LateBound ( debruijn, id) => {
120+ Region :: LateBound ( debruijn, id, origin ) => {
98121 Region :: LateBound ( ty:: DebruijnIndex {
99122 depth : debruijn. depth - ( depth - 1 )
100- } , id)
123+ } , id, origin )
101124 }
102125 Region :: LateBoundAnon ( debruijn, index) => {
103126 Region :: LateBoundAnon ( ty:: DebruijnIndex {
@@ -110,7 +133,7 @@ impl Region {
110133
111134 fn subst ( self , params : & [ hir:: Lifetime ] , map : & NamedRegionMap )
112135 -> Option < Region > {
113- if let Region :: EarlyBound ( index, _) = self {
136+ if let Region :: EarlyBound ( index, _, _ ) = self {
114137 params. get ( index as usize ) . and_then ( |lifetime| {
115138 map. defs . get ( & lifetime. id ) . cloned ( )
116139 } )
@@ -187,6 +210,9 @@ struct LifetimeContext<'a, 'tcx: 'a> {
187210 // I'm sorry.
188211 trait_ref_hack : bool ,
189212
213+ // Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
214+ is_in_fn_syntax : bool ,
215+
190216 // List of labels in the function/method currently under analysis.
191217 labels_in_fn : Vec < ( ast:: Name , Span ) > ,
192218
@@ -280,6 +306,7 @@ pub fn krate(sess: &Session,
280306 map : & mut map,
281307 scope : ROOT_SCOPE ,
282308 trait_ref_hack : false ,
309+ is_in_fn_syntax : false ,
283310 labels_in_fn : vec ! [ ] ,
284311 xcrate_object_lifetime_defaults : DefIdMap ( ) ,
285312 } ;
@@ -384,6 +411,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
384411 match ty. node {
385412 hir:: TyBareFn ( ref c) => {
386413 let next_early_index = self . next_early_index ( ) ;
414+ let was_in_fn_syntax = self . is_in_fn_syntax ;
415+ self . is_in_fn_syntax = true ;
387416 let scope = Scope :: Binder {
388417 lifetimes : c. lifetimes . iter ( ) . map ( |def| {
389418 Region :: late ( self . hir_map , def)
@@ -397,6 +426,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
397426 this. check_lifetime_defs ( old_scope, & c. lifetimes ) ;
398427 intravisit:: walk_ty ( this, ty) ;
399428 } ) ;
429+ self . is_in_fn_syntax = was_in_fn_syntax;
400430 }
401431 hir:: TyTraitObject ( ref bounds, ref lifetime) => {
402432 for bound in bounds {
@@ -430,7 +460,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
430460 // well-supported at the moment, so this doesn't work.
431461 // In the future, this should be fixed and this error should be removed.
432462 let def = self . map . defs . get ( & lifetime. id ) ;
433- if let Some ( & Region :: LateBound ( _, def_id) ) = def {
463+ if let Some ( & Region :: LateBound ( _, def_id, _ ) ) = def {
434464 if let Some ( node_id) = self . hir_map . as_local_node_id ( def_id) {
435465 // Ensure that the parent of the def is an item, not HRTB
436466 let parent_id = self . hir_map . get_parent_node ( node_id) ;
@@ -528,6 +558,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
528558 }
529559
530560 fn visit_generics ( & mut self , generics : & ' tcx hir:: Generics ) {
561+ check_mixed_explicit_and_in_band_defs ( & self . sess , & generics. lifetimes ) ;
531562 for ty_param in generics. ty_params . iter ( ) {
532563 walk_list ! ( self , visit_ty_param_bound, & ty_param. bounds) ;
533564 if let Some ( ref ty) = ty_param. default {
@@ -639,6 +670,22 @@ impl ShadowKind {
639670 }
640671}
641672
673+ fn check_mixed_explicit_and_in_band_defs (
674+ sess : & Session ,
675+ lifetime_defs : & [ hir:: LifetimeDef ] ,
676+ ) {
677+ let oob_def = lifetime_defs. iter ( ) . find ( |lt| !lt. in_band ) ;
678+ let in_band_def = lifetime_defs. iter ( ) . find ( |lt| lt. in_band ) ;
679+
680+ if let ( Some ( oob_def) , Some ( in_band_def) ) = ( oob_def, in_band_def) {
681+ struct_span_err ! ( sess, in_band_def. lifetime. span, E0688 ,
682+ "cannot mix in-band and explicit lifetime definitions" )
683+ . span_label ( in_band_def. lifetime . span , "in-band lifetime definition here" )
684+ . span_label ( oob_def. lifetime . span , "explicit lifetime definition here" )
685+ . emit ( ) ;
686+ }
687+ }
688+
642689fn signal_shadowing_problem ( sess : & Session , name : ast:: Name , orig : Original , shadower : Shadower ) {
643690 let mut err = if let ( ShadowKind :: Lifetime , ShadowKind :: Lifetime ) = ( orig. kind , shadower. kind ) {
644691 // lifetime/lifetime shadowing is an error
@@ -767,7 +814,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
767814 match * set {
768815 Set1 :: Empty => "BaseDefault" . to_string ( ) ,
769816 Set1 :: One ( Region :: Static ) => "'static" . to_string ( ) ,
770- Set1 :: One ( Region :: EarlyBound ( i, _) ) => {
817+ Set1 :: One ( Region :: EarlyBound ( i, _, _ ) ) => {
771818 generics. lifetimes [ i as usize ] . lifetime . name . name ( ) . to_string ( )
772819 }
773820 Set1 :: One ( _) => bug ! ( ) ,
@@ -837,7 +884,8 @@ fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
837884 def. lifetime . name == name
838885 } ) . map_or ( Set1 :: Many , |( i, def) | {
839886 let def_id = hir_map. local_def_id ( def. lifetime . id ) ;
840- Set1 :: One ( Region :: EarlyBound ( i as u32 , def_id) )
887+ let origin = LifetimeDefOrigin :: from_is_in_band ( def. in_band ) ;
888+ Set1 :: One ( Region :: EarlyBound ( i as u32 , def_id, origin) )
841889 } )
842890 }
843891 }
@@ -868,6 +916,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
868916 map : * map,
869917 scope : & wrap_scope,
870918 trait_ref_hack : self . trait_ref_hack ,
919+ is_in_fn_syntax : self . is_in_fn_syntax ,
871920 labels_in_fn,
872921 xcrate_object_lifetime_defaults,
873922 } ;
@@ -1020,6 +1069,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
10201069 _ => { }
10211070 }
10221071 }
1072+
1073+ // Check for fn-syntax conflicts with in-band lifetime definitions
1074+ if self . is_in_fn_syntax {
1075+ match def {
1076+ Region :: EarlyBound ( _, _, LifetimeDefOrigin :: InBand ) |
1077+ Region :: LateBound ( _, _, LifetimeDefOrigin :: InBand ) => {
1078+ struct_span_err ! ( self . sess, lifetime_ref. span, E0687 ,
1079+ "lifetimes used in `fn` or `Fn` syntax must be \
1080+ explicitly declared using `<...>` binders")
1081+ . span_label ( lifetime_ref. span ,
1082+ "in-band lifetime definition" )
1083+ . emit ( ) ;
1084+ } ,
1085+
1086+ Region :: Static |
1087+ Region :: EarlyBound ( _, _, LifetimeDefOrigin :: Explicit ) |
1088+ Region :: LateBound ( _, _, LifetimeDefOrigin :: Explicit ) |
1089+ Region :: LateBoundAnon ( ..) |
1090+ Region :: Free ( ..) => { }
1091+ }
1092+ }
1093+
10231094 self . insert_lifetime ( lifetime_ref, def) ;
10241095 } else {
10251096 struct_span_err ! ( self . sess, lifetime_ref. span, E0261 ,
@@ -1033,8 +1104,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
10331104 def : Def ,
10341105 depth : usize ,
10351106 params : & ' tcx hir:: PathParameters ) {
1107+
10361108 if params. parenthesized {
1109+ let was_in_fn_syntax = self . is_in_fn_syntax ;
1110+ self . is_in_fn_syntax = true ;
10371111 self . visit_fn_like_elision ( params. inputs ( ) , Some ( & params. bindings [ 0 ] . ty ) ) ;
1112+ self . is_in_fn_syntax = was_in_fn_syntax;
10381113 return ;
10391114 }
10401115
@@ -1355,7 +1430,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
13551430 fn visit_lifetime ( & mut self , lifetime_ref : & hir:: Lifetime ) {
13561431 if let Some ( & lifetime) = self . map . defs . get ( & lifetime_ref. id ) {
13571432 match lifetime {
1358- Region :: LateBound ( debruijn, _) |
1433+ Region :: LateBound ( debruijn, _, _ ) |
13591434 Region :: LateBoundAnon ( debruijn, _)
13601435 if debruijn. depth < self . binder_depth => {
13611436 self . have_bound_regions = true ;
0 commit comments