Skip to content

Emit ForbiddenBound for bounds of type params when parsing higher ranked binders#149728

Open
mu001999 wants to merge 1 commit intorust-lang:mainfrom
mu001999-contrib:fix/149695
Open

Emit ForbiddenBound for bounds of type params when parsing higher ranked binders#149728
mu001999 wants to merge 1 commit intorust-lang:mainfrom
mu001999-contrib:fix/149695

Conversation

@mu001999
Copy link
Contributor

@mu001999 mu001999 commented Dec 7, 2025

View all comments

Fixes #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.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 7, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 7, 2025

r? @wesleywiser

rustbot has assigned @wesleywiser.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rust-log-analyzer

This comment has been minimized.

@mu001999 mu001999 changed the title Emit ForbiddenBound fatally Emit ForbiddenBound fatally if meeting complex bounds Dec 7, 2025
@mu001999
Copy link
Contributor Author

@rustbot reroll

@rustbot rustbot assigned jdonszelmann and unassigned wesleywiser Dec 18, 2025
@jdonszelmann
Copy link
Contributor

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 8, 2026
@rustbot
Copy link
Collaborator

rustbot commented Jan 8, 2026

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@mu001999
Copy link
Contributor Author

mu001999 commented Jan 9, 2026

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 9, 2026
@jdonszelmann
Copy link
Contributor

@rusbot author

@jdonszelmann
Copy link
Contributor

@rustbot blocked on #149728 (comment)

@rustbot rustbot added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 9, 2026
@rustbot

This comment has been minimized.

@mu001999 mu001999 marked this pull request as draft January 9, 2026 15:56
@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jan 9, 2026
@rust-log-analyzer

This comment has been minimized.

@mu001999
Copy link
Contributor Author

mu001999 commented Jan 9, 2026

Hi @jdonszelmann, in the lastest rough change, I tried to filter nested items in the bound, and not lower them to hir.

dbg! shows it works:

