@@ -46,18 +46,29 @@ enum DisallowTildeConstContext<'a> {
4646 Item ,
4747}
4848
49+ enum TraitOrTraitImpl < ' a > {
50+ Trait { span : Span , constness : Option < Span > } ,
51+ TraitImpl { constness : Const , polarity : ImplPolarity , trait_ref : & ' a TraitRef } ,
52+ }
53+
54+ impl < ' a > TraitOrTraitImpl < ' a > {
55+ fn constness ( & self ) -> Option < Span > {
56+ match self {
57+ Self :: Trait { constness : Some ( span) , .. }
58+ | Self :: TraitImpl { constness : Const :: Yes ( span) , .. } => Some ( * span) ,
59+ _ => None ,
60+ }
61+ }
62+ }
63+
4964struct AstValidator < ' a > {
5065 session : & ' a Session ,
5166 features : & ' a Features ,
5267
5368 /// The span of the `extern` in an `extern { ... }` block, if any.
5469 extern_mod : Option < & ' a Item > ,
5570
56- /// Are we inside a trait impl?
57- in_trait_impl : bool ,
58-
59- /// Are we inside a const trait defn or impl?
60- in_const_trait_or_impl : bool ,
71+ outer_trait_or_trait_impl : Option < TraitOrTraitImpl < ' a > > ,
6172
6273 has_proc_macro_decls : bool ,
6374
@@ -78,24 +89,28 @@ struct AstValidator<'a> {
7889impl < ' a > AstValidator < ' a > {
7990 fn with_in_trait_impl (
8091 & mut self ,
81- is_in : bool ,
82- constness : Option < Const > ,
92+ trait_ : Option < ( Const , ImplPolarity , & ' a TraitRef ) > ,
8393 f : impl FnOnce ( & mut Self ) ,
8494 ) {
85- let old = mem:: replace ( & mut self . in_trait_impl , is_in) ;
86- let old_const = mem:: replace (
87- & mut self . in_const_trait_or_impl ,
88- matches ! ( constness, Some ( Const :: Yes ( _) ) ) ,
95+ let old = mem:: replace (
96+ & mut self . outer_trait_or_trait_impl ,
97+ trait_. map ( |( constness, polarity, trait_ref) | TraitOrTraitImpl :: TraitImpl {
98+ constness,
99+ polarity,
100+ trait_ref,
101+ } ) ,
89102 ) ;
90103 f ( self ) ;
91- self . in_trait_impl = old;
92- self . in_const_trait_or_impl = old_const;
104+ self . outer_trait_or_trait_impl = old;
93105 }
94106
95- fn with_in_trait ( & mut self , is_const : bool , f : impl FnOnce ( & mut Self ) ) {
96- let old = mem:: replace ( & mut self . in_const_trait_or_impl , is_const) ;
107+ fn with_in_trait ( & mut self , span : Span , constness : Option < Span > , f : impl FnOnce ( & mut Self ) ) {
108+ let old = mem:: replace (
109+ & mut self . outer_trait_or_trait_impl ,
110+ Some ( TraitOrTraitImpl :: Trait { span, constness } ) ,
111+ ) ;
97112 f ( self ) ;
98- self . in_const_trait_or_impl = old;
113+ self . outer_trait_or_trait_impl = old;
99114 }
100115
101116 fn with_banned_impl_trait ( & mut self , f : impl FnOnce ( & mut Self ) ) {
@@ -291,10 +306,48 @@ impl<'a> AstValidator<'a> {
291306 }
292307 }
293308
294- fn check_trait_fn_not_const ( & self , constness : Const ) {
295- if let Const :: Yes ( span) = constness {
296- self . dcx ( ) . emit_err ( errors:: TraitFnConst { span } ) ;
297- }
309+ fn check_trait_fn_not_const ( & self , constness : Const , parent : & TraitOrTraitImpl < ' a > ) {
310+ let Const :: Yes ( span) = constness else {
311+ return ;
312+ } ;
313+
314+ let make_impl_const_sugg = if self . features . const_trait_impl
315+ && let TraitOrTraitImpl :: TraitImpl {
316+ constness : Const :: No ,
317+ polarity : ImplPolarity :: Positive ,
318+ trait_ref,
319+ } = parent
320+ {
321+ Some ( trait_ref. path . span . shrink_to_lo ( ) )
322+ } else {
323+ None
324+ } ;
325+
326+ let make_trait_const_sugg = if self . features . const_trait_impl
327+ && let TraitOrTraitImpl :: Trait { span, constness : None } = parent
328+ {
329+ Some ( span. shrink_to_lo ( ) )
330+ } else {
331+ None
332+ } ;
333+
334+ let parent_constness = parent. constness ( ) ;
335+ self . dcx ( ) . emit_err ( errors:: TraitFnConst {
336+ span,
337+ in_impl : matches ! ( parent, TraitOrTraitImpl :: TraitImpl { .. } ) ,
338+ const_context_label : parent_constness,
339+ remove_const_sugg : (
340+ self . session . source_map ( ) . span_extend_while ( span, |c| c == ' ' ) . unwrap_or ( span) ,
341+ match parent_constness {
342+ Some ( _) => rustc_errors:: Applicability :: MachineApplicable ,
343+ None => rustc_errors:: Applicability :: MaybeIncorrect ,
344+ } ,
345+ ) ,
346+ requires_multiple_changes : make_impl_const_sugg. is_some ( )
347+ || make_trait_const_sugg. is_some ( ) ,
348+ make_impl_const_sugg,
349+ make_trait_const_sugg,
350+ } ) ;
298351 }
299352
300353 fn check_fn_decl ( & self , fn_decl : & FnDecl , self_semantic : SelfSemantic ) {
@@ -817,7 +870,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
817870 self_ty,
818871 items,
819872 } ) => {
820- self . with_in_trait_impl ( true , Some ( * constness) , |this| {
873+ self . with_in_trait_impl ( Some ( ( * constness, * polarity , t ) ) , |this| {
821874 this. visibility_not_permitted (
822875 & item. vis ,
823876 errors:: VisibilityNotPermittedNote :: TraitImpl ,
@@ -963,8 +1016,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9631016 }
9641017 }
9651018 ItemKind :: Trait ( box Trait { is_auto, generics, bounds, items, .. } ) => {
966- let is_const_trait = attr:: contains_name ( & item. attrs , sym:: const_trait) ;
967- self . with_in_trait ( is_const_trait, |this| {
1019+ let is_const_trait =
1020+ attr:: find_by_name ( & item. attrs , sym:: const_trait) . map ( |attr| attr. span ) ;
1021+ self . with_in_trait ( item. span , is_const_trait, |this| {
9681022 if * is_auto == IsAuto :: Yes {
9691023 // Auto traits cannot have generics, super traits nor contain items.
9701024 this. deny_generic_params ( generics, item. ident . span ) ;
@@ -977,8 +1031,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9771031 // context for the supertraits.
9781032 this. visit_vis ( & item. vis ) ;
9791033 this. visit_ident ( item. ident ) ;
980- let disallowed =
981- ( !is_const_trait) . then ( || DisallowTildeConstContext :: Trait ( item. span ) ) ;
1034+ let disallowed = is_const_trait
1035+ . is_none ( )
1036+ . then ( || DisallowTildeConstContext :: Trait ( item. span ) ) ;
9821037 this. with_tilde_const ( disallowed, |this| {
9831038 this. visit_generics ( generics) ;
9841039 walk_list ! ( this, visit_param_bound, bounds, BoundKind :: SuperTraits )
@@ -1342,7 +1397,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13421397
13431398 let tilde_const_allowed =
13441399 matches ! ( fk. header( ) , Some ( FnHeader { constness: ast:: Const :: Yes ( _) , .. } ) )
1345- || matches ! ( fk. ctxt( ) , Some ( FnCtxt :: Assoc ( _) ) if self . in_const_trait_or_impl) ;
1400+ || matches ! ( fk. ctxt( ) , Some ( FnCtxt :: Assoc ( _) ) )
1401+ && self
1402+ . outer_trait_or_trait_impl
1403+ . as_ref ( )
1404+ . and_then ( TraitOrTraitImpl :: constness)
1405+ . is_some ( ) ;
13461406
13471407 let disallowed = ( !tilde_const_allowed) . then ( || DisallowTildeConstContext :: Fn ( fk) ) ;
13481408 self . with_tilde_const ( disallowed, |this| visit:: walk_fn ( this, fk) ) ;
@@ -1353,7 +1413,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13531413 self . check_nomangle_item_asciionly ( item. ident , item. span ) ;
13541414 }
13551415
1356- if ctxt == AssocCtxt :: Trait || ! self . in_trait_impl {
1416+ if ctxt == AssocCtxt :: Trait || self . outer_trait_or_trait_impl . is_none ( ) {
13571417 self . check_defaultness ( item. span , item. kind . defaultness ( ) ) ;
13581418 }
13591419
@@ -1401,10 +1461,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14011461 ) ;
14021462 }
14031463
1404- if ctxt == AssocCtxt :: Trait || self . in_trait_impl {
1464+ if let Some ( parent ) = & self . outer_trait_or_trait_impl {
14051465 self . visibility_not_permitted ( & item. vis , errors:: VisibilityNotPermittedNote :: TraitImpl ) ;
14061466 if let AssocItemKind :: Fn ( box Fn { sig, .. } ) = & item. kind {
1407- self . check_trait_fn_not_const ( sig. header . constness ) ;
1467+ self . check_trait_fn_not_const ( sig. header . constness , parent ) ;
14081468 }
14091469 }
14101470
@@ -1414,7 +1474,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14141474
14151475 match & item. kind {
14161476 AssocItemKind :: Fn ( box Fn { sig, generics, body, .. } )
1417- if self . in_const_trait_or_impl
1477+ if self
1478+ . outer_trait_or_trait_impl
1479+ . as_ref ( )
1480+ . and_then ( TraitOrTraitImpl :: constness)
1481+ . is_some ( )
14181482 || ctxt == AssocCtxt :: Trait
14191483 || matches ! ( sig. header. constness, Const :: Yes ( _) ) =>
14201484 {
@@ -1430,8 +1494,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14301494 ) ;
14311495 self . visit_fn ( kind, item. span , item. id ) ;
14321496 }
1433- _ => self
1434- . with_in_trait_impl ( false , None , |this| visit:: walk_assoc_item ( this, item, ctxt) ) ,
1497+ _ => self . with_in_trait_impl ( None , |this| visit:: walk_assoc_item ( this, item, ctxt) ) ,
14351498 }
14361499 }
14371500}
@@ -1547,8 +1610,7 @@ pub fn check_crate(
15471610 session,
15481611 features,
15491612 extern_mod : None ,
1550- in_trait_impl : false ,
1551- in_const_trait_or_impl : false ,
1613+ outer_trait_or_trait_impl : None ,
15521614 has_proc_macro_decls : false ,
15531615 outer_impl_trait : None ,
15541616 disallow_tilde_const : Some ( DisallowTildeConstContext :: Item ) ,
0 commit comments