@@ -17,10 +17,11 @@ use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
1717use rustc_parse:: validate_attr;
1818use rustc_session:: lint:: builtin:: PATTERNS_IN_FNS_WITHOUT_BODY ;
1919use rustc_session:: lint:: { BuiltinLintDiagnostics , LintBuffer } ;
20- use rustc_session:: Session ;
20+ use rustc_session:: { DiagnosticMessageId , Session } ;
2121use rustc_span:: source_map:: Spanned ;
2222use rustc_span:: symbol:: { kw, sym, Ident } ;
2323use rustc_span:: Span ;
24+ use std:: convert:: TryInto ;
2425use std:: mem;
2526use std:: ops:: DerefMut ;
2627
@@ -33,24 +34,6 @@ enum SelfSemantic {
3334 No ,
3435}
3536
36- /// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
37- #[ derive( Clone , Copy ) ]
38- enum BoundContext {
39- ImplTrait ,
40- TraitBounds ,
41- TraitObject ,
42- }
43-
44- impl BoundContext {
45- fn description ( & self ) -> & ' static str {
46- match self {
47- Self :: ImplTrait => "`impl Trait`" ,
48- Self :: TraitBounds => "supertraits" ,
49- Self :: TraitObject => "trait objects" ,
50- }
51- }
52- }
53-
5437struct AstValidator < ' a > {
5538 session : & ' a Session ,
5639
@@ -60,18 +43,16 @@ struct AstValidator<'a> {
6043 /// Are we inside a trait impl?
6144 in_trait_impl : bool ,
6245
46+ in_const_trait_impl : bool ,
47+
6348 has_proc_macro_decls : bool ,
6449
6550 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
6651 /// Nested `impl Trait` _is_ allowed in associated type position,
6752 /// e.g., `impl Iterator<Item = impl Debug>`.
6853 outer_impl_trait : Option < Span > ,
6954
70- /// Keeps track of the `BoundContext` as we recurse.
71- ///
72- /// This is used to forbid `?const Trait` bounds in, e.g.,
73- /// `impl Iterator<Item = Box<dyn ?const Trait>`.
74- bound_context : Option < BoundContext > ,
55+ is_tilde_const_allowed : bool ,
7556
7657 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
7758 /// or `Foo::Bar<impl Trait>`
@@ -88,10 +69,18 @@ struct AstValidator<'a> {
8869}
8970
9071impl < ' a > AstValidator < ' a > {
91- fn with_in_trait_impl ( & mut self , is_in : bool , f : impl FnOnce ( & mut Self ) ) {
72+ fn with_in_trait_impl (
73+ & mut self ,
74+ is_in : bool ,
75+ constness : Option < Const > ,
76+ f : impl FnOnce ( & mut Self ) ,
77+ ) {
9278 let old = mem:: replace ( & mut self . in_trait_impl , is_in) ;
79+ let old_const =
80+ mem:: replace ( & mut self . in_const_trait_impl , matches ! ( constness, Some ( Const :: Yes ( _) ) ) ) ;
9381 f ( self ) ;
9482 self . in_trait_impl = old;
83+ self . in_const_trait_impl = old_const;
9584 }
9685
9786 fn with_banned_impl_trait ( & mut self , f : impl FnOnce ( & mut Self ) ) {
@@ -100,6 +89,18 @@ impl<'a> AstValidator<'a> {
10089 self . is_impl_trait_banned = old;
10190 }
10291
92+ fn with_tilde_const_allowed ( & mut self , f : impl FnOnce ( & mut Self ) ) {
93+ let old = mem:: replace ( & mut self . is_tilde_const_allowed , true ) ;
94+ f ( self ) ;
95+ self . is_tilde_const_allowed = old;
96+ }
97+
98+ fn with_banned_tilde_const ( & mut self , f : impl FnOnce ( & mut Self ) ) {
99+ let old = mem:: replace ( & mut self . is_tilde_const_allowed , false ) ;
100+ f ( self ) ;
101+ self . is_tilde_const_allowed = old;
102+ }
103+
103104 fn with_let_allowed ( & mut self , allowed : bool , f : impl FnOnce ( & mut Self , bool ) ) {
104105 let old = mem:: replace ( & mut self . is_let_allowed , allowed) ;
105106 f ( self , old) ;
@@ -130,19 +131,13 @@ impl<'a> AstValidator<'a> {
130131 fn with_impl_trait ( & mut self , outer : Option < Span > , f : impl FnOnce ( & mut Self ) ) {
131132 let old = mem:: replace ( & mut self . outer_impl_trait , outer) ;
132133 if outer. is_some ( ) {
133- self . with_bound_context ( BoundContext :: ImplTrait , |this| f ( this ) ) ;
134+ self . with_banned_tilde_const ( f ) ;
134135 } else {
135- f ( self )
136+ f ( self ) ;
136137 }
137138 self . outer_impl_trait = old;
138139 }
139140
140- fn with_bound_context ( & mut self , ctx : BoundContext , f : impl FnOnce ( & mut Self ) ) {
141- let old = self . bound_context . replace ( ctx) ;
142- f ( self ) ;
143- self . bound_context = old;
144- }
145-
146141 fn visit_assoc_ty_constraint_from_generic_args ( & mut self , constraint : & ' a AssocTyConstraint ) {
147142 match constraint. kind {
148143 AssocTyConstraintKind :: Equality { .. } => { }
@@ -164,9 +159,7 @@ impl<'a> AstValidator<'a> {
164159 TyKind :: ImplTrait ( ..) => {
165160 self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) )
166161 }
167- TyKind :: TraitObject ( ..) => {
168- self . with_bound_context ( BoundContext :: TraitObject , |this| visit:: walk_ty ( this, t) ) ;
169- }
162+ TyKind :: TraitObject ( ..) => self . with_banned_tilde_const ( |this| visit:: walk_ty ( this, t) ) ,
170163 TyKind :: Path ( ref qself, ref path) => {
171164 // We allow these:
172165 // - `Option<impl Trait>`
@@ -1083,13 +1076,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10831076 unsafety,
10841077 polarity,
10851078 defaultness : _,
1086- constness : _ ,
1087- generics : _ ,
1079+ constness,
1080+ ref generics ,
10881081 of_trait : Some ( ref t) ,
10891082 ref self_ty,
1090- items : _ ,
1083+ ref items ,
10911084 } ) => {
1092- self . with_in_trait_impl ( true , |this| {
1085+ self . with_in_trait_impl ( true , Some ( constness ) , |this| {
10931086 this. invalid_visibility ( & item. vis , None ) ;
10941087 if let TyKind :: Err = self_ty. kind {
10951088 this. err_handler ( )
@@ -1112,7 +1105,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11121105 . emit ( ) ;
11131106 }
11141107
1115- visit:: walk_item ( this, item) ;
1108+ this. visit_vis ( & item. vis ) ;
1109+ this. visit_ident ( item. ident ) ;
1110+ if let Const :: Yes ( _) = constness {
1111+ this. with_tilde_const_allowed ( |this| this. visit_generics ( generics) ) ;
1112+ } else {
1113+ this. visit_generics ( generics) ;
1114+ }
1115+ this. visit_trait_ref ( t) ;
1116+ this. visit_ty ( self_ty) ;
1117+
1118+ walk_list ! ( this, visit_assoc_item, items, AssocCtxt :: Impl ) ;
11161119 } ) ;
11171120 return ; // Avoid visiting again.
11181121 }
@@ -1157,13 +1160,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11571160 . emit ( ) ;
11581161 }
11591162 }
1160- ItemKind :: Fn ( box FnKind ( def, _ , _ , ref body) ) => {
1163+ ItemKind :: Fn ( box FnKind ( def, ref sig , ref generics , ref body) ) => {
11611164 self . check_defaultness ( item. span , def) ;
11621165
11631166 if body. is_none ( ) {
11641167 let msg = "free function without a body" ;
11651168 self . error_item_without_body ( item. span , "function" , msg, " { <body> }" ) ;
11661169 }
1170+ self . visit_vis ( & item. vis ) ;
1171+ self . visit_ident ( item. ident ) ;
1172+ if let Const :: Yes ( _) = sig. header . constness {
1173+ self . with_tilde_const_allowed ( |this| this. visit_generics ( generics) ) ;
1174+ } else {
1175+ self . visit_generics ( generics) ;
1176+ }
1177+ let kind = FnKind :: Fn ( FnCtxt :: Free , item. ident , sig, & item. vis , body. as_deref ( ) ) ;
1178+ self . visit_fn ( kind, item. span , item. id ) ;
1179+ walk_list ! ( self , visit_attribute, & item. attrs) ;
11671180 }
11681181 ItemKind :: ForeignMod ( ForeignMod { unsafety, .. } ) => {
11691182 let old_item = mem:: replace ( & mut self . extern_mod , Some ( item) ) ;
@@ -1206,9 +1219,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12061219 self . visit_vis ( & item. vis ) ;
12071220 self . visit_ident ( item. ident ) ;
12081221 self . visit_generics ( generics) ;
1209- self . with_bound_context ( BoundContext :: TraitBounds , |this| {
1210- walk_list ! ( this, visit_param_bound, bounds) ;
1211- } ) ;
1222+ self . with_banned_tilde_const ( |this| walk_list ! ( this, visit_param_bound, bounds) ) ;
12121223 walk_list ! ( self , visit_assoc_item, trait_items, AssocCtxt :: Trait ) ;
12131224 walk_list ! ( self , visit_attribute, & item. attrs) ;
12141225 return ;
@@ -1281,7 +1292,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12811292 _ => { }
12821293 }
12831294
1284- visit:: walk_item ( self , item)
1295+ visit:: walk_item ( self , item) ;
12851296 }
12861297
12871298 fn visit_foreign_item ( & mut self , fi : & ' a ForeignItem ) {
@@ -1428,15 +1439,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14281439 fn visit_param_bound ( & mut self , bound : & ' a GenericBound ) {
14291440 match bound {
14301441 GenericBound :: Trait ( _, TraitBoundModifier :: MaybeConst ) => {
1431- if let Some ( ctx) = self . bound_context {
1432- let msg = format ! ( "`?const` is not permitted in {}" , ctx. description( ) ) ;
1433- self . err_handler ( ) . span_err ( bound. span ( ) , & msg) ;
1442+ if !self . is_tilde_const_allowed {
1443+ let msg = "`~const` is not allowed here" ;
1444+ let id_span_msg = (
1445+ DiagnosticMessageId :: StabilityId ( 67792 . try_into ( ) . ok ( ) ) ,
1446+ Some ( bound. span ( ) ) ,
1447+ msg. to_owned ( ) ,
1448+ ) ;
1449+ let fresh = self . session . one_time_diagnostics . borrow_mut ( ) . insert ( id_span_msg) ;
1450+ if fresh {
1451+ self . err_handler ( )
1452+ . struct_span_err ( bound. span ( ) , msg)
1453+ . note ( "only allowed on bounds on traits' associated types, const fns, const impls and its associated functions" )
1454+ . emit ( ) ;
1455+ }
14341456 }
14351457 }
14361458
14371459 GenericBound :: Trait ( _, TraitBoundModifier :: MaybeConstMaybe ) => {
14381460 self . err_handler ( )
1439- . span_err ( bound. span ( ) , "`? const` and `?` are mutually exclusive" ) ;
1461+ . span_err ( bound. span ( ) , "`~ const` and `?` are mutually exclusive" ) ;
14401462 }
14411463
14421464 _ => { }
@@ -1589,7 +1611,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15891611 self . check_item_named ( item. ident , "const" ) ;
15901612 }
15911613
1592- self . with_in_trait_impl ( false , |this| visit:: walk_assoc_item ( this, item, ctxt) ) ;
1614+ match item. kind {
1615+ AssocItemKind :: TyAlias ( box TyAliasKind ( _, ref generics, ref bounds, ref ty) )
1616+ if ctxt == AssocCtxt :: Trait =>
1617+ {
1618+ self . visit_vis ( & item. vis ) ;
1619+ self . visit_ident ( item. ident ) ;
1620+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1621+ self . with_tilde_const_allowed ( |this| {
1622+ this. visit_generics ( generics) ;
1623+ walk_list ! ( this, visit_param_bound, bounds) ;
1624+ } ) ;
1625+ walk_list ! ( self , visit_ty, ty) ;
1626+ }
1627+ AssocItemKind :: Fn ( box FnKind ( _, ref sig, ref generics, ref body) )
1628+ if self . in_const_trait_impl =>
1629+ {
1630+ self . visit_vis ( & item. vis ) ;
1631+ self . visit_ident ( item. ident ) ;
1632+ self . with_tilde_const_allowed ( |this| this. visit_generics ( generics) ) ;
1633+ let kind =
1634+ FnKind :: Fn ( FnCtxt :: Assoc ( ctxt) , item. ident , sig, & item. vis , body. as_deref ( ) ) ;
1635+ self . visit_fn ( kind, item. span , item. id ) ;
1636+ }
1637+ _ => self
1638+ . with_in_trait_impl ( false , None , |this| visit:: walk_assoc_item ( this, item, ctxt) ) ,
1639+ }
15931640 }
15941641}
15951642
@@ -1683,9 +1730,10 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
16831730 session,
16841731 extern_mod : None ,
16851732 in_trait_impl : false ,
1733+ in_const_trait_impl : false ,
16861734 has_proc_macro_decls : false ,
16871735 outer_impl_trait : None ,
1688- bound_context : None ,
1736+ is_tilde_const_allowed : false ,
16891737 is_impl_trait_banned : false ,
16901738 is_assoc_ty_bound_banned : false ,
16911739 is_let_allowed : false ,
0 commit comments