about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs9
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs8
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.rs2
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.stderr43
-rw-r--r--tests/ui/issues/issue-39089.rs2
-rw-r--r--tests/ui/issues/issue-39089.stderr8
8 files changed, 66 insertions, 11 deletions
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<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
+const fn with_positive<F: for<'a> ~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<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const fn with_positive<F: for<'a> ~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<F: for<'a> ~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<F: for<'a> ~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<F: for<'a> ~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<T: ?for<'a> 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<T: ?for<'a> Sized>() {}
-   |          ^^^^^^^^^^^^^
+   |         -   ^^^^
+   |         |
+   |         place the `for<...>` binder before any modifiers
 
 error: aborting due to 1 previous error