@@ -935,9 +935,14 @@ impl<'a> Parser<'a> {
935935 /// If no modifiers are present, this does not consume any tokens.
936936 ///
937937 /// ```ebnf
938- /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"]
938+ /// CONSTNESS = [["~"] "const"]
939+ /// ASYNCNESS = ["async"]
940+ /// POLARITY = ["?" | "!"]
939941 /// ```
942+ ///
943+ /// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
940944 fn parse_trait_bound_modifiers ( & mut self ) -> PResult < ' a , TraitBoundModifiers > {
945+ let modifier_lo = self . token . span ;
941946 let constness = if self . eat ( & token:: Tilde ) {
942947 let tilde = self . prev_token . span ;
943948 self . expect_keyword ( kw:: Const ) ?;
@@ -970,6 +975,7 @@ impl<'a> Parser<'a> {
970975 } else {
971976 BoundAsyncness :: Normal
972977 } ;
978+ let modifier_hi = self . prev_token . span ;
973979
974980 let polarity = if self . eat ( & token:: Question ) {
975981 BoundPolarity :: Maybe ( self . prev_token . span )
@@ -980,13 +986,40 @@ impl<'a> Parser<'a> {
980986 BoundPolarity :: Positive
981987 } ;
982988
989+ // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`.
990+ match polarity {
991+ BoundPolarity :: Positive => {
992+ // All trait bound modifiers allowed to combine with positive polarity
993+ }
994+ BoundPolarity :: Maybe ( polarity_span) | BoundPolarity :: Negative ( polarity_span) => {
995+ match ( asyncness, constness) {
996+ ( BoundAsyncness :: Normal , BoundConstness :: Never ) => {
997+ // Ok, no modifiers.
998+ }
999+ ( _, _) => {
1000+ let constness = constness. as_str ( ) ;
1001+ let asyncness = asyncness. as_str ( ) ;
1002+ let glue =
1003+ if !constness. is_empty ( ) && !asyncness. is_empty ( ) { " " } else { "" } ;
1004+ let modifiers_concatenated = format ! ( "{constness}{glue}{asyncness}" ) ;
1005+ self . dcx ( ) . emit_err ( errors:: PolarityAndModifiers {
1006+ polarity_span,
1007+ polarity : polarity. as_str ( ) ,
1008+ modifiers_span : modifier_lo. to ( modifier_hi) ,
1009+ modifiers_concatenated,
1010+ } ) ;
1011+ }
1012+ }
1013+ }
1014+ }
1015+
9831016 Ok ( TraitBoundModifiers { constness, asyncness, polarity } )
9841017 }
9851018
9861019 /// Parses a type bound according to:
9871020 /// ```ebnf
9881021 /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
989- /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [ for<LT_PARAM_DEFS> ] SIMPLE_PATH
1022+ /// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY ] SIMPLE_PATH
9901023 /// ```
9911024 ///
9921025 /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`.
@@ -996,16 +1029,37 @@ impl<'a> Parser<'a> {
9961029 has_parens : bool ,
9971030 leading_token : & Token ,
9981031 ) -> PResult < ' a , GenericBound > {
999- let modifiers = self . parse_trait_bound_modifiers ( ) ?;
10001032 let ( mut lifetime_defs, binder_span) = self . parse_late_bound_lifetime_defs ( ) ?;
10011033
1034+ let modifiers_lo = self . token . span ;
1035+ let modifiers = self . parse_trait_bound_modifiers ( ) ?;
1036+ let modifiers_span = modifiers_lo. to ( self . prev_token . span ) ;
1037+
1038+ if let Some ( binder_span) = binder_span {
1039+ match modifiers. polarity {
1040+ BoundPolarity :: Negative ( polarity_span) | BoundPolarity :: Maybe ( polarity_span) => {
1041+ self . dcx ( ) . emit_err ( errors:: BinderAndPolarity {
1042+ binder_span,
1043+ polarity_span,
1044+ polarity : modifiers. polarity . as_str ( ) ,
1045+ } ) ;
1046+ }
1047+ BoundPolarity :: Positive => { }
1048+ }
1049+ }
1050+
10021051 // Recover erroneous lifetime bound with modifiers or binder.
10031052 // e.g. `T: for<'a> 'a` or `T: ~const 'a`.
10041053 if self . token . is_lifetime ( ) {
10051054 let _: ErrorGuaranteed = self . error_lt_bound_with_modifiers ( modifiers, binder_span) ;
10061055 return self . parse_generic_lt_bound ( lo, has_parens) ;
10071056 }
10081057
1058+ if let ( more_lifetime_defs, Some ( binder_span) ) = self . parse_late_bound_lifetime_defs ( ) ? {
1059+ lifetime_defs. extend ( more_lifetime_defs) ;
1060+ self . dcx ( ) . emit_err ( errors:: BinderBeforeModifiers { binder_span, modifiers_span } ) ;
1061+ }
1062+
10091063 let mut path = if self . token . is_keyword ( kw:: Fn )
10101064 && self . look_ahead ( 1 , |tok| tok. kind == TokenKind :: OpenDelim ( Delimiter :: Parenthesis ) )
10111065 && let Some ( path) = self . recover_path_from_fn ( )
0 commit comments