From e8445818d49fe968b35a130c66071c1b56498f93 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Jun 2024 12:58:35 -0400 Subject: Reorder modifiers and polarity to be *after* binder in trait bounds --- compiler/rustc_parse/src/parser/ty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1e5b227aaa9..24183ac1218 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -978,7 +978,7 @@ impl<'a> Parser<'a> { /// Parses a type bound according to: /// ```ebnf /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for] SIMPLE_PATH + /// TY_BOUND_NOPAREN = [for] [TRAIT_BOUND_MODIFIERS] SIMPLE_PATH /// ``` /// /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`. @@ -988,8 +988,8 @@ impl<'a> Parser<'a> { has_parens: bool, leading_token: &Token, ) -> PResult<'a, GenericBound> { - let modifiers = self.parse_trait_bound_modifiers()?; let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; + let modifiers = self.parse_trait_bound_modifiers()?; // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: ~const 'a`. -- cgit 1.4.1-3-g733a5 From 32c8bfdb11e519c6608ead730b6dfafc6cafb9c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Jun 2024 13:07:03 -0400 Subject: Improve error message --- compiler/rustc_parse/messages.ftl | 3 ++ compiler/rustc_parse/src/errors.rs | 9 +++++ compiler/rustc_parse/src/parser/ty.rs | 8 ++++ src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/impl-trait/normalize-tait-in-const.rs | 2 +- tests/ui/impl-trait/normalize-tait-in-const.stderr | 43 +++++++++++++++++++--- tests/ui/issues/issue-39089.rs | 2 +- tests/ui/issues/issue-39089.stderr | 8 ++-- 8 files changed, 66 insertions(+), 11 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 02c3c87313b..5fb59eeb4f3 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_before_modifiers = `for<...>` binder should be placed before trait bound modifiers + .label = place the `for<...>` binder before any modifiers + parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases parse_box_not_pat = expected pattern, found {$descr} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3ae9b6dad99..6738cc4a120 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3041,3 +3041,12 @@ pub struct UnsafeAttrOutsideUnsafeSuggestion { #[suggestion_part(code = ")")] pub right: Span, } + +#[derive(Diagnostic)] +#[diag(parse_binder_before_modifiers)] +pub struct BinderBeforeModifiers { + #[primary_span] + pub binder_span: Span, + #[label] + pub modifiers_span: Span, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 24183ac1218..306029ca94c 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -989,7 +989,10 @@ impl<'a> Parser<'a> { leading_token: &Token, ) -> PResult<'a, GenericBound> { let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; + + let modifiers_lo = self.token.span; let modifiers = self.parse_trait_bound_modifiers()?; + let modifiers_span = modifiers_lo.to(self.prev_token.span); // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: ~const 'a`. @@ -998,6 +1001,11 @@ impl<'a> Parser<'a> { return self.parse_generic_lt_bound(lo, has_parens); } + if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? { + lifetime_defs.extend(more_lifetime_defs); + self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span }); + } + let mut path = if self.token.is_keyword(kw::Fn) && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 5e6992038e3..0ae0356b2c4 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -16,7 +16,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1672; +const ISSUES_ENTRY_LIMIT: u32 = 1673; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs index fc90139d640..e3f53e5f8a8 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.rs +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -24,7 +24,7 @@ mod foo { } use foo::*; -const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { +const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { fun(filter_positive()); } diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 77de689fb97..b20dabe7b25 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,8 +1,41 @@ -error: expected a trait, found type - --> $DIR/normalize-tait-in-const.rs:27:34 +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:27:42 | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/normalize-tait-in-const.rs:27:69 + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^^^^^^ + +error[E0015]: cannot call non-const closure in constant functions + --> $DIR/normalize-tait-in-const.rs:28:5 + | +LL | fun(filter_positive()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: consider further restricting this bound + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) { + | ++++++++++++++++++++++++++++ +help: add `#![feature(effects)]` to the crate attributes to enable + | +LL + #![feature(effects)] + | + +error[E0493]: destructor of `F` cannot be evaluated at compile-time + --> $DIR/normalize-tait-in-const.rs:27:79 + | +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { + | ^^^ the destructor for this type cannot be evaluated in constant functions +LL | fun(filter_positive()); +LL | } + | - value is dropped here + +error: aborting due to 4 previous errors +Some errors have detailed explanations: E0015, E0493. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/issues/issue-39089.rs b/tests/ui/issues/issue-39089.rs index e6bec337354..822c47503af 100644 --- a/tests/ui/issues/issue-39089.rs +++ b/tests/ui/issues/issue-39089.rs @@ -1,4 +1,4 @@ fn f Sized>() {} -//~^ ERROR expected a trait, found type +//~^ ERROR `for<...>` binder should be placed before trait bound modifiers fn main() {} diff --git a/tests/ui/issues/issue-39089.stderr b/tests/ui/issues/issue-39089.stderr index 3e57a6fcbcb..a81010aedff 100644 --- a/tests/ui/issues/issue-39089.stderr +++ b/tests/ui/issues/issue-39089.stderr @@ -1,8 +1,10 @@ -error: expected a trait, found type - --> $DIR/issue-39089.rs:1:10 +error: `for<...>` binder should be placed before trait bound modifiers + --> $DIR/issue-39089.rs:1:13 | LL | fn f Sized>() {} - | ^^^^^^^^^^^^^ + | - ^^^^ + | | + | place the `for<...>` binder before any modifiers error: aborting due to 1 previous error -- cgit 1.4.1-3-g733a5 From 898ed2ffa6c485530af1fbe6117c0deb4290715f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 17:49:50 -0400 Subject: Enforce that ? and for<...> are not combined --- compiler/rustc_parse/messages.ftl | 3 +++ compiler/rustc_parse/src/errors.rs | 10 ++++++++++ compiler/rustc_parse/src/parser/ty.rs | 13 +++++++++++++ tests/ui/parser/bounds-type.rs | 2 +- tests/ui/parser/bounds-type.stderr | 10 +++++++++- .../ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs | 4 ++-- 6 files changed, 38 insertions(+), 4 deletions(-) (limited to 'compiler/rustc_parse/src/parser') 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 @@ impl<'a> Parser<'a> { 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>, >; -- cgit 1.4.1-3-g733a5 From de88bc5c8921774681ecac0a5249b370a9768a6c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jul 2024 18:06:44 -0400 Subject: And additionally enforce ? and async/const aren't mixed --- compiler/rustc_ast_passes/messages.ftl | 2 - compiler/rustc_ast_passes/src/ast_validation.rs | 11 ------ compiler/rustc_ast_passes/src/errors.rs | 9 ----- compiler/rustc_parse/messages.ftl | 3 ++ compiler/rustc_parse/src/errors.rs | 11 ++++++ compiler/rustc_parse/src/parser/ty.rs | 29 ++++++++++++++ tests/ui/parser/bounds-type.rs | 13 +++++- tests/ui/parser/bounds-type.stderr | 46 +++++++++++++++++++--- .../mutually-exclusive-trait-bound-modifiers.rs | 8 ++-- ...mutually-exclusive-trait-bound-modifiers.stderr | 32 +++++++++------ 10 files changed, 120 insertions(+), 44 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 7da726ef408..0408f6ad543 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -152,8 +152,6 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features -ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive - ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .because = {$annotation} because of this .type = inherent impl for this type diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52c..8041b89abe2 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1435,17 +1435,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); } - ( - _, - BoundConstness::Always(_) | BoundConstness::Maybe(_), - BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), - ) => { - self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { - span: bound.span(), - left: modifiers.constness.as_str(), - right: modifiers.polarity.as_str(), - }); - } _ => {} } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb90476450..51f80b9ad4a 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -657,15 +657,6 @@ pub enum TildeConstReason { Item, } -#[derive(Diagnostic)] -#[diag(ast_passes_incompatible_trait_bound_modifiers)] -pub struct IncompatibleTraitBoundModifiers { - #[primary_span] - pub span: Span, - pub left: &'static str, - pub right: &'static str, -} - #[derive(Diagnostic)] #[diag(ast_passes_const_and_async)] pub struct ConstAndAsync { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 5b4a5f4dd38..f0cdb6c63a4 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -575,6 +575,9 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds .suggestion = remove the `{$modifier}` +parse_modifiers_and_polarity = `{$modifiers_concatenated}` trait not allowed with `{$polarity}` trait polarity modifier + .label = there is not a well-defined meaning for a `{$modifiers_concatenated} {$polarity}` trait + parse_more_than_one_char = character literal may only contain one codepoint .followed_by = this `{$chr}` is followed by the combining {$len -> [one] mark diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 9b18a771fde..75417885d2a 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3060,3 +3060,14 @@ pub struct BinderAndPolarity { pub binder_span: Span, pub polarity: &'static str, } + +#[derive(Diagnostic)] +#[diag(parse_modifiers_and_polarity)] +pub struct PolarityAndModifiers { + #[primary_span] + pub polarity_span: Span, + #[label] + pub modifiers_span: Span, + pub polarity: &'static str, + pub modifiers_concatenated: String, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6de778fa9f2..a2db4b6feef 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -930,6 +930,7 @@ impl<'a> Parser<'a> { /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"] /// ``` fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { + let modifier_lo = self.token.span; let constness = if self.eat(&token::Tilde) { let tilde = self.prev_token.span; self.expect_keyword(kw::Const)?; @@ -962,6 +963,7 @@ impl<'a> Parser<'a> { } else { BoundAsyncness::Normal }; + let modifier_hi = self.prev_token.span; let polarity = if self.eat(&token::Question) { BoundPolarity::Maybe(self.prev_token.span) @@ -972,6 +974,33 @@ impl<'a> Parser<'a> { BoundPolarity::Positive }; + // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`. + match polarity { + BoundPolarity::Positive => { + // All trait bound modifiers allowed to combine with positive polarity + } + BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => { + match (asyncness, constness) { + (BoundAsyncness::Normal, BoundConstness::Never) => { + // Ok, no modifiers. + } + (_, _) => { + let constness = constness.as_str(); + let asyncness = asyncness.as_str(); + let glue = + if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" }; + let modifiers_concatenated = format!("{constness}{glue}{asyncness}"); + self.dcx().emit_err(errors::PolarityAndModifiers { + polarity_span, + polarity: polarity.as_str(), + modifiers_span: modifier_lo.to(modifier_hi), + modifiers_concatenated, + }); + } + } + } + } + Ok(TraitBoundModifiers { constness, asyncness, polarity }) } diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index 47fec7b1e77..7cee6def32f 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Z parse-only +//@ edition: 2021 struct S< T: 'a + Tr, // OK @@ -10,10 +11,20 @@ struct S< T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds T: ~const Tr, // OK - T: ~const ?Tr, // OK + T: ~const ?Tr, //~ ERROR `~const` trait not allowed with `?` trait polarity modifier T: ~const Tr + 'a, // OK T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds + + T: async Tr, // OK + T: async ?Tr, //~ ERROR `async` trait not allowed with `?` trait polarity modifier + T: async Tr + 'a, // OK + T: async 'a, //~ ERROR `async` may only modify trait bounds, not lifetime bounds + + T: const async Tr, // OK + T: const async ?Tr, //~ ERROR `const async` trait not allowed with `?` trait polarity modifier + T: const async Tr + 'a, // OK + T: const async 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds >; fn main() {} diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr index fa8ab6812b1..09c35c12b00 100644 --- a/tests/ui/parser/bounds-type.stderr +++ b/tests/ui/parser/bounds-type.stderr @@ -1,5 +1,5 @@ error: `for<...>` binder not allowed with `?` trait polarity modifier - --> $DIR/bounds-type.rs:8:16 + --> $DIR/bounds-type.rs:9:16 | LL | T: for<'a> ?Trait, | ---- ^ @@ -7,22 +7,58 @@ 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 + --> $DIR/bounds-type.rs:11:8 | LL | T: ?'a, | ^ +error: `~const` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:14:15 + | +LL | T: ~const ?Tr, + | ------ ^ + | | + | there is not a well-defined meaning for a `~const ?` trait + error: `~const` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:15:8 + --> $DIR/bounds-type.rs:16:8 | LL | T: ~const 'a, | ^^^^^^ error: `const` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:16:8 + --> $DIR/bounds-type.rs:17:8 | LL | T: const 'a, | ^^^^^ -error: aborting due to 4 previous errors +error: `async` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:20:14 + | +LL | T: async ?Tr, + | ----- ^ + | | + | there is not a well-defined meaning for a `async ?` trait + +error: `async` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:22:8 + | +LL | T: async 'a, + | ^^^^^ + +error: `const async` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:25:20 + | +LL | T: const async ?Tr, + | ----------- ^ + | | + | there is not a well-defined meaning for a `const async ?` trait + +error: `const` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:27:8 + | +LL | T: const async 'a, + | ^^^^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs index 37e285f2c65..aaab8e819a3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs @@ -1,17 +1,17 @@ #![feature(const_trait_impl)] const fn maybe_const_maybe() {} -//~^ ERROR `~const` and `?` are mutually exclusive +//~^ ERROR `~const` trait not allowed with `?` trait polarity modifier fn const_maybe() {} -//~^ ERROR `const` and `?` are mutually exclusive +//~^ ERROR `const` trait not allowed with `?` trait polarity modifier const fn maybe_const_negative() {} -//~^ ERROR `~const` and `!` are mutually exclusive +//~^ ERROR `~const` trait not allowed with `!` trait polarity modifier //~| ERROR negative bounds are not supported fn const_negative() {} -//~^ ERROR `const` and `!` are mutually exclusive +//~^ ERROR `const` trait not allowed with `!` trait polarity modifier //~| ERROR negative bounds are not supported #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr index 1938f740170..18e4d160f5f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr @@ -1,26 +1,34 @@ -error: `~const` and `?` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31 +error: `~const` trait not allowed with `?` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:38 | LL | const fn maybe_const_maybe() {} - | ^^^^^^^^^^^^^ + | ------ ^ + | | + | there is not a well-defined meaning for a `~const ?` trait -error: `const` and `?` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:19 +error: `const` trait not allowed with `?` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25 | LL | fn const_maybe() {} - | ^^^^^^^^^^^^ + | ----- ^ + | | + | there is not a well-defined meaning for a `const ?` trait -error: `~const` and `!` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:34 +error: `~const` trait not allowed with `!` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 | LL | const fn maybe_const_negative() {} - | ^^^^^^^^^^^^^ + | ------ ^ + | | + | there is not a well-defined meaning for a `~const !` trait -error: `const` and `!` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:22 +error: `const` trait not allowed with `!` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28 | LL | fn const_negative() {} - | ^^^^^^^^^^^^ + | ----- ^ + | | + | there is not a well-defined meaning for a `const !` trait error: negative bounds are not supported --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 -- cgit 1.4.1-3-g733a5 From 2f305ff460862e18b67db2faa11b85ab223d4e60 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 15:02:19 +1000 Subject: Remove an unnecessary `?`. --- compiler/rustc_parse/src/parser/item.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d2fea5583b8..994e7c5d2db 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -128,14 +128,10 @@ impl<'a> Parser<'a> { Some(item.into_inner()) }); - let item = - self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| { - let item = - this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode); - Ok((item?, TrailingToken::None)) - })?; - - Ok(item) + self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { + let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode)?; + Ok((item, TrailingToken::None)) + }) } fn parse_item_common_( -- cgit 1.4.1-3-g733a5 From 48cdfc388d67a6bde420d8d44eddf8ef1e5b7eb2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 15:07:42 +1000 Subject: Inline `Parser::parse_item_common_`. It has a single call site, it isn't that big, and its name is confusingly similar to `Parser::parse_item_common`. --- compiler/rustc_parse/src/parser/item.rs | 75 ++++++++++++++------------------- 1 file changed, 32 insertions(+), 43 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 994e7c5d2db..2d5781c3bbf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -128,52 +128,41 @@ impl<'a> Parser<'a> { Some(item.into_inner()) }); - self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { - let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode)?; - Ok((item, TrailingToken::None)) - }) - } - - fn parse_item_common_( - &mut self, - mut attrs: AttrVec, - mac_allowed: bool, - attrs_allowed: bool, - fn_parse_mode: FnParseMode, - ) -> PResult<'a, Option> { - let lo = self.token.span; - let vis = self.parse_visibility(FollowedByType::No)?; - let mut def = self.parse_defaultness(); - let kind = self.parse_item_kind( - &mut attrs, - mac_allowed, - lo, - &vis, - &mut def, - fn_parse_mode, - Case::Sensitive, - )?; - if let Some((ident, kind)) = kind { - self.error_on_unconsumed_default(def, &kind); - let span = lo.to(self.prev_token.span); - let id = DUMMY_NODE_ID; - let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; - return Ok(Some(item)); - } + self.collect_tokens_trailing_token(attrs, force_collect, |this, mut attrs| { + let lo = this.token.span; + let vis = this.parse_visibility(FollowedByType::No)?; + let mut def = this.parse_defaultness(); + let kind = this.parse_item_kind( + &mut attrs, + mac_allowed, + lo, + &vis, + &mut def, + fn_parse_mode, + Case::Sensitive, + )?; + if let Some((ident, kind)) = kind { + this.error_on_unconsumed_default(def, &kind); + let span = lo.to(this.prev_token.span); + let id = DUMMY_NODE_ID; + let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; + return Ok((Some(item), TrailingToken::None)); + } - // At this point, we have failed to parse an item. - if !matches!(vis.kind, VisibilityKind::Inherited) { - self.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); - } + // At this point, we have failed to parse an item. + if !matches!(vis.kind, VisibilityKind::Inherited) { + this.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); + } - if let Defaultness::Default(span) = def { - self.dcx().emit_err(errors::DefaultNotFollowedByItem { span }); - } + if let Defaultness::Default(span) = def { + this.dcx().emit_err(errors::DefaultNotFollowedByItem { span }); + } - if !attrs_allowed { - self.recover_attrs_no_item(&attrs)?; - } - Ok(None) + if !attrs_allowed { + this.recover_attrs_no_item(&attrs)?; + } + Ok((None, TrailingToken::None)) + }) } /// Error in-case `default` was parsed in an in-appropriate context. -- cgit 1.4.1-3-g733a5 From d247489ac280147b48c72ed739ea9056e0ca6ff2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 15:54:34 +1000 Subject: Reorder `Parser::parse_expr_dot_or_call_with` arguments. Put `attrs` before `e0` because that matches the order in the source code, where outer attributes appear before expressions. --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_parse/src/parser/stmt.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b2df9a14eb0..a1bb047e464 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -885,15 +885,15 @@ impl<'a> Parser<'a> { self.collect_tokens_for_expr(attrs, |this, attrs| { let base = this.parse_expr_bottom()?; let span = this.interpolated_or_expr_span(&base); - this.parse_expr_dot_or_call_with(base, span, attrs) + this.parse_expr_dot_or_call_with(attrs, base, span) }) } pub(super) fn parse_expr_dot_or_call_with( &mut self, + mut attrs: ast::AttrVec, e0: P, lo: Span, - mut attrs: ast::AttrVec, ) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 6f2b7177159..7ef6474c29e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -388,9 +388,9 @@ impl<'a> Parser<'a> { // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. if let Ok(expr) = snapshot .parse_expr_dot_or_call_with( + AttrVec::new(), self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr` pat_span, - AttrVec::new(), ) .map_err(|err| err.cancel()) { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index d65f6ff68ee..1259d223af6 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -164,7 +164,7 @@ impl<'a> Parser<'a> { }; let expr = this.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_expr_dot_or_call_with(expr, lo, attrs) + this.parse_expr_dot_or_call_with(attrs, expr, lo) })?; // `DUMMY_SP` will get overwritten later in this function Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None)) @@ -206,7 +206,7 @@ impl<'a> Parser<'a> { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; - let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?; + let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?; let e = self .parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?; StmtKind::Expr(e) -- cgit 1.4.1-3-g733a5 From 96cc9c99b29c373db41093dee3170f36dc15543b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:02:45 +1000 Subject: Inline and remove `Parser::parse_and_disallow_postfix_after_cast`. It has a single call site. Removing it removes the need for an `ExprKind` check. The commit also clarifies the relevant comment. --- compiler/rustc_parse/src/parser/expr.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a1bb047e464..49a71b97be2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -785,19 +785,10 @@ impl<'a> Parser<'a> { } }; - self.parse_and_disallow_postfix_after_cast(cast_expr) - } - - /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast, - /// then emits an error and returns the newly parsed tree. - /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`. - fn parse_and_disallow_postfix_after_cast( - &mut self, - cast_expr: P, - ) -> PResult<'a, P> { - if let ExprKind::Type(_, _) = cast_expr.kind { - panic!("ExprKind::Type must not be parsed"); - } + // Try to parse a postfix operator such as `.`, `?`, or index (`[]`) + // after a cast. If one is present, emit an error then return a valid + // parse tree; For something like `&x as T[0]` will be as if it was + // written `((&x) as T)[0]`. let span = cast_expr.span; -- cgit 1.4.1-3-g733a5 From 96b39f1204992368f059b44b56362a91e1e27ef9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:12:58 +1000 Subject: Inline and remove `Parser::parse_expr_dot_or_call_with_`. It only has two call sites, and it extremely similar to `Parser::parse_expr_dot_or_call_with`, in both name and behaviour. The only difference is the latter has an `attrs` argument and an `ensure_sufficient_stack` call. We can pass in an empty `attrs` as necessary, as is already done at some `parse_expr_dot_or_call_with` call sites. --- compiler/rustc_parse/src/parser/expr.rs | 102 +++++++++++++++----------------- 1 file changed, 49 insertions(+), 53 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 49a71b97be2..896f84d3a36 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -792,7 +792,7 @@ impl<'a> Parser<'a> { let span = cast_expr.span; - let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?; + let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, it is an illegal postfix operator. @@ -883,16 +883,56 @@ impl<'a> Parser<'a> { pub(super) fn parse_expr_dot_or_call_with( &mut self, mut attrs: ast::AttrVec, - e0: P, + mut e: P, lo: Span, ) -> PResult<'a, P> { - // Stitch the list of outer attributes onto the return value. - // A little bit ugly, but the best way given the current code - // structure - let res = ensure_sufficient_stack( - // this expr demonstrates the recursion it guards against - || self.parse_expr_dot_or_call_with_(e0, lo), - ); + let res = ensure_sufficient_stack(|| { + loop { + let has_question = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `?` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Question) + } else { + self.eat(&token::Question) + }; + if has_question { + // `expr?` + e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); + continue; + } + let has_dot = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `.` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true + } else { + self.eat(&token::Dot) + }; + if has_dot { + // expr.f + e = self.parse_dot_suffix_expr(lo, e)?; + continue; + } + if self.expr_is_complete(&e) { + return Ok(e); + } + e = match self.token.kind { + token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), + token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, + _ => return Ok(e), + } + } + }); + + // Stitch the list of outer attributes onto the return value. A little + // bit ugly, but the best way given the current code structure. if attrs.is_empty() { res } else { @@ -906,50 +946,6 @@ impl<'a> Parser<'a> { } } - fn parse_expr_dot_or_call_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { - loop { - let has_question = - if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // we are using noexpect here because we don't expect a `?` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Question) - } else { - self.eat(&token::Question) - }; - if has_question { - // `expr?` - e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); - continue; - } - let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // we are using noexpect here because we don't expect a `.` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Dot) - } else if self.token.kind == TokenKind::RArrow && self.may_recover() { - // Recovery for `expr->suffix`. - self.bump(); - let span = self.prev_token.span; - self.dcx().emit_err(errors::ExprRArrowCall { span }); - true - } else { - self.eat(&token::Dot) - }; - if has_dot { - // expr.f - e = self.parse_dot_suffix_expr(lo, e)?; - continue; - } - if self.expr_is_complete(&e) { - return Ok(e); - } - e = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), - token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, - _ => return Ok(e), - } - } - } - pub(super) fn parse_dot_suffix_expr( &mut self, lo: Span, -- cgit 1.4.1-3-g733a5 From 8cb6bc3b5a33cbd7d9b131fad2f63cc243b26ea0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:39:04 +1000 Subject: Fix a comment. --- compiler/rustc_parse/src/parser/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 896f84d3a36..796a279188d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1375,7 +1375,7 @@ impl<'a> Parser<'a> { /// Parses things like parenthesized exprs, macros, `return`, etc. /// /// N.B., this does not parse outer attributes, and is private because it only works - /// correctly if called from `parse_dot_or_call_expr()`. + /// correctly if called from `parse_expr_dot_or_call`. fn parse_expr_bottom(&mut self) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); -- cgit 1.4.1-3-g733a5 From 9c4f3dbd066fd8e35f188388f66493522f7d4476 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jul 2024 16:40:35 +1000 Subject: Remove references to `maybe_whole_expr`. It was removed in #126571. --- compiler/rustc_ast/src/token.rs | 3 +-- compiler/rustc_parse/src/parser/mod.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index efe19566152..9478da236c3 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -699,8 +699,7 @@ impl Token { false } - /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? - /// That is, is this a pre-parsed expression dropped into the token stream + /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { if let Interpolated(nt) = &self.kind diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 958458eda9a..0117f993bcb 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -101,7 +101,6 @@ pub enum TrailingToken { MaybeComma, } -/// Like `maybe_whole_expr`, but for things other than expressions. #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { -- cgit 1.4.1-3-g733a5 From d0a1851ec2cf84bdb41bc4d788b3995a8463c543 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Jun 2024 16:36:35 -0400 Subject: Deny keyword lifetimes pre-expansion --- compiler/rustc_ast_passes/messages.ftl | 6 ----- compiler/rustc_ast_passes/src/ast_validation.rs | 30 ---------------------- compiler/rustc_ast_passes/src/errors.rs | 15 ----------- compiler/rustc_parse/messages.ftl | 6 +++++ compiler/rustc_parse/src/errors.rs | 15 +++++++++++ compiler/rustc_parse/src/parser/expr.rs | 13 +++++++--- compiler/rustc_parse/src/parser/nonterminal.rs | 7 +++-- compiler/rustc_parse/src/parser/pat.rs | 8 +++--- compiler/rustc_parse/src/parser/ty.rs | 6 +++++ tests/ui/parser/cfg-keyword-lifetime.rs | 15 +++++++++++ tests/ui/parser/cfg-keyword-lifetime.stderr | 14 ++++++++++ .../require-parens-for-chained-comparison.rs | 2 ++ .../require-parens-for-chained-comparison.stderr | 20 ++++++++++++--- tests/ui/self/self_type_keyword.stderr | 12 ++++----- 14 files changed, 99 insertions(+), 70 deletions(-) create mode 100644 tests/ui/parser/cfg-keyword-lifetime.rs create mode 100644 tests/ui/parser/cfg-keyword-lifetime.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 7da726ef408..02bdff96aa6 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -159,9 +159,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .type = inherent impl for this type .only_trait = only trait implementations may be annotated with {$annotation} -ast_passes_invalid_label = - invalid label name `{$name}` - ast_passes_invalid_unnamed_field = unnamed fields are not allowed outside of structs or unions .label = unnamed field declared here @@ -176,9 +173,6 @@ ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot ast_passes_item_underscore = `{$kind}` items in this context need a name .label = `_` is not a valid name for this `{$kind}` item -ast_passes_keyword_lifetime = - lifetimes cannot use keyword names - ast_passes_match_arm_with_no_body = `match` arm with no body .suggestion = add a body after the pattern diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52c..f33176c0b32 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -284,19 +284,6 @@ impl<'a> AstValidator<'a> { self.session.dcx() } - fn check_lifetime(&self, ident: Ident) { - let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; - if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); - } - } - - fn check_label(&self, ident: Ident) { - if ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); - } - } - fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { if let VisibilityKind::Inherited = vis.kind { return; @@ -923,16 +910,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.walk_ty(ty) } - fn visit_label(&mut self, label: &'a Label) { - self.check_label(label.ident); - visit::walk_label(self, label); - } - - fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) { - self.check_lifetime(lifetime.ident); - visit::walk_lifetime(self, lifetime); - } - fn visit_field_def(&mut self, field: &'a FieldDef) { self.deny_unnamed_field(field); visit::walk_field_def(self, field) @@ -1371,13 +1348,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - fn visit_generic_param(&mut self, param: &'a GenericParam) { - if let GenericParamKind::Lifetime { .. } = param.kind { - self.check_lifetime(param.ident); - } - visit::walk_generic_param(self, param); - } - fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { match bound { GenericBound::Trait(trait_ref, modifiers) => { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb90476450..4dff4ecfae0 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -9,21 +9,6 @@ use rustc_span::{symbol::Ident, Span, Symbol}; use crate::fluent_generated as fluent; -#[derive(Diagnostic)] -#[diag(ast_passes_keyword_lifetime)] -pub struct KeywordLifetime { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_label)] -pub struct InvalidLabel { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - #[derive(Diagnostic)] #[diag(ast_passes_visibility_not_permitted, code = E0449)] pub struct VisibilityNotPermitted { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c2201b1c41e..4ce9e0f025c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -388,6 +388,9 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` parse_invalid_identifier_with_leading_number = identifiers cannot start with a number +parse_invalid_label = + invalid label name `{$name}` + parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases @@ -414,6 +417,9 @@ parse_invalid_unicode_escape = invalid unicode character escape parse_invalid_variable_declaration = invalid variable declaration +parse_keyword_lifetime = + lifetimes cannot use keyword names + parse_kw_bad_case = keyword `{$kw}` is written in the wrong case .suggestion = write it in the correct case diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 092a2a10ab7..4222486034b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2009,6 +2009,21 @@ pub struct CannotBeRawIdent { pub ident: Symbol, } +#[derive(Diagnostic)] +#[diag(parse_keyword_lifetime)] +pub struct KeywordLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_invalid_label)] +pub struct InvalidLabel { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + #[derive(Diagnostic)] #[diag(parse_cr_doc_comment)] pub struct CrDocComment { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4bd20be4171..0ba8c66f48f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2932,10 +2932,17 @@ impl<'a> Parser<'a> { } pub(crate) fn eat_label(&mut self) -> Option