Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ErrorGuaranteed unsoundness with stash/steal. #120828

Merged
merged 1 commit into from
Feb 9, 2024

Conversation

nnethercote
Copy link
Contributor

@nnethercote nnethercote commented Feb 9, 2024

When you stash an error, the error count is incremented. You can then use the non-zero error count to get an ErrorGuaranteed. You can then steal the error, which decrements the error count. You can then cancel the error.

Example code:

fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
    let sp = rustc_span::DUMMY_SP;
    let k = rustc_errors::StashKey::Cycle;
    dcx.struct_err("bogus").stash(sp, k);           // increment error count on stash
    let guar = dcx.has_errors().unwrap();           // ErrorGuaranteed from error count > 0
    let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
    err.cancel();                                   // cancel error
    guar                                            // ErrorGuaranteed with no error emitted!
}

This commit fixes the problem in the simplest way: by not counting stashed errors in DiagCtxt::{err_count,has_errors}.

However, just doing this without any other changes leads to over 40 ui test failures. Mostly because of uninteresting extra errors (many saying "type annotations needed" when type inference fails), and in a few cases, due to delayed bugs causing ICEs when no normal errors are printed.

To fix these, this commit adds DiagCtxt::stashed_err_count, and uses it in three places alongside DiagCtxt::{has_errors,err_count}. It's dodgy to rely on it, because unlike DiagCtxt::err_count it can go up and down. But it's needed to preserve existing behaviour, and at least the three places that need it are now obvious.

r? oli-obk

When you stash an error, the error count is incremented. You can then
use the non-zero error count to get an `ErrorGuaranteed`. You can then
steal the error, which decrements the error count. You can then cancel
the error.

Example code:
```
fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
    let sp = rustc_span::DUMMY_SP;
    let k = rustc_errors::StashKey::Cycle;
    dcx.struct_err("bogus").stash(sp, k);           // increment error count on stash
    let guar = dcx.has_errors().unwrap();           // ErrorGuaranteed from error count > 0
    let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
    err.cancel();                                   // cancel error
    guar                                            // ErrorGuaranteed with no error emitted!
}
```

This commit fixes the problem in the simplest way: by not counting
stashed errors in `DiagCtxt::{err_count,has_errors}`.

However, just doing this without any other changes leads to over 40 ui
test failures. Mostly because of uninteresting extra errors (many saying
"type annotations needed" when type inference fails), and in a few
cases, due to delayed bugs causing ICEs when no normal errors are
printed.

To fix these, this commit adds `DiagCtxt::stashed_err_count`, and uses
it in three places alongside `DiagCtxt::{has_errors,err_count}`. It's
dodgy to rely on it, because unlike `DiagCtxt::err_count` it can go up
and down. But it's needed to preserve existing behaviour, and at least
the three places that need it are now obvious.
@rustbot
Copy link
Collaborator

rustbot commented Feb 9, 2024

r? @petrochenkov

rustbot has assigned @petrochenkov.
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

@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 Feb 9, 2024
@nnethercote
Copy link
Contributor Author

I botched the review request syntax:

r? @oli-obk

@rustbot rustbot assigned oli-obk and unassigned petrochenkov Feb 9, 2024
@rust-lang rust-lang deleted a comment from rustbot Feb 9, 2024
@oli-obk
Copy link
Contributor

oli-obk commented Feb 9, 2024

Thanks! This is great, now I can tackle these just like the has_errors checks

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Feb 9, 2024

📌 Commit 7619792 has been approved by oli-obk

It is now in the queue for this repository.

@bors bors 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 Feb 9, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 9, 2024
…-obk

Fix `ErrorGuaranteed` unsoundness with stash/steal.

When you stash an error, the error count is incremented. You can then use the non-zero error count to get an `ErrorGuaranteed`. You can then steal the error, which decrements the error count. You can then cancel the error.

Example code:
```
fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
    let sp = rustc_span::DUMMY_SP;
    let k = rustc_errors::StashKey::Cycle;
    dcx.struct_err("bogus").stash(sp, k);           // increment error count on stash
    let guar = dcx.has_errors().unwrap();           // ErrorGuaranteed from error count > 0
    let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
    err.cancel();                                   // cancel error
    guar                                            // ErrorGuaranteed with no error emitted!
}
```

This commit fixes the problem in the simplest way: by not counting stashed errors in `DiagCtxt::{err_count,has_errors}`.

However, just doing this without any other changes leads to over 40 ui test failures. Mostly because of uninteresting extra errors (many saying "type annotations needed" when type inference fails), and in a few cases, due to delayed bugs causing ICEs when no normal errors are printed.

