@@ -17,10 +17,11 @@ use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
17
17
use rustc_parse:: validate_attr;
18
18
use rustc_session:: lint:: builtin:: PATTERNS_IN_FNS_WITHOUT_BODY ;
19
19
use rustc_session:: lint:: { BuiltinLintDiagnostics , LintBuffer } ;
20
- use rustc_session:: Session ;
20
+ use rustc_session:: { DiagnosticMessageId , Session } ;
21
21
use rustc_span:: source_map:: Spanned ;
22
22
use rustc_span:: symbol:: { kw, sym, Ident } ;
23
23
use rustc_span:: Span ;
24
+ use std:: convert:: TryInto ;
24
25
use std:: mem;
25
26
use std:: ops:: DerefMut ;
26
27
@@ -33,24 +34,6 @@ enum SelfSemantic {
33
34
No ,
34
35
}
35
36
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
-
54
37
struct AstValidator < ' a > {
55
38
session : & ' a Session ,
56
39
@@ -60,18 +43,16 @@ struct AstValidator<'a> {
60
43
/// Are we inside a trait impl?
61
44
in_trait_impl : bool ,
62
45
46
+ in_const_trait_impl : bool ,
47
+
63
48
has_proc_macro_decls : bool ,
64
49
65
50
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
66
51
/// Nested `impl Trait` _is_ allowed in associated type position,
67
52
/// e.g., `impl Iterator<Item = impl Debug>`.
68
53
outer_impl_trait : Option < Span > ,
69
54
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 ,
75
56
76
57
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
77
58
/// or `Foo::Bar<impl Trait>`
@@ -88,10 +69,18 @@ struct AstValidator<'a> {
88
69
}
89
70
90
71
impl < ' 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
+ ) {
92
78
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 ( _) ) ) ) ;
93
81
f ( self ) ;
94
82
self . in_trait_impl = old;
83
+ self . in_const_trait_impl = old_const;
95
84
}
96
85
97
86
fn with_banned_impl_trait ( & mut self , f : impl FnOnce ( & mut Self ) ) {
@@ -100,6 +89,18 @@ impl<'a> AstValidator<'a> {
100
89
self . is_impl_trait_banned = old;
101
90
}
102
91
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
+
103
104
fn with_let_allowed ( & mut self , allowed : bool , f : impl FnOnce ( & mut Self , bool ) ) {
104
105
let old = mem:: replace ( & mut self . is_let_allowed , allowed) ;
105
106
f ( self , old) ;
@@ -130,19 +131,13 @@ impl<'a> AstValidator<'a> {
130
131
fn with_impl_trait ( & mut self , outer : Option < Span > , f : impl FnOnce ( & mut Self ) ) {
131
132
let old = mem:: replace ( & mut self . outer_impl_trait , outer) ;
132
133
if outer. is_some ( ) {
133
- self . with_bound_context ( BoundContext :: ImplTrait , |this| f ( this ) ) ;
134
+ self . with_banned_tilde_const ( f ) ;
134
135
} else {
135
- f ( self )
136
+ f ( self ) ;
136
137
}
137
138
self . outer_impl_trait = old;
138
139
}
139
140
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
-
146
141
fn visit_assoc_ty_constraint_from_generic_args ( & mut self , constraint : & ' a AssocTyConstraint ) {
147
142
match constraint. kind {
148
143
AssocTyConstraintKind :: Equality { .. } => { }
@@ -164,9 +159,7 @@ impl<'a> AstValidator<'a> {
164
159
TyKind :: ImplTrait ( ..) => {
165
160
self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) )
166
161
}
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) ) ,
170
163
TyKind :: Path ( ref qself, ref path) => {
171
164
// We allow these:
172
165
// - `Option<impl Trait>`
@@ -1083,13 +1076,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1083
1076
unsafety,
1084
1077
polarity,
1085
1078
defaultness : _,
1086
- constness : _ ,
1087
- generics : _ ,
1079
+ constness,
1080
+ ref generics ,
1088
1081
of_trait : Some ( ref t) ,
1089
1082
ref self_ty,
1090
- items : _ ,
1083
+ ref items ,
1091
1084
} ) => {
1092
- self . with_in_trait_impl ( true , |this| {
1085
+ self . with_in_trait_impl ( true , Some ( constness ) , |this| {
1093
1086
this. invalid_visibility ( & item. vis , None ) ;
1094
1087
if let TyKind :: Err = self_ty. kind {
1095
1088
this. err_handler ( )
@@ -1112,7 +1105,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1112
1105
. emit ( ) ;
1113
1106
}
1114
1107
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 ) ;
1116
1119
} ) ;
1117
1120
return ; // Avoid visiting again.
1118
1121
}
@@ -1157,13 +1160,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1157
1160
. emit ( ) ;
1158
1161
}
1159
1162
}
1160
- ItemKind :: Fn ( box FnKind ( def, _ , _ , ref body) ) => {
1163
+ ItemKind :: Fn ( box FnKind ( def, ref sig , ref generics , ref body) ) => {
1161
1164
self . check_defaultness ( item. span , def) ;
1162
1165
1163
1166
if body. is_none ( ) {
1164
1167
let msg = "free function without a body" ;
1165
1168
self . error_item_without_body ( item. span , "function" , msg, " { <body> }" ) ;
1166
1169
}
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) ;
1167
1180
}
1168
1181
ItemKind :: ForeignMod ( ForeignMod { unsafety, .. } ) => {
1169
1182
let old_item = mem:: replace ( & mut self . extern_mod , Some ( item) ) ;
@@ -1206,9 +1219,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1206
1219
self . visit_vis ( & item. vis ) ;
1207
1220
self . visit_ident ( item. ident ) ;
1208
1221
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) ) ;
1212
1223
walk_list ! ( self , visit_assoc_item, trait_items, AssocCtxt :: Trait ) ;
1213
1224
walk_list ! ( self , visit_attribute, & item. attrs) ;
1214
1225
return ;
@@ -1281,7 +1292,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1281
1292
_ => { }
1282
1293
}
1283
1294
1284
- visit:: walk_item ( self , item)
1295
+ visit:: walk_item ( self , item) ;
1285
1296
}
1286
1297
1287
1298
fn visit_foreign_item ( & mut self , fi : & ' a ForeignItem ) {
@@ -1428,15 +1439,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1428
1439
fn visit_param_bound ( & mut self , bound : & ' a GenericBound ) {
1429
1440
match bound {
1430
1441
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
+ }
1434
1456
}
1435
1457
}
1436
1458
1437
1459
GenericBound :: Trait ( _, TraitBoundModifier :: MaybeConstMaybe ) => {
1438
1460
self . err_handler ( )
1439
- . span_err ( bound. span ( ) , "`? const` and `?` are mutually exclusive" ) ;
1461
+ . span_err ( bound. span ( ) , "`~ const` and `?` are mutually exclusive" ) ;
1440
1462
}
1441
1463
1442
1464
_ => { }
@@ -1589,7 +1611,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1589
1611
self . check_item_named ( item. ident , "const" ) ;
1590
1612
}
1591
1613
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
+ }
1593
1640
}
1594
1641
}
1595
1642
@@ -1683,9 +1730,10 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
1683
1730
session,
1684
1731
extern_mod : None ,
1685
1732
in_trait_impl : false ,
1733
+ in_const_trait_impl : false ,
1686
1734
has_proc_macro_decls : false ,
1687
1735
outer_impl_trait : None ,
1688
- bound_context : None ,
1736
+ is_tilde_const_allowed : false ,
1689
1737
is_impl_trait_banned : false ,
1690
1738
is_assoc_ty_bound_banned : false ,
1691
1739
is_let_allowed : false ,
0 commit comments