[compiler/rustc_ast_lowering/src/lib.rs:527:17] "skipping lowering of {:?}" = "skipping lowering of {:?}"
[compiler/rustc_ast_lowering/src/lib.rs:527:17] def_id = DefId(0:6 ~ bad_bounds[bee6]::produce::{constant#0}::A)
[compiler/rustc_ast_lowering/src/lib.rs:527:17] "skipping lowering of {:?}" = "skipping lowering of {:?}"
[compiler/rustc_ast_lowering/src/lib.rs:527:17] def_id = DefId(0:7 ~ bad_bounds[bee6]::produce::{constant#0}::A::{constructor#0})
[compiler/rustc_ast_lowering/src/lib.rs:527:17] "skipping lowering of {:?}" = "skipping lowering of {:?}"
[compiler/rustc_ast_lowering/src/lib.rs:527:17] def_id = DefId(0:8 ~ bad_bounds[bee6]::produce::{constant#0}::A::A)
[compiler/rustc_ast_lowering/src/lib.rs:527:17] "skipping lowering of {:?}" = "skipping lowering of {:?}"
[compiler/rustc_ast_lowering/src/lib.rs:527:17] def_id = DefId(0:10 ~ bad_bounds[bee6]::produce::{constant#0}::A#1)
[compiler/rustc_ast_lowering/src/lib.rs:527:17] "skipping lowering of {:?}" = "skipping lowering of {:?}"
[compiler/rustc_ast_lowering/src/lib.rs:527:17] def_id = DefId(0:11 ~ bad_bounds[bee6]::produce::{constant#0}::{impl#0})

But there still be errors, because they still have LocalDefId, so that they can be result of many other queries. For example, after the change, a new ICE appears because type_of(bad_bounds[bee6]::produce::{constant#0}::{impl#0}).

Concrete content of the new ICE is:

error: internal compiler error: compiler/rustc_middle/src/hir/mod.rs:385:32: No HirId for DefId(0:11 ~ bad_bounds[bee6]::produce::{constant#0}::{impl#0})


thread 'rustc' (6902108) panicked at compiler/rustc_middle/src/hir/mod.rs:385:32:
Box<dyn Any>
stack backtrace:
   0: std::panicking::begin_panic::<rustc_errors::ExplicitBug>
             at /rustc/1b6e21e163baa0b20f119e17e3871910978a60b6/library/std/src/panicking.rs:761:5
   1: std::panic::panic_any::<rustc_errors::ExplicitBug>
             at /rustc/1b6e21e163baa0b20f119e17e3871910978a60b6/library/std/src/panic.rs:260:5
   2: <rustc_errors::diagnostic::BugAbort as rustc_errors::diagnostic::EmissionGuarantee>::emit_producing_guarantee
             at ./compiler/rustc_errors/src/diagnostic.rs:63:9
   3: <rustc_errors::diagnostic::Diag<rustc_errors::diagnostic::BugAbort>>::emit
             at ./compiler/rustc_errors/src/diagnostic.rs:1405:9
   4: <rustc_errors::DiagCtxtHandle>::bug::<alloc::string::String>
             at ./compiler/rustc_errors/src/lib.rs:1231:30
   5: rustc_middle::util::bug::opt_span_bug_fmt::<rustc_span::span_encoding::Span>::{closure#0}
             at ./compiler/rustc_middle/src/util/bug.rs:39:48
   6: rustc_middle::ty::context::tls::with_opt::<rustc_middle::util::bug::opt_span_bug_fmt<rustc_span::span_encoding::Span>::{closure#0}, !>::{closure#0}
             at ./compiler/rustc_middle/src/ty/context/tls.rs:136:23
   7: rustc_middle::ty::context::tls::with_context_opt::<rustc_middle::ty::context::tls::with_opt<rustc_middle::util::bug::opt_span_bug_fmt<rustc_span::span_encoding::Span>::{closure#0}, !>::{closure#0}, !>
             at ./compiler/rustc_middle/src/ty/context/tls.rs:79:18
   8: rustc_middle::ty::context::tls::with_opt::<rustc_middle::util::bug::opt_span_bug_fmt<rustc_span::span_encoding::Span>::{closure#0}, !>
             at ./compiler/rustc_middle/src/ty/context/tls.rs:134:5
   9: rustc_middle::util::bug::opt_span_bug_fmt::<rustc_span::span_encoding::Span>
             at ./compiler/rustc_middle/src/util/bug.rs:33:5
  10: rustc_middle::util::bug::bug_fmt
             at ./compiler/rustc_middle/src/util/bug.rs:16:5
  11: rustc_middle::hir::provide::{closure#0}
             at ./compiler/rustc_middle/src/macros.rs:18:9
  12: <rustc_middle::hir::provide::{closure#0} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId)>>::call_once
             at /rustc/1b6e21e163baa0b20f119e17e3871910978a60b6/library/core/src/ops/function.rs:250:5
  13: rustc_query_impl::query_impl::local_def_id_to_hir_id::dynamic_query::{closure#2}::{closure#0}
             at ./compiler/rustc_query_impl/src/plumbing.rs:298:9
      [... omitted 22 frames ...]
  14: rustc_middle::query::inner::query_get_at::<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::Erased<[u8; 8]>, rustc_query_system::dep_graph::graph::DepNodeIndex>>
             at ./compiler/rustc_middle/src/query/inner.rs:33:17
  15: <rustc_middle::query::plumbing::TyCtxtAt>::local_def_id_to_hir_id::<rustc_span::def_id::LocalDefId>
             at ./compiler/rustc_middle/src/query/plumbing.rs:415:31
  16: <rustc_middle::ty::context::TyCtxt>::local_def_id_to_hir_id::<rustc_span::def_id::LocalDefId>
             at ./compiler/rustc_middle/src/query/plumbing.rs:406:35
  17: rustc_hir_analysis::collect::type_of::type_of::{closure#0}
             at ./compiler/rustc_hir_analysis/src/collect/type_of.rs:56:22
  18: rustc_hir_analysis::collect::type_of::type_of
             at ./compiler/rustc_hir_analysis/src/collect/type_of.rs:21:1
  19: rustc_query_impl::query_impl::type_of::dynamic_query::{closure#2}::{closure#0}
             at ./compiler/rustc_query_impl/src/plumbing.rs:302:13
      [... omitted 22 frames ...]
  20: rustc_middle::query::inner::query_get_at::<rustc_query_system::query::caches::DefIdCache<rustc_middle::query::erase::Erased<[u8; 8]>>>
             at ./compiler/rustc_middle/src/query/inner.rs:33:17
  21: <rustc_middle::query::plumbing::TyCtxtAt>::type_of::<rustc_span::def_id::DefId>
             at ./compiler/rustc_middle/src/query/plumbing.rs:415:31
  22: <rustc_middle::ty::context::TyCtxt>::type_of::<rustc_span::def_id::DefId>
             at ./compiler/rustc_middle/src/query/plumbing.rs:406:35
  23: rustc_middle::ty::trait_def::trait_impls_of_provider
             at ./compiler/rustc_middle/src/ty/trait_def.rs:227:32
  24: rustc_query_impl::query_impl::trait_impls_of::dynamic_query::{closure#2}::{closure#0}
             at ./compiler/rustc_query_impl/src/plumbing.rs:298:9
      [... omitted 22 frames ...]
  25: rustc_middle::query::inner::query_get_at::<rustc_query_system::query::caches::DefIdCache<rustc_middle::query::erase::Erased<[u8; 8]>>>
             at ./compiler/rustc_middle/src/query/inner.rs:33:17
  26: <rustc_middle::query::plumbing::TyCtxtAt>::trait_impls_of::<rustc_span::def_id::DefId>
             at ./compiler/rustc_middle/src/query/plumbing.rs:415:31
  27: <rustc_middle::ty::context::TyCtxt>::trait_impls_of::<rustc_span::def_id::DefId>
             at ./compiler/rustc_middle/src/query/plumbing.rs:406:35
  28: <rustc_middle::ty::context::TyCtxt>::all_impls
             at ./compiler/rustc_middle/src/ty/trait_def.rs:194:68

@mu001999
Copy link
Contributor Author

mu001999 commented Jan 9, 2026

I think at least it's more difficult than I expected. Do you have any suggestions?

@rust-bors

This comment has been minimized.

@rustbot
Copy link
Collaborator

rustbot commented Feb 15, 2026

Some changes occurred in src/tools/rustfmt

cc @rust-lang/rustfmt

@rustbot rustbot added the T-rustfmt Relevant to the rustfmt team, which will review and decide on the PR/issue. label Feb 15, 2026
@rust-log-analyzer

This comment has been minimized.

@jdonszelmann
Copy link
Contributor

@mu001999 is this ready for review? I think doing it like this is quite reasonable, and we don't error fatally which is nice.

@mu001999
Copy link
Contributor Author

is this ready for review

yep, it's ready :)

@jdonszelmann
Copy link
Contributor

r=me after that

@mu001999 mu001999 requested a review from jdonszelmann March 5, 2026 03:41
@jdonszelmann
Copy link
Contributor

@bors r+ rollup

@rust-bors
Copy link
Contributor

rust-bors bot commented Mar 9, 2026

📌 Commit ca6cc5d has been approved by jdonszelmann

It is now in the queue for this repository.

@rust-bors rust-bors bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 9, 2026
@jdonszelmann
Copy link
Contributor

@bors rollup=never

@rust-bors
Copy link
Contributor

rust-bors bot commented Mar 9, 2026

⌛ Testing commit ca6cc5d with merge e9478d8...

Workflow: https://github.com/rust-lang/rust/actions/runs/22864415094

rust-bors bot pushed a commit that referenced this pull request Mar 9, 2026
Emit ForbiddenBound for bounds of type params when parsing higher ranked binders



Fixes #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.
Copy link
Member

@fmease fmease left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change to stable Rust's grammar. This is not acceptable without T-lang involvement and a crater run.

Moreover this renders the grammar quite inconsistent by syntactically rejecting bounds on higher-ranked type parameters but syntactically permitting them on higher-ranked lifetime parameters.

View changes since this review

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 9, 2026
@fmease
Copy link
Member

fmease commented Mar 9, 2026

@bors r-

@rust-bors rust-bors bot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 9, 2026
@rust-bors
Copy link
Contributor

rust-bors bot commented Mar 9, 2026

This pull request was unapproved.

Auto build was cancelled due to unapproval. Cancelled workflows:

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 9, 2026
…r=fmease

Ping fmease on parser modifications

From time to time innocuous-seeming PRs get submitted and sometimes even approved that unbeknownst to their author and to reviewers change the grammar of (stable) Rust which would be a breaking change; often they only meant to tweak diagnostics.

I sometimes catch such PRs before they get merged but I want to make it a lot harder for them to slip through the cracks going forward.

I'm going to list recent examples to paint a picture (note: this is not about blame!):

1. rust-lang#149728 (review) (2026)
   * caught before merge but after approval
   * PR unapproved for now
2. rust-lang#152501 (2026)
   * caught after merge of rust-lang#149489
   * fixed & backported
3. rust-lang#152499 (2026)
   * caught after merge of rust-lang#149667
   * fixed & backported
4. rust-lang#151960 (comment) (2026)
   * caught right after submission
   * the approach was thus changed
5. rust-lang#148238 (2025)
   * caught after merge of rust-lang#118947
   * still unaddressed
6. rust-lang#144386 (review) (2025)
   * caught right after submission
   * crater & T-lang were activated by me
7. rust-lang#119042 (comment) (2023)
   * caught right after submission
   * the approach was thus changed
8. rust-lang#103534 (2022)
   * caught way later
   * partially addressed

Why not just post a note without pinging me? Well, due to them not failing CI and generally due to (friendly) botspam, such comments just get lost or sometimes even actively ignored.

Of course, I'm not able to catch everything. E.g., I didn't notice issue rust-lang#146417 before PR rust-lang#139858 was merged despite having skimmed its diff and more importantly, I as a reviewer missed the blatantly obvious rust-lang#144958 before merge.

Separately, off and on over the span of one year I've worked on a Rust parser that now has >99% accuracy/parity with rustc according to some metrics (this includes stable + unstable + internal syntax) and which I'm using to detect such regressions and issues in general among other things (e.g., rust-lang#152499 and rust-lang#152820 were found this way, more to come). I'm pretty invested, let's say.

r? me
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Mar 9, 2026
…r=fmease

Ping fmease on parser modifications

From time to time innocuous-seeming PRs get submitted and sometimes even approved that unbeknownst to their author and to reviewers change the grammar of (stable) Rust which would be a breaking change; often they only meant to tweak diagnostics.

I sometimes catch such PRs before they get merged but I want to make it a lot harder for them to slip through the cracks going forward.

I'm going to list recent examples to paint a picture (note: this is not about blame!):

1. rust-lang#149728 (review) (2026)
   * caught before merge but after approval
   * PR unapproved for now
2. rust-lang#152501 (2026)
   * caught after merge of rust-lang#149489
   * fixed & backported
3. rust-lang#152499 (2026)
   * caught after merge of rust-lang#149667
   * fixed & backported
4. rust-lang#151960 (comment) (2026)
   * caught right after submission
   * the approach was thus changed
5. rust-lang#148238 (2025)
   * caught after merge of rust-lang#118947
   * still unaddressed
6. rust-lang#144386 (review) (2025)
   * caught right after submission
   * crater & T-lang were activated by me
7. rust-lang#119042 (comment) (2023)
   * caught right after submission
   * the approach was thus changed
8. rust-lang#103534 (2022)
   * caught way later
   * partially addressed

Why not just post a note without pinging me? Well, due to them not failing CI and generally due to (friendly) botspam, such comments just get lost or sometimes even actively ignored.

Of course, I'm not able to catch everything. E.g., I didn't notice issue rust-lang#146417 before PR rust-lang#139858 was merged despite having skimmed its diff and more importantly, I as a reviewer missed the blatantly obvious rust-lang#144958 before merge.

Separately, off and on over the span of one year I've worked on a Rust parser that now has >99% accuracy/parity with rustc according to some metrics (this includes stable + unstable + internal syntax) and which I'm using to detect such regressions and issues in general among other things (e.g., rust-lang#152499 and rust-lang#152820 were found this way, more to come). I'm pretty invested, let's say.

r? me
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Mar 9, 2026
…r=fmease

Ping fmease on parser modifications

From time to time innocuous-seeming PRs get submitted and sometimes even approved that unbeknownst to their author and to reviewers change the grammar of (stable) Rust which would be a breaking change; often they only meant to tweak diagnostics.

I sometimes catch such PRs before they get merged but I want to make it a lot harder for them to slip through the cracks going forward.

I'm going to list recent examples to paint a picture (note: this is not about blame!):

1. rust-lang#149728 (review) (2026)
   * caught before merge but after approval
   * PR unapproved for now
2. rust-lang#152501 (2026)
   * caught after merge of rust-lang#149489
   * fixed & backported
3. rust-lang#152499 (2026)
   * caught after merge of rust-lang#149667
   * fixed & backported
4. rust-lang#151960 (comment) (2026)
   * caught right after submission
   * the approach was thus changed
5. rust-lang#148238 (2025)
   * caught after merge of rust-lang#118947
   * still unaddressed
6. rust-lang#144386 (review) (2025)
   * caught right after submission
   * crater & T-lang were activated by me
7. rust-lang#119042 (comment) (2023)
   * caught right after submission
   * the approach was thus changed
8. rust-lang#103534 (2022)
   * caught way later
   * partially addressed

Why not just post a note without pinging me? Well, due to them not failing CI and generally due to (friendly) botspam, such comments just get lost or sometimes even actively ignored.

Of course, I'm not able to catch everything. E.g., I didn't notice issue rust-lang#146417 before PR rust-lang#139858 was merged despite having skimmed its diff and more importantly, I as a reviewer missed the blatantly obvious rust-lang#144958 before merge.

Separately, off and on over the span of one year I've worked on a Rust parser that now has >99% accuracy/parity with rustc according to some metrics (this includes stable + unstable + internal syntax) and which I'm now using to detect such regressions and issues in general among other things (e.g., rust-lang#152499 and rust-lang#152820 were found this way, more to come). I'm pretty invested, let's say.

r? me
@mu001999
Copy link
Contributor Author

mu001999 commented Mar 10, 2026

@jdonszelmann Hi, what's your opinion on the next step? Do a crater run and nominate it for T-lang discussion, or back to directly emitting a fatal error?

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 10, 2026
rust-timer added a commit that referenced this pull request Mar 10, 2026
Rollup merge of #153624 - fmease:ping-me-on-parser-changes, r=fmease

Ping fmease on parser modifications

From time to time innocuous-seeming PRs get submitted and sometimes even approved that unbeknownst to their author and to reviewers change the grammar of (stable) Rust which would be a breaking change; often they only meant to tweak diagnostics.

I sometimes catch such PRs before they get merged but I want to make it a lot harder for them to slip through the cracks going forward.

I'm going to list recent examples to paint a picture (note: this is not about blame!):

1. #149728 (review) (2026)
   * caught before merge but after approval
   * PR unapproved for now
2. #152501 (2026)
   * caught after merge of #149489
   * fixed & backported
3. #152499 (2026)
   * caught after merge of #149667
   * fixed & backported
4. #151960 (comment) (2026)
   * caught right after submission
   * the approach was thus changed
5. #148238 (2025)
   * caught after merge of #118947
   * still unaddressed
6. #144386 (review) (2025)
   * caught right after submission
   * crater & T-lang were activated by me
7. #119042 (comment) (2023)
   * caught right after submission
   * the approach was thus changed
8. #103534 (2022)
   * caught way later
   * partially addressed

Why not just post a note without pinging me? Well, due to them not failing CI and generally due to (friendly) botspam, such comments just get lost or sometimes even actively ignored.

Of course, I'm not able to catch everything. E.g., I didn't notice issue #146417 before PR #139858 was merged despite having skimmed its diff and more importantly, I as a reviewer missed the blatantly obvious #144958 before merge.

Separately, off and on over the span of one year I've worked on a Rust parser that now has >99% accuracy/parity with rustc according to some metrics (this includes stable + unstable + internal syntax) and which I'm now using to detect such regressions and issues in general among other things (e.g., #152499 and #152820 were found this way, more to come). I'm pretty invested, let's say.

r? me
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-regression Performance regression. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustfmt Relevant to the rustfmt team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ICE No HirId for DefId

8 participants