To fix these, this commit adds `DiagCtxt::stashed_err_count`, and uses it in three places alongside `DiagCtxt::{has_errors,err_count}`. It's dodgy to rely on it, because unlike `DiagCtxt::err_count` it can go up and down. But it's needed to preserve existing behaviour, and at least the three places that need it are now obvious.

r? oli-obk
@nnethercote
Copy link
Contributor Author

Thanks! This is great, now I can tackle these just like the has_errors checks

What does "these" refer to here? I have an in-progress change that removes the unchecked_error_guaranteed() calls in DiagCtxt::has_errors and its related methods...

@nnethercote
Copy link
Contributor Author

#120833 has the in-progress work. The second commit contains the unchecked_error_guaranteed removals. I have a couple of follow-up changes I want to work on next week. But I posted it because I don't want us to duplicate any work.

bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 9, 2024
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#120308 (core/time: avoid divisions in Duration::new)
 - rust-lang#120596 ([rustdoc] Correctly generate path for non-local items in source code pages)
 - rust-lang#120693 (Invert diagnostic lints.)
 - rust-lang#120704 (A drive-by rewrite of `give_region_a_name()`)
 - rust-lang#120809 (Use `transmute_unchecked` in `NonZero::new`.)
 - rust-lang#120817 (Fix more `ty::Error` ICEs in MIR passes)
 - rust-lang#120828 (Fix `ErrorGuaranteed` unsoundness with stash/steal.)

