@@ -6,7 +6,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
66use rustc_error_codes:: * ;
77use rustc_errors:: { pluralize, struct_span_err, 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} ;
@@ -17,6 +17,24 @@ use syntax::ast::{Mac, Mutability};
1717use syntax:: ptr:: P ;
1818use syntax:: token:: { self , Token } ;
1919
20+ /// Any `?` or `?const` modifiers that appear at the start of a bound.
21+ struct BoundModifiers {
22+ /// `?Trait`.
23+ maybe : Option < Span > ,
24+
25+ /// `?const Trait`.
26+ maybe_const : Option < Span > ,
27+ }
28+
29+ impl BoundModifiers {
30+ fn trait_bound_modifier ( & self ) -> TraitBoundModifier {
31+ match self . maybe {
32+ Some ( _) => TraitBoundModifier :: Maybe ,
33+ None => TraitBoundModifier :: None ,
34+ }
35+ }
36+ }
37+
2038/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
2139/// `IDENT<<u8 as Trait>::AssocTy>`.
2240///
@@ -195,7 +213,9 @@ impl<'a> Parser<'a> {
195213 lo : Span ,
196214 parse_plus : bool ,
197215 ) -> PResult < ' a , TyKind > {
198- let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, lo. to ( self . prev_span ) ) ;
216+ assert_ne ! ( self . token, token:: Question ) ;
217+
218+ let poly_trait_ref = PolyTraitRef :: new ( generic_params, path, None , lo. to ( self . prev_span ) ) ;
199219 let mut bounds = vec ! [ GenericBound :: Trait ( poly_trait_ref, TraitBoundModifier :: None ) ] ;
200220 if parse_plus {
201221 self . eat_plus ( ) ; // `+`, or `+=` gets split and `+` is discarded
@@ -421,12 +441,15 @@ impl<'a> Parser<'a> {
421441 let has_parens = self . eat ( & token:: OpenDelim ( token:: Paren ) ) ;
422442 let inner_lo = self . token . span ;
423443 let is_negative = self . eat ( & token:: Not ) ;
424- let question = self . eat ( & token:: Question ) . then_some ( self . prev_span ) ;
444+
445+ let modifiers = self . parse_ty_bound_modifiers ( ) ;
425446 let bound = if self . token . is_lifetime ( ) {
426- self . parse_generic_lt_bound ( lo, inner_lo, has_parens, question) ?
447+ self . error_lt_bound_with_modifiers ( modifiers) ;
448+ self . parse_generic_lt_bound ( lo, inner_lo, has_parens) ?
427449 } else {
428- self . parse_generic_ty_bound ( lo, has_parens, question ) ?
450+ self . parse_generic_ty_bound ( lo, has_parens, modifiers ) ?
429451 } ;
452+
430453 Ok ( if is_negative { Err ( anchor_lo. to ( self . prev_span ) ) } else { Ok ( bound) } )
431454 }
432455
@@ -439,9 +462,7 @@ impl<'a> Parser<'a> {
439462 lo : Span ,
440463 inner_lo : Span ,
441464 has_parens : bool ,
442- question : Option < Span > ,
443465 ) -> PResult < ' a , GenericBound > {
444- self . error_opt_out_lifetime ( question) ;
445466 let bound = GenericBound :: Outlives ( self . expect_lifetime ( ) ) ;
446467 if has_parens {
447468 // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
@@ -451,8 +472,17 @@ impl<'a> Parser<'a> {
451472 Ok ( bound)
452473 }
453474
454- fn error_opt_out_lifetime ( & self , question : Option < Span > ) {
455- if let Some ( span) = question {
475+ /// Emits an error if any trait bound modifiers were present.
476+ fn error_lt_bound_with_modifiers ( & self , modifiers : BoundModifiers ) {
477+ if let Some ( span) = modifiers. maybe_const {
478+ self . struct_span_err (
479+ span,
480+ "`?const` may only modify trait bounds, not lifetime bounds" ,
481+ )
482+ . emit ( ) ;
483+ }
484+
485+ if let Some ( span) = modifiers. maybe {
456486 self . struct_span_err ( span, "`?` may only modify trait bounds, not lifetime bounds" )
457487 . emit ( ) ;
458488 }
@@ -478,25 +508,58 @@ impl<'a> Parser<'a> {
478508 Ok ( ( ) )
479509 }
480510
511+ /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
512+ ///
513+ /// If no modifiers are present, this does not consume any tokens.
514+ ///
515+ /// ```
516+ /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
517+ /// ```
518+ fn parse_ty_bound_modifiers ( & mut self ) -> BoundModifiers {
519+ if !self . eat ( & token:: Question ) {
520+ return BoundModifiers { maybe : None , maybe_const : None } ;
521+ }
522+
523+ // `? ...`
524+ let first_question = self . prev_span ;
525+ if !self . eat_keyword ( kw:: Const ) {
526+ return BoundModifiers { maybe : Some ( first_question) , maybe_const : None } ;
527+ }
528+
529+ // `?const ...`
530+ let maybe_const = first_question. to ( self . prev_span ) ;
531+ self . sess . gated_spans . gate ( sym:: const_trait_bound_opt_out, maybe_const) ;
532+ if !self . eat ( & token:: Question ) {
533+ return BoundModifiers { maybe : None , maybe_const : Some ( maybe_const) } ;
534+ }
535+
536+ // `?const ? ...`
537+ let second_question = self . prev_span ;
538+ BoundModifiers { maybe : Some ( second_question) , maybe_const : Some ( maybe_const) }
539+ }
540+
481541 /// Parses a type bound according to:
482542 /// ```
483543 /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
484- /// TY_BOUND_NOPAREN = [? ] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
544+ /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS ] [for<LT_PARAM_DEFS>] SIMPLE_PATH
485545 /// ```
546+ ///
547+ /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
486548 fn parse_generic_ty_bound (
487549 & mut self ,
488550 lo : Span ,
489551 has_parens : bool ,
490- question : Option < Span > ,
552+ modifiers : BoundModifiers ,
491553 ) -> PResult < ' a , GenericBound > {
492554 let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
493555 let path = self . parse_path ( PathStyle :: Type ) ?;
494556 if has_parens {
495557 self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?;
496558 }
497- let poly_trait = PolyTraitRef :: new ( lifetime_defs, path, lo. to ( self . prev_span ) ) ;
498- let modifier = question. map_or ( TraitBoundModifier :: None , |_| TraitBoundModifier :: Maybe ) ;
499- Ok ( GenericBound :: Trait ( poly_trait, modifier) )
559+
560+ let constness = modifiers. maybe_const . map ( |_| ast:: Constness :: NotConst ) ;
561+ let poly_trait = PolyTraitRef :: new ( lifetime_defs, path, constness, lo. to ( self . prev_span ) ) ;
562+ Ok ( GenericBound :: Trait ( poly_trait, modifiers. trait_bound_modifier ( ) ) )
500563 }
501564
502565 /// Optionally parses `for<$generic_params>`.
0 commit comments