@@ -6,7 +6,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
66use rustc_error_codes:: * ;
77use rustc_errors:: { pluralize, Applicability , PResult } ;
88use rustc_span:: source_map:: Span ;
9- use rustc_span:: symbol:: kw ;
9+ use rustc_span:: symbol:: { kw , sym } ;
1010use syntax:: ast:: {
1111 self , BareFnTy , FunctionRetTy , GenericParam , Ident , Lifetime , MutTy , Ty , TyKind ,
1212} ;
@@ -18,6 +18,24 @@ use syntax::ptr::P;
1818use syntax:: struct_span_err;
1919use syntax:: token:: { self , Token } ;
2020
21+ /// Any `?` or `?const` modifiers that appear at the start of a bound.
22+ struct BoundModifiers {
23+ /// `?Trait`.
24+ maybe : Option < Span > ,
25+
26+ /// `?const Trait`.
27+ maybe_const : Option < Span > ,
28+ }
29+
30+ impl BoundModifiers {
31+ fn trait_bound_modifier ( & self ) -> TraitBoundModifier {
32+ match self . maybe {
33+ Some ( _) => TraitBoundModifier :: Maybe ,
34+ None => TraitBoundModifier :: None ,
35+ }
36+ }
37+ }
38+
2139/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
2240/// `IDENT<<u8 as Trait>::AssocTy>`.
2341///
@@ -196,7 +214,9 @@ impl<'a> Parser<'a> {
196214 lo : Span ,
197215 parse_plus : bool ,
198216 ) -> PResult < ' a , TyKind > {
199- let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, lo. to ( self . prev_span ) ) ;
217+ assert_ne ! ( self . token, token:: Question ) ;
218+
219+ let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, None , lo. to ( self . prev_span ) ) ;
200220 let mut bounds = vec ! [ GenericBound :: Trait ( poly_trait_ref, TraitBoundModifier :: None ) ] ;
201221 if parse_plus {
202222 self . eat_plus ( ) ; // `+`, or `+=` gets split and `+` is discarded
@@ -422,12 +442,15 @@ impl<'a> Parser<'a> {
422442 let has_parens = self . eat ( & token:: OpenDelim ( token:: Paren ) ) ;
423443 let inner_lo = self . token . span ;
424444 let is_negative = self . eat ( & token:: Not ) ;
425- let question = self . eat ( & token:: Question ) . then_some ( self . prev_span ) ;
445+
446+ let modifiers = self . parse_ty_bound_modifiers ( ) ;
426447 let bound = if self . token . is_lifetime ( ) {
427- self . parse_generic_lt_bound ( lo, inner_lo, has_parens, question) ?
448+ self . error_lt_bound_with_modifiers ( modifiers) ;
449+ self . parse_generic_lt_bound ( lo, inner_lo, has_parens) ?
428450 } else {
429- self . parse_generic_ty_bound ( lo, has_parens, question ) ?
451+ self . parse_generic_ty_bound ( lo, has_parens, modifiers ) ?
430452 } ;
453+
431454 Ok ( if is_negative { Err ( anchor_lo. to ( self . prev_span ) ) } else { Ok ( bound) } )
432455 }
433456
@@ -440,9 +463,7 @@ impl<'a> Parser<'a> {
440463 lo : Span ,
441464 inner_lo : Span ,
442465 has_parens : bool ,
443- question : Option < Span > ,
444466 ) -> PResult < ' a , GenericBound > {
445- self . error_opt_out_lifetime ( question) ;
446467 let bound = GenericBound :: Outlives ( self . expect_lifetime ( ) ) ;
447468 if has_parens {
448469 // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
@@ -452,8 +473,17 @@ impl<'a> Parser<'a> {
452473 Ok ( bound)
453474 }
454475
455- fn error_opt_out_lifetime ( & self , question : Option < Span > ) {
456- if let Some ( span) = question {
476+ /// Emits an error if any trait bound modifiers were present.
477+ fn error_lt_bound_with_modifiers ( & self , modifiers : BoundModifiers ) {
478+ if let Some ( span) = modifiers. maybe_const {
479+ self . struct_span_err (
480+ span,
481+ "`?const` may only modify trait bounds, not lifetime bounds" ,
482+ )
483+ . emit ( ) ;
484+ }
485+
486+ if let Some ( span) = modifiers. maybe {
457487 self . struct_span_err ( span, "`?` may only modify trait bounds, not lifetime bounds" )
458488 . emit ( ) ;
459489 }
@@ -479,25 +509,58 @@ impl<'a> Parser<'a> {
479509 Ok ( ( ) )
480510 }
481511
512+ /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
513+ ///
514+ /// If no modifiers are present, this does not consume any tokens.
515+ ///
516+ /// ```
517+ /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
518+ /// ```
519+ fn parse_ty_bound_modifiers ( & mut self ) -> BoundModifiers {
520+ if !self . eat ( & token:: Question ) {
521+ return BoundModifiers { maybe : None , maybe_const : None } ;
522+ }
523+
524+ // `? ...`
525+ let first_question = self . prev_span ;
526+ if !self . eat_keyword ( kw:: Const ) {
527+ return BoundModifiers { maybe : Some ( first_question) , maybe_const : None } ;
528+ }
529+
530+ // `?const ...`
531+ let maybe_const = first_question. to ( self . prev_span ) ;
532+ self . sess . gated_spans . gate ( sym:: const_trait_bound_opt_out, maybe_const) ;
533+ if !self . eat ( & token:: Question ) {
534+ return BoundModifiers { maybe : None , maybe_const : Some ( maybe_const) } ;
535+ }
536+
537+ // `?const ? ...`
538+ let second_question = self . prev_span ;
539+ BoundModifiers { maybe : Some ( second_question) , maybe_const : Some ( maybe_const) }
540+ }
541+
482542 /// Parses a type bound according to:
483543 /// ```
484544 /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
485- /// TY_BOUND_NOPAREN = [? ] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
545+ /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS ] [for<LT_PARAM_DEFS>] SIMPLE_PATH
486546 /// ```
547+ ///
548+ /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
487549 fn parse_generic_ty_bound (
488550 & mut self ,
489551 lo : Span ,
490552 has_parens : bool ,
491- question : Option < Span > ,
553+ modifiers : BoundModifiers ,
492554 ) -> PResult < ' a , GenericBound > {
493555 let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
494556 let path = self . parse_path ( PathStyle :: Type ) ?;
495557 if has_parens {
496558 self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?;
497559 }
498- let poly_trait = PolyTraitRef :: new ( lifetime_defs, path, lo. to ( self . prev_span ) ) ;
499- let modifier = question. map_or ( TraitBoundModifier :: None , |_| TraitBoundModifier :: Maybe ) ;
500- Ok ( GenericBound :: Trait ( poly_trait, modifier) )
560+
561+ let constness = modifiers. maybe_const . map ( |_| ast:: Constness :: NotConst ) ;
562+ let poly_trait = PolyTraitRef :: new ( lifetime_defs, path, constness, lo. to ( self . prev_span ) ) ;
563+ Ok ( GenericBound :: Trait ( poly_trait, modifiers. trait_bound_modifier ( ) ) )
501564 }
502565
503566 /// Optionally parses `for<$generic_params>`.
0 commit comments