r? `@ghost`
`@rustbot` modify labels: rollup
Some(guar)
} else if self.dcx().err_count() > self.err_count_on_creation {
// Errors reported since this infcx was made.
let guar = self.dcx().has_errors().unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

I am planning on getting rid of this one by correctly bubbling up errors instead.

// because the count of stashed errors can go down. But without
// this case we get a moderate number of uninteresting and
// extraneous "type annotations needed" errors.
let guar = self.dcx().delayed_bug("tainted_by_errors: stashed bug awaiting emission");
Copy link
Contributor

Choose a reason for hiding this comment

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

This one is harder due to the stashing. I'm considering differentiating between "avoid type_annotations_needed" usages and other usages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IIRC, if the we get rid of the MaybeForgetReturn StashKey by just emitting those errors immediately, we can then remove this stashed_err_count call and most or all of the extra "type annotations needed" errors go away, and the reduction in quality of other error messages is very small. In other words, stashing MaybeForgetReturn errors seems like it's more trouble than it's worth.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 9, 2024
…-obk

Fix `ErrorGuaranteed` unsoundness with stash/steal.

When you stash an error, the error count is incremented. You can then use the non-zero error count to get an `ErrorGuaranteed`. You can then steal the error, which decrements the error count. You can then cancel the error.

Example code:
```
fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
    let sp = rustc_span::DUMMY_SP;
    let k = rustc_errors::StashKey::Cycle;
    dcx.struct_err("bogus").stash(sp, k);           // increment error count on stash
    let guar = dcx.has_errors().unwrap();           // ErrorGuaranteed from error count > 0
    let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
    err.cancel();                                   // cancel error
    guar                                            // ErrorGuaranteed with no error emitted!
}
```

This commit fixes the problem in the simplest way: by not counting stashed errors in `DiagCtxt::{err_count,has_errors}`.

However, just doing this without any other changes leads to over 40 ui test failures. Mostly because of uninteresting extra errors (many saying "type annotations needed" when type inference fails), and in a few cases, due to delayed bugs causing ICEs when no normal errors are printed.

To fix these, this commit adds `DiagCtxt::stashed_err_count`, and uses it in three places alongside `DiagCtxt::{has_errors,err_count}`. It's dodgy to rely on it, because unlike `DiagCtxt::err_count` it can go up and down. But it's needed to preserve existing behaviour, and at least the three places that need it are now obvious.

r? oli-obk
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 9, 2024
…iaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang#113026 (Introduce `run-make` V2 infrastructure, a `run_make_support` library and port over 2 tests as example)
 - rust-lang#113671 (Make privacy visitor use types more (instead of HIR))
 - rust-lang#120308 (core/time: avoid divisions in Duration::new)
 - rust-lang#120693 (Invert diagnostic lints.)
 - rust-lang#120704 (A drive-by rewrite of `give_region_a_name()`)
 - rust-lang#120809 (Use `transmute_unchecked` in `NonZero::new`.)
 - rust-lang#120817 (Fix more `ty::Error` ICEs in MIR passes)
 - rust-lang#120828 (Fix `ErrorGuaranteed` unsoundness with stash/steal.)
 - rust-lang#120831 (Startup objects disappearing from sysroot)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 9, 2024
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#113671 (Make privacy visitor use types more (instead of HIR))
 - rust-lang#120308 (core/time: avoid divisions in Duration::new)
 - rust-lang#120693 (Invert diagnostic lints.)
 - rust-lang#120704 (A drive-by rewrite of `give_region_a_name()`)
 - rust-lang#120809 (Use `transmute_unchecked` in `NonZero::new`.)
 - rust-lang#120817 (Fix more `ty::Error` ICEs in MIR passes)
 - rust-lang#120828 (Fix `ErrorGuaranteed` unsoundness with stash/steal.)
 - rust-lang#120831 (Startup objects disappearing from sysroot)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 2f1ac41 into rust-lang:master Feb 9, 2024
11 checks passed
@rustbot rustbot added this to the 1.78.0 milestone Feb 9, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Feb 9, 2024
Rollup merge of rust-lang#120828 - nnethercote:fix-stash-steal, r=oli-obk

Fix `ErrorGuaranteed` unsoundness with stash/steal.

When you stash an error, the error count is incremented. You can then use the non-zero error count to get an `ErrorGuaranteed`. You can then steal the error, which decrements the error count. You can then cancel the error.

Example code:
```
fn unsound(dcx: &DiagCtxt) -> ErrorGuaranteed {
    let sp = rustc_span::DUMMY_SP;
    let k = rustc_errors::StashKey::Cycle;
    dcx.struct_err("bogus").stash(sp, k);           // increment error count on stash
    let guar = dcx.has_errors().unwrap();           // ErrorGuaranteed from error count > 0
    let err = dcx.steal_diagnostic(sp, k).unwrap(); // decrement error count on steal
    err.cancel();                                   // cancel error
    guar                                            // ErrorGuaranteed with no error emitted!
}
```

This commit fixes the problem in the simplest way: by not counting stashed errors in `DiagCtxt::{err_count,has_errors}`.

However, just doing this without any other changes leads to over 40 ui test failures. Mostly because of uninteresting extra errors (many saying "type annotations needed" when type inference fails), and in a few cases, due to delayed bugs causing ICEs when no normal errors are printed.

To fix these, this commit adds `DiagCtxt::stashed_err_count`, and uses it in three places alongside `DiagCtxt::{has_errors,err_count}`. It's dodgy to rely on it, because unlike `DiagCtxt::err_count` it can go up and down. But it's needed to preserve existing behaviour, and at least the three places that need it are now obvious.

r? oli-obk
@nnethercote nnethercote deleted the fix-stash-steal branch February 9, 2024 21:32
nnethercote added a commit to nnethercote/rust that referenced this pull request Feb 9, 2024
The meaning of this assertion changed in rust-lang#120828 when the meaning of
`has_errors` changed to exclude stashed errors. Evidently the new
meaning is too restrictive.

Fixes rust-lang#120856.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 10, 2024
Loosen an assertion to account for stashed errors.

The meaning of this assertion changed in rust-lang#120828 when the meaning of `has_errors` changed to exclude stashed errors. Evidently the new meaning is too restrictive.

Fixes rust-lang#120856.

r? `@oli-obk`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 10, 2024
Loosen an assertion to account for stashed errors.

The meaning of this assertion changed in rust-lang#120828 when the meaning of `has_errors` changed to exclude stashed errors. Evidently the new meaning is too restrictive.

Fixes rust-lang#120856.

r? ``@oli-obk``
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 10, 2024
Loosen an assertion to account for stashed errors.

The meaning of this assertion changed in rust-lang#120828 when the meaning of `has_errors` changed to exclude stashed errors. Evidently the new meaning is too restrictive.

Fixes rust-lang#120856.

r? ```@oli-obk```
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Feb 10, 2024
Rollup merge of rust-lang#120859 - nnethercote:fix-120856, r=oli-obk

Loosen an assertion to account for stashed errors.

The meaning of this assertion changed in rust-lang#120828 when the meaning of `has_errors` changed to exclude stashed errors. Evidently the new meaning is too restrictive.

Fixes rust-lang#120856.

r? ```@oli-obk```
flip1995 pushed a commit to flip1995/rust that referenced this pull request Feb 26, 2024
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#113671 (Make privacy visitor use types more (instead of HIR))
 - rust-lang#120308 (core/time: avoid divisions in Duration::new)
 - rust-lang#120693 (Invert diagnostic lints.)
 - rust-lang#120704 (A drive-by rewrite of `give_region_a_name()`)
 - rust-lang#120809 (Use `transmute_unchecked` in `NonZero::new`.)
 - rust-lang#120817 (Fix more `ty::Error` ICEs in MIR passes)
 - rust-lang#120828 (Fix `ErrorGuaranteed` unsoundness with stash/steal.)
 - rust-lang#120831 (Startup objects disappearing from sysroot)

r? `@ghost`
`@rustbot` modify labels: rollup
nnethercote added a commit to nnethercote/rust that referenced this pull request Feb 27, 2024
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. rust-lang#120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes rust-lang#121451.
Fixes rust-lang#121477.
Fixes rust-lang#121504.
Fixes rust-lang#121508.
nnethercote added a commit to nnethercote/rust that referenced this pull request Feb 27, 2024
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. rust-lang#120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes rust-lang#121451.
Fixes rust-lang#121477.
Fixes rust-lang#121504.
Fixes rust-lang#121508.
nnethercote added a commit to nnethercote/rust that referenced this pull request Feb 27, 2024
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. rust-lang#120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes rust-lang#121451.
Fixes rust-lang#121477.
Fixes rust-lang#121504.
Fixes rust-lang#121508.
nnethercote added a commit to nnethercote/rust that referenced this pull request Feb 29, 2024
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. rust-lang#120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes rust-lang#121451.
Fixes rust-lang#121477.
Fixes rust-lang#121504.
Fixes rust-lang#121508.
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Feb 29, 2024
…in, r=estebank

Count stashed errors again

Stashed diagnostics are such a pain. Their "might be emitted, might not" semantics messes with lots of things.

rust-lang#120828 and rust-lang#121206 made some big changes to how they work, improving some things, but still leaving some problems, as seen by the issues caused by rust-lang#121206. This PR aims to fix all of them by restricting them in a way that eliminates the "might be emitted, might not" semantics while still allowing 98% of their benefit. Details in the individual commit logs.

r? `@oli-obk`
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Feb 29, 2024
Rollup merge of rust-lang#121669 - nnethercote:count-stashed-errs-again, r=estebank

Count stashed errors again

Stashed diagnostics are such a pain. Their "might be emitted, might not" semantics messes with lots of things.

rust-lang#120828 and rust-lang#121206 made some big changes to how they work, improving some things, but still leaving some problems, as seen by the issues caused by rust-lang#121206. This PR aims to fix all of them by restricting them in a way that eliminates the "might be emitted, might not" semantics while still allowing 98% of their benefit. Details in the individual commit logs.

r? `@oli-obk`
nnethercote added a commit to nnethercote/rust that referenced this pull request Mar 1, 2024
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. rust-lang#120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes rust-lang#121451.
Fixes rust-lang#121477.
Fixes rust-lang#121504.
Fixes rust-lang#121508.
flip1995 pushed a commit to flip1995/rust that referenced this pull request Mar 7, 2024
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. rust-lang#120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes rust-lang#121451.
Fixes rust-lang#121477.
Fixes rust-lang#121504.
Fixes rust-lang#121508.
flip1995 pushed a commit to flip1995/rust that referenced this pull request Mar 7, 2024
…in, r=estebank

Count stashed errors again

Stashed diagnostics are such a pain. Their "might be emitted, might not" semantics messes with lots of things.

rust-lang#120828 and rust-lang#121206 made some big changes to how they work, improving some things, but still leaving some problems, as seen by the issues caused by rust-lang#121206. This PR aims to fix all of them by restricting them in a way that eliminates the "might be emitted, might not" semantics while still allowing 98% of their benefit. Details in the individual commit logs.

r? `@oli-obk`
bjorn3 pushed a commit to bjorn3/rust that referenced this pull request Mar 8, 2024
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#113671 (Make privacy visitor use types more (instead of HIR))
 - rust-lang#120308 (core/time: avoid divisions in Duration::new)
 - rust-lang#120693 (Invert diagnostic lints.)
 - rust-lang#120704 (A drive-by rewrite of `give_region_a_name()`)
 - rust-lang#120809 (Use `transmute_unchecked` in `NonZero::new`.)
 - rust-lang#120817 (Fix more `ty::Error` ICEs in MIR passes)
 - rust-lang#120828 (Fix `ErrorGuaranteed` unsoundness with stash/steal.)
 - rust-lang#120831 (Startup objects disappearing from sysroot)

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants