Repository: rust-lang/rust
Pull request: Emit ForbiddenBound fatally if meeting complex bound

<!-- homu-ignore:start -->
*[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/149728)*
<!-- homu-ignore:end -->

Fixes https://github.com/rust-lang/rust/issues/149695

---

Bounds in binders are denied, hir items won't contain and index them. But nested items in the bounds will still be lowered to hir. And their parents, i.e., the block in bounds is not in hir. So that ICE happens when error handling requires visiting hir parents.

~~This PR collects hirless def ids and skips them when iterating parents.~~

~~This PR checks such bounds used in higher ranked binders and emit error `ForbiddenBound` when parsing. And make sure no such bounds appear in hir.~~

This PR emits this error fatally if meeting complex bound.


Changed files:
filename: compiler/rustc_ast_passes/src/feature_gate.rs
patch: @@ -1,5 +1,5 @@
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
+use rustc_ast::{self as ast, AttrVec, GenericBound, NodeId, PatKind, attr, token};
 use rustc_attr_parsing::AttributeParser;
 use rustc_errors::msg;
 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
@@ -149,7 +149,14 @@ impl<'a> PostExpansionVisitor<'a> {
         for param in params {
             if !param.bounds.is_empty() {
                 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-                self.sess.dcx().emit_err(errors::ForbiddenBound { spans });
+                if param.bounds.iter().any(|bound| matches!(bound, GenericBound::Trait(_))) {
+                    // Issue #149695
+                    // Abort immediately otherwise items defined in complex bounds will be lowered into HIR,
+                    // which will cause ICEs when errors of the items visit unlowered parents.
+                    self.sess.dcx().emit_fatal(errors::ForbiddenBound { spans });
+                } else {
+                    self.sess.dcx().emit_err(errors::ForbiddenBound { spans });
+                }
             }
         }
     }

filename: tests/ui/closures/binder/bounds-on-closure-type-binders.rs
patch: @@ -10,5 +10,4 @@ fn main() {
     // Regression test for issue #119067
     let _ = for<T: Trait> || -> () {};
     //~^ ERROR bounds cannot be used in this context
-    //~| ERROR late-bound type parameter not allowed on closures
 }

filename: tests/ui/closures/binder/bounds-on-closure-type-binders.stderr
patch: @@ -4,11 +4,5 @@ error: bounds cannot be used in this context
 LL |     let _ = for<T: Trait> || -> () {};
    |                    ^^^^^
 
-error: late-bound type parameter not allowed on closures
-  --> $DIR/bounds-on-closure-type-binders.rs:11:17
-   |
-LL |     let _ = for<T: Trait> || -> () {};
-   |                 ^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 

filename: tests/ui/traits/non_lifetime_binders/bad-bounds.rs
patch: @@ -0,0 +1,13 @@
+//@ edition: 2024
+
+#![feature(non_lifetime_binders)]
+#![expect(incomplete_features)]
+
+fn produce() -> for<A: A<{ //~ ERROR expected trait, found type parameter `A`
+    //~^ ERROR bounds cannot be used in this context
+    #[derive(Hash)]
+    enum A {}
+    struct A<A>; //~ ERROR the name `A` is defined multiple times
+}>> Trait {} //~ ERROR cannot find trait `Trait` in this scope
+
+fn main() {}

filename: tests/ui/traits/non_lifetime_binders/bad-bounds.stderr
patch: @@ -0,0 +1,46 @@
+error[E0428]: the name `A` is defined multiple times
+  --> $DIR/bad-bounds.rs:10:5
+   |
+LL |     enum A {}
+   |     ------ previous definition of the type `A` here
+LL |     struct A<A>;
+   |     ^^^^^^^^^^^^ `A` redefined here
+   |
+   = note: `A` must be defined only once in the type namespace of this block
+
+error[E0404]: expected trait, found type parameter `A`
+  --> $DIR/bad-bounds.rs:6:24
+   |
+LL |   fn produce() -> for<A: A<{
+   |  _____________________-__^
+   | |                     |
+   | |                     found this type parameter
+LL | |
+LL | |     #[derive(Hash)]
+LL | |     enum A {}
+LL | |     struct A<A>;
+LL | | }>> Trait {}
+   | |__^ not a trait
+
+error[E0405]: cannot find trait `Trait` in this scope
+  --> $DIR/bad-bounds.rs:11:5
+   |
+LL | }>> Trait {}
+   |     ^^^^^ not found in this scope
+
+error: bounds cannot be used in this context
+  --> $DIR/bad-bounds.rs:6:24
+   |
+LL |   fn produce() -> for<A: A<{
+   |  ________________________^
+LL | |
+LL | |     #[derive(Hash)]
+LL | |     enum A {}
+LL | |     struct A<A>;
+LL | | }>> Trait {}
+   | |__^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0404, E0405, E0428.
+For more information about an error, try `rustc --explain E0404`.