@@ -24,6 +24,23 @@ use syntax::walk_list;
2424
2525use rustc_error_codes:: * ;
2626
27+ #[ derive( Clone , Copy ) ]
28+ enum BoundContext {
29+ ImplTrait ,
30+ TraitBounds ,
31+ TraitObject ,
32+ }
33+
34+ impl BoundContext {
35+ fn description ( & self ) -> & ' static str {
36+ match self {
37+ Self :: ImplTrait => "`impl Trait`" ,
38+ Self :: TraitBounds => "supertraits" ,
39+ Self :: TraitObject => "trait objects" ,
40+ }
41+ }
42+ }
43+
2744struct AstValidator < ' a > {
2845 session : & ' a Session ,
2946 has_proc_macro_decls : bool ,
@@ -33,6 +50,11 @@ struct AstValidator<'a> {
3350 /// e.g., `impl Iterator<Item = impl Debug>`.
3451 outer_impl_trait : Option < Span > ,
3552
53+ /// Tracks the context in which a bound can appear.
54+ ///
55+ /// This is used to forbid `?const Trait` bounds in certain contexts.
56+ bound_context_stack : Vec < Option < BoundContext > > ,
57+
3658 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
3759 /// or `Foo::Bar<impl Trait>`
3860 is_impl_trait_banned : bool ,
@@ -58,9 +80,21 @@ impl<'a> AstValidator<'a> {
5880 }
5981
6082 fn with_impl_trait ( & mut self , outer : Option < Span > , f : impl FnOnce ( & mut Self ) ) {
83+ self . bound_context_stack . push ( outer. map ( |_| BoundContext :: ImplTrait ) ) ;
6184 let old = mem:: replace ( & mut self . outer_impl_trait , outer) ;
6285 f ( self ) ;
6386 self . outer_impl_trait = old;
87+ self . bound_context_stack . pop ( ) ;
88+ }
89+
90+ fn with_bound_context ( & mut self , ctx : Option < BoundContext > , f : impl FnOnce ( & mut Self ) ) {
91+ self . bound_context_stack . push ( ctx) ;
92+ f ( self ) ;
93+ self . bound_context_stack . pop ( ) ;
94+ }
95+
96+ fn innermost_bound_context ( & mut self ) -> Option < BoundContext > {
97+ self . bound_context_stack . iter ( ) . rev ( ) . find ( |x| x. is_some ( ) ) . copied ( ) . flatten ( )
6498 }
6599
66100 fn visit_assoc_ty_constraint_from_generic_args ( & mut self , constraint : & ' a AssocTyConstraint ) {
@@ -84,6 +118,11 @@ impl<'a> AstValidator<'a> {
84118 TyKind :: ImplTrait ( ..) => {
85119 self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) )
86120 }
121+ TyKind :: TraitObject ( ..) => {
122+ self . with_bound_context ( Some ( BoundContext :: TraitObject ) , |this| {
123+ visit:: walk_ty ( this, t)
124+ } ) ;
125+ }
87126 TyKind :: Path ( ref qself, ref path) => {
88127 // We allow these:
89128 // - `Option<impl Trait>`
@@ -192,6 +231,8 @@ impl<'a> AstValidator<'a> {
192231 }
193232 }
194233
234+ // FIXME(ecstaticmorse): Instead, use the `bound_context_stack` to check this in
235+ // `visit_param_bound`.
195236 fn no_questions_in_bounds ( & self , bounds : & GenericBounds , where_ : & str , is_trait : bool ) {
196237 for bound in bounds {
197238 if let GenericBound :: Trait ( ref poly, TraitBoundModifier :: Maybe ) = * bound {
@@ -697,6 +738,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
697738 }
698739 }
699740 self . no_questions_in_bounds ( bounds, "supertraits" , true ) ;
741+
742+ // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
743+ // context for the supertraits.
744+ self . visit_generics ( generics) ;
745+ self . with_bound_context ( Some ( BoundContext :: TraitBounds ) , |this| {
746+ walk_list ! ( this, visit_param_bound, bounds) ;
747+ } ) ;
748+ walk_list ! ( self , visit_trait_item, trait_items) ;
749+ return ;
700750 }
701751 ItemKind :: Mod ( _) => {
702752 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
@@ -841,6 +891,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
841891 visit:: walk_generic_param ( self , param) ;
842892 }
843893
894+ fn visit_param_bound ( & mut self , bound : & ' a GenericBound ) {
895+ if let GenericBound :: Trait ( poly, maybe_bound) = bound {
896+ match poly. trait_ref . constness {
897+ Some ( Constness :: NotConst ) => {
898+ if * maybe_bound == TraitBoundModifier :: Maybe {
899+ self . err_handler ( )
900+ . span_err ( bound. span ( ) , "`?const` and `?` are mutually exclusive" ) ;
901+ }
902+
903+ if let Some ( ctx) = self . innermost_bound_context ( ) {
904+ let msg = format ! ( "`?const` is not permitted in {}" , ctx. description( ) ) ;
905+ self . err_handler ( ) . span_err ( bound. span ( ) , & msg) ;
906+ }
907+ }
908+
909+ Some ( Constness :: Const ) => bug ! ( "Parser should reject bare `const` on bounds" ) ,
910+ None => { }
911+ }
912+ }
913+
914+ visit:: walk_param_bound ( self , bound)
915+ }
916+
844917 fn visit_pat ( & mut self , pat : & ' a Pat ) {
845918 match pat. kind {
846919 PatKind :: Lit ( ref expr) => {
@@ -949,6 +1022,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffe
9491022 session,
9501023 has_proc_macro_decls : false ,
9511024 outer_impl_trait : None ,
1025+ bound_context_stack : Vec :: new ( ) ,
9521026 is_impl_trait_banned : false ,
9531027 is_assoc_ty_bound_banned : false ,
9541028 lint_buffer : lints,
0 commit comments