diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 5fb59eeb4f3..5b4a5f4dd38 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -53,6 +53,9 @@ parse_bare_cr = {$double_quotes -> parse_bare_cr_in_raw_string = bare CR not allowed in raw string +parse_binder_and_polarity = `for<...>` binder not allowed with `{$polarity}` trait polarity modifier + .label = there is not a well-defined meaning for a higher-ranked `{$polarity}` trait + parse_binder_before_modifiers = `for<...>` binder should be placed before trait bound modifiers .label = place the `for<...>` binder before any modifiers diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6738cc4a120..9b18a771fde 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3050,3 +3050,13 @@ pub struct BinderBeforeModifiers { #[label] pub modifiers_span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_binder_and_polarity)] +pub struct BinderAndPolarity { + #[primary_span] + pub polarity_span: Span, + #[label] + pub binder_span: Span, + pub polarity: &'static str, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 306029ca94c..6de778fa9f2 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -994,6 +994,19 @@ fn parse_generic_ty_bound( let modifiers = self.parse_trait_bound_modifiers()?; let modifiers_span = modifiers_lo.to(self.prev_token.span); + if let Some(binder_span) = binder_span { + match modifiers.polarity { + BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => { + self.dcx().emit_err(errors::BinderAndPolarity { + binder_span, + polarity_span, + polarity: modifiers.polarity.as_str(), + }); + } + BoundPolarity::Positive => {} + } + } + // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: ~const 'a`. if self.token.is_lifetime() { diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index 2b2a44b7062..47fec7b1e77 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -5,7 +5,7 @@ struct S< T: Tr + 'a, // OK T: 'a, // OK T:, // OK - T: for<'a> ?Trait, // OK + T: for<'a> ?Trait, //~ ERROR `for<...>` binder not allowed with `?` trait polarity modifier T: Tr +, // OK T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr index d1210e88d66..fa8ab6812b1 100644 --- a/tests/ui/parser/bounds-type.stderr +++ b/tests/ui/parser/bounds-type.stderr @@ -1,3 +1,11 @@ +error: `for<...>` binder not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:8:16 + | +LL | T: for<'a> ?Trait, + | ---- ^ + | | + | there is not a well-defined meaning for a higher-ranked `?` trait + error: `?` may only modify trait bounds, not lifetime bounds --> $DIR/bounds-type.rs:10:8 | @@ -16,5 +24,5 @@ error: `const` may only modify trait bounds, not lifetime bounds LL | T: const 'a, | ^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs index 4dd0e69598d..d65ecae3d06 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs @@ -4,6 +4,6 @@ #![feature(const_trait_impl)] struct S< - T: for<'a> ~const ?Tr<'a> + 'static + ~const std::ops::Add, - T: for<'a: 'b> ~const ?m::Trait<'a>, + T: for<'a> ~const Tr<'a> + 'static + ~const std::ops::Add, + T: for<'a: 'b> ~const m::Trait<'a>, >;