about summary refs log tree commit diff
path: root/compiler/rustc_parse
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2023-12-18 17:55:55 +0100
committerLeón Orell Valerian Liehr <me@fmease.dev>2023-12-27 12:51:32 +0100
commit3eb48a35c8ae8335da66dc2bdb4f60e6ae22e1dd (patch)
treeeadb378f48629728c106252798e74f8faf1bf745 /compiler/rustc_parse
parent2fe50cd72c476ebacdedb14893e9632b4de961c2 (diff)
downloadrust-3eb48a35c8ae8335da66dc2bdb4f60e6ae22e1dd.tar.gz
rust-3eb48a35c8ae8335da66dc2bdb4f60e6ae22e1dd.zip
Introduce `const Trait` (always-const trait bounds)
Diffstat (limited to 'compiler/rustc_parse')
-rw-r--r--compiler/rustc_parse/messages.ftl9
-rw-r--r--compiler/rustc_parse/src/errors.rs18
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs35
3 files changed, 27 insertions, 35 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 363b8f4bfb9..c6bddbfacd6 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -95,9 +95,6 @@ parse_compound_assignment_expression_in_let = can't reassign to an uninitialized
     .suggestion = initialize the variable
     .help = if you meant to overwrite, remove the `let` binding
 
-parse_const_bounds_missing_tilde = const bounds must start with `~`
-    .suggestion = add `~`
-
 parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
     .suggestion = enclose the `const` expression in braces
 
@@ -555,8 +552,8 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl
     .suggestion_add_trait = add a trait here
     .suggestion_remove_for = for an inherent impl, drop this `for`
 
-parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
-    .suggestion = remove the `{$sigil}`
+parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds
+    .suggestion = remove the `{$modifier}`
 
 parse_more_than_one_char = character literal may only contain one codepoint
     .followed_by = this `{$chr}` is followed by the combining {$len ->
@@ -729,8 +726,6 @@ parse_switch_ref_box_order = switch the order of `ref` and `box`
 parse_ternary_operator = Rust has no ternary operator
     .help = use an `if-else` expression instead
 
-parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
-
 parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
     .suggestion = use `!` to perform bitwise not
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 53cce9e2883..e276b34ca37 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2556,19 +2556,12 @@ pub(crate) struct AssocLifetime {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_tilde_const_lifetime)]
-pub(crate) struct TildeConstLifetime {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_modifier_lifetime)]
 pub(crate) struct ModifierLifetime {
     #[primary_span]
     #[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
     pub span: Span,
-    pub sigil: &'static str,
+    pub modifier: &'static str,
 }
 
 #[derive(Diagnostic)]
@@ -2582,15 +2575,6 @@ pub(crate) struct ParenthesizedLifetime {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_const_bounds_missing_tilde)]
-pub(crate) struct ConstMissingTilde {
-    #[primary_span]
-    pub span: Span,
-    #[suggestion(code = "~", applicability = "machine-applicable")]
-    pub start: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_underscore_literal_suffix)]
 pub(crate) struct UnderscoreLiteralSuffix {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 42ab23d6292..4be2c662d03 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -86,6 +86,18 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
     t == &token::ModSep || t == &token::Lt || t == &token::BinOp(token::Shl)
 }
 
+fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
+    // `Not`, `Tilde` & `Const` are deliberately not part of this list to
+    // contain the number of potential regressions esp. in MBE code.
+    // `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`.
+    // `Not` would regress `dyn!(...)` macro calls in Rust 2015.
+    t.is_path_start()
+        || t.is_lifetime()
+        || t == &TokenKind::Question
+        || t.is_keyword(kw::For)
+        || t == &TokenKind::OpenDelim(Delimiter::Parenthesis)
+}
+
 impl<'a> Parser<'a> {
     /// Parses a type.
     pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
@@ -665,7 +677,8 @@ impl<'a> Parser<'a> {
         self.check_keyword(kw::Dyn)
             && (self.token.uninterpolated_span().at_least_rust_2018()
                 || self.look_ahead(1, |t| {
-                    (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star))
+                    (can_begin_dyn_bound_in_edition_2015(t)
+                        || t.kind == TokenKind::BinOp(token::Star))
                         && !can_continue_type_after_non_fn_ident(t)
                 }))
     }
@@ -758,12 +771,12 @@ impl<'a> Parser<'a> {
 
     /// Can the current token begin a bound?
     fn can_begin_bound(&mut self) -> bool {
-        // This needs to be synchronized with `TokenKind::can_begin_bound`.
         self.check_path()
             || self.check_lifetime()
             || self.check(&token::Not)
             || self.check(&token::Question)
             || self.check(&token::Tilde)
+            || self.check_keyword(kw::Const)
             || self.check_keyword(kw::For)
             || self.check(&token::OpenDelim(Delimiter::Parenthesis))
     }
@@ -812,8 +825,11 @@ impl<'a> Parser<'a> {
     fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) {
         match modifiers.constness {
             BoundConstness::Never => {}
-            BoundConstness::Maybe(span) => {
-                self.dcx().emit_err(errors::TildeConstLifetime { span });
+            BoundConstness::Always(span) | BoundConstness::Maybe(span) => {
+                self.dcx().emit_err(errors::ModifierLifetime {
+                    span,
+                    modifier: modifiers.constness.as_str(),
+                });
             }
         }
 
@@ -822,7 +838,7 @@ impl<'a> Parser<'a> {
             BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {
                 self.dcx().emit_err(errors::ModifierLifetime {
                     span,
-                    sigil: modifiers.polarity.as_str(),
+                    modifier: modifiers.polarity.as_str(),
                 });
             }
         }
@@ -848,7 +864,7 @@ impl<'a> Parser<'a> {
     /// If no modifiers are present, this does not consume any tokens.
     ///
     /// ```ebnf
-    /// TRAIT_BOUND_MODIFIERS = ["~const"] ["?" | "!"]
+    /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"]
     /// ```
     fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
         let constness = if self.eat(&token::Tilde) {
@@ -858,11 +874,8 @@ impl<'a> Parser<'a> {
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
             BoundConstness::Maybe(span)
         } else if self.eat_keyword(kw::Const) {
-            let span = self.prev_token.span;
-            self.sess.gated_spans.gate(sym::const_trait_impl, span);
-            self.dcx().emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() });
-
-            BoundConstness::Maybe(span)
+            self.sess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);
+            BoundConstness::Always(self.prev_token.span)
         } else {
             BoundConstness::Never
         };