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

Improve unused_unsafe lint #93678

Merged
merged 1 commit into from
Feb 20, 2022
Merged

Conversation

steffahn
Copy link
Member

@steffahn steffahn commented Feb 5, 2022

I’m going to add some motivation and explanation below, particularly pointing the changes in behavior from this PR.

Edit: Looking for existing issues, looks like this PR fixes #88260.

Edit2: Now also contains code that closes #90776.

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Feb 5, 2022
@rust-highfive
Copy link
Collaborator

r? @petrochenkov

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 5, 2022
@rust-log-analyzer

This comment has been minimized.

@steffahn
Copy link
Member Author

steffahn commented Feb 5, 2022

By the way, this is the first time I’ve touched rustc source code (prior contributions of mine were standard-library only).

Main motivation: Fixes some issues with the current behavior. This PR is more-or-less completely re-implementing the unused_unsafe lint; it’s also only done in the MIR-version of the lint, the set of tests for the -Zthir-unsafeck version no longer succeeds (and is thus disabled, see lint-unused-unsafe.rs).

On current nightly,

unsafe fn unsf() {}

fn inner_ignored() {
    unsafe {
        #[allow(unused_unsafe)]
        unsafe {
            unsf()
        }
    }
}

doesn’t create any warnings. This situation is not unrealistic to come by, the inner unsafe block could e.g. come from a macro. Actually, this PR even includes removal of one unused unsafe in the standard library that was missed in a similar situation. (The inner unsafe coming from an external macro hides the warning, too.)

The reason behind this problem is how the check currently works:

  • While generating MIR, it already skips nested unsafe blocks (i.e. unsafe nested in other unsafe) so that the inner one is always the one considered unused
  • To differentiate the cases of no unsafe operations inside the unsafe vs. a surrounding unsafe block, there’s some ad-hoc magic walking up the HIR to look for surrounding used unsafe blocks.

There’s a lot of problems with this approach besides the one presented above. E.g. the MIR-building uses checks for unsafe_op_in_unsafe_fn lint to decide early whether or not unsafe blocks in an unsafe fn are redundant and ought to be removed.

#[allow(unsafe_op_in_unsafe_fn)]
unsafe fn granular_disallow_op_in_unsafe_fn() {
    unsafe {
        #[deny(unsafe_op_in_unsafe_fn)]
        {
            unsf();
        }
    }
}
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
  --> src/main.rs:13:13
   |
13 |             unsf();
   |             ^^^^^^ call to unsafe function
   |
note: the lint level is defined here
  --> src/main.rs:11:16
   |
11 |         #[deny(unsafe_op_in_unsafe_fn)]
   |                ^^^^^^^^^^^^^^^^^^^^^^
   = note: consult the function's documentation for information on how to avoid undefined behavior

warning: unnecessary `unsafe` block
  --> src/main.rs:10:5
   |
9  | unsafe fn granular_disallow_op_in_unsafe_fn() {
   | --------------------------------------------- because it's nested under this `unsafe` fn
10 |     unsafe {
   |     ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

Here, the intermediate unsafe was ignored, even though it contains a unsafe operation that is not allowed to happen in an unsafe fn without an additional unsafe block.

Also closures were problematic and the workaround/algorithms used on current nightly didn’t work properly. (I skipped trying to fully understand what it was supposed to do, because this PR uses a completely different approach.)

fn nested() {
    unsafe {
        unsafe { unsf() }
    }
}
warning: unnecessary `unsafe` block
  --> src/main.rs:10:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

vs

fn nested() {
    let _ = || unsafe {
        let _ = || unsafe { unsf() };
    };
}
warning: unnecessary `unsafe` block
 --> src/main.rs:9:16
  |
9 |     let _ = || unsafe {
  |                ^^^^^^ unnecessary `unsafe` block
  |
  = note: `#[warn(unused_unsafe)]` on by default

warning: unnecessary `unsafe` block
  --> src/main.rs:10:20
   |
10 |         let _ = || unsafe { unsf() };
   |                    ^^^^^^ unnecessary `unsafe` block

note that this warning kind-of suggests that both unsafe blocks are redundant


I also dislike the fact that it always suggests keeping the outermost unsafe. E.g. for

fn granularity() {
    unsafe {
        unsafe { unsf() }
        unsafe { unsf() }
        unsafe { unsf() }
    }
}

I prefer if rustc suggests removing the more-course outer-level unsafe instead of the fine-grained inner unsafe blocks, which it currently does on nightly:

warning: unnecessary `unsafe` block
  --> src/main.rs:10:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

warning: unnecessary `unsafe` block
  --> src/main.rs:11:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsafe { unsf() }
11 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block

warning: unnecessary `unsafe` block
  --> src/main.rs:12:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
...
12 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block

Needless to say, this PR addresses all these points. For context, as far as my understanding goes, the main advantage of skipping inner unsafe blocks was that a test case like

fn top_level_used() {
    unsafe {
        unsf();
        unsafe { unsf() }
        unsafe { unsf() }
        unsafe { unsf() }
    }
}

should generate some warning because there’s redundant nested unsafe, however every single unsafe block does contain some statement that uses it. Of course this PR doesn’t aim change the warnings on this kind of code example, because the current behavior, warning on all the inner unsafe blocks, makes sense in this case.

As mentioned, during MIR building all the unsafe blocks are kept now, and usage is attributed to them. The way to still generate a warning like

warning: unnecessary `unsafe` block
  --> src/main.rs:11:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsf();
11 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

warning: unnecessary `unsafe` block
  --> src/main.rs:12:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
...
12 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block

warning: unnecessary `unsafe` block
  --> src/main.rs:13:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
...
13 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block

in this case is by emitting a unused_unsafe warning for all of the unsafe blocks that are within a used unsafe block.

The previous code had a little HIR traversal already anyways to collect a set of all the unsafe blocks (in order to afterwards determine which ones are unused afterwards). This PR uses such a traversal to do additional things including logic like always warn for an unsafe block that’s inside of another used unsafe block. The traversal is expanded to include nested closures in the same go, this simplifies a lot of things.

The whole logic around unsafe_op_in_unsafe_fn is a little complicated, there’s some test cases of corner-cases in this PR. (The implementation involves differentiating between whether a used unsafe block was used exclusively by operations where allow(unsafe_op_in_unsafe_fn) was active.) The main goal was to make sure that code should compile successfully if all the unused_unsafe-warnings are addressed simultaneously (by removing the respective unsafe blocks) no matter how complicated the patterns of unsafe_op_in_unsafe_fn being disallowed and allowed throughout the function are.


One noteworthy design decision I took here: An unsafe block with allow(unused_unsafe) is considered used for the purposes of linting about redundant contained unsafe blocks. So while

#![deny(unused_unsafe)]

fn granularity() {
    unsafe { //~ ERROR: unnecessary `unsafe` block
        unsafe { unsf() }
        unsafe { unsf() }
        unsafe { unsf() }
    }
}

warns for the outer unsafe block,

#![deny(unused_unsafe)]

fn top_level_ignored() {
    #[allow(unused_unsafe)]
    unsafe {
        #[deny(unused_unsafe)]
        {
            unsafe { unsf() } //~ ERROR: unnecessary `unsafe` block
            unsafe { unsf() } //~ ERROR: unnecessary `unsafe` block
            unsafe { unsf() } //~ ERROR: unnecessary `unsafe` block
        }
    }
}

warns on the inner ones.


It makes sense to review commit-by-commit; I’ve e.g. split implementation from addressing tests, and within tests, there’s also distinguishing blessing changed output from previous tests from adding new tests.

@steffahn
Copy link
Member Author

steffahn commented Feb 5, 2022

Alright, that test failure is interesting… looks like I have some debugging to do. Some problems in handling inline_const

@steffahn
Copy link
Member Author

steffahn commented Feb 5, 2022

Unsurprisingly, it fails for

fn f() {
    let x: [(); unsafe { size() }] = [];
}

const unsafe fn size() -> usize { 0 } 

too.

Probably the underlying issues here is that the OnlyBodies filter does include such non-item constants.

Hmm, maybe I should go all-in and try to fix #72359? 🤔, ah well, probably better as a separate thing.

@steffahn
Copy link
Member Author

steffahn commented Feb 5, 2022

Let’s see if it passes now.

@rust-log-analyzer

This comment has been minimized.

@steffahn steffahn force-pushed the better_unsafe_diagnostics branch 2 times, most recently from 27ea257 to 616482e Compare February 5, 2022 21:38
@petrochenkov
Copy link
Contributor

I have approximately zero experience with MIR passes, so it's probably better to find someone else for reviewing this.
r? rust-lang/compiler

@rust-highfive rust-highfive assigned nagisa and unassigned petrochenkov Feb 6, 2022
@steffahn
Copy link
Member Author

steffahn commented Feb 6, 2022

I’m replacing the fix of c14a771 with a different approach. The idea in c14a771 was to still keep the opt-in to visiting all nested bodies, but opt-out of handling anonymous consts. For this to correlate correctly with unsafety checking (which only recurses into closures), it relies on the fact that nested bodies only appear in

  • item-likes (i.e. items, impl items, trait-decl items)
  • closures
  • non-item constants (in types or array length or inline consts) via “anon-const”

The nested-bodies traversal via OnlyBodies skips item-likes and manually making visit_anon_const a no-op left only closures.

I’m adding a new commit that uses the default None filter again, and instead uses an opt-in approach to handle closures nonetheless.

@steffahn
Copy link
Member Author

steffahn commented Feb 6, 2022

I’m adding a fix for #90776. Feel free to tell me if this should rather be in a separate PR.

@steffahn
Copy link
Member Author

steffahn commented Feb 7, 2022

I’ve also created a way to integrate this improved unused_unsafe check into the -Zthir_unsafeck code: dc1056a

I’ll keep that for a separate PR, for if this one gets accepted.

@bors
Copy link
Contributor

bors commented Feb 8, 2022

☔ The latest upstream changes (presumably #92007) made this pull request unmergeable. Please resolve the merge conflicts.

@steffahn
Copy link
Member Author

steffahn commented Feb 8, 2022

(The conflict is just some use statements, I can fix that later as a rebase might interfere with review.)

Copy link
Member

@nagisa nagisa left a comment

Choose a reason for hiding this comment

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

Haven't reviewed the pass itself yet, but please do rebase. This needs a perf run.

@steffahn
Copy link
Member Author

steffahn commented Feb 14, 2022

Haven't reviewed the pass itself yet, but please do rebase. This needs a perf run.

Actually, looks like the PR that had the conflict was reverted 3 days ago, and there is no merge conflict anymore.

@nagisa
Copy link
Member

nagisa commented Feb 14, 2022

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Feb 14, 2022
@bors
Copy link
Contributor

bors commented Feb 14, 2022

⌛ Trying commit 3cecf81 with merge cba9c92e82f65b5d96c1039773f6812ec659a4f7...

@bors
Copy link
Contributor

bors commented Feb 15, 2022

☀️ Try build successful - checks-actions
Build commit: cba9c92e82f65b5d96c1039773f6812ec659a4f7 (cba9c92e82f65b5d96c1039773f6812ec659a4f7)

@rust-timer
Copy link
Collaborator

Queued cba9c92e82f65b5d96c1039773f6812ec659a4f7 with parent c5c610a, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (cba9c92e82f65b5d96c1039773f6812ec659a4f7): comparison url.

Summary: This benchmark run shows 9 relevant improvements 🎉 but 5 relevant regressions 😿 to instruction counts.

  • Average relevant regression: 0.8%
  • Average relevant improvement: -0.2%
  • Largest improvement in instruction counts: -0.3% on incr-unchanged builds of keccak debug
  • Largest regression in instruction counts: 1.3% on incr-patched: println builds of webrender check

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR led to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: +S-waiting-on-review -S-waiting-on-perf +perf-regression

@steffahn
Copy link
Member Author

Looks like one of those PRs that introduces using let-else in a lot of places introduced a (trivial to resolve) merge conflict. As before, I'll postpone rebasing until review is complete.

@nagisa
Copy link
Member

nagisa commented Feb 20, 2022

LGTM.

@steffahn
Copy link
Member Author

LGTM.

So I can rebase?

@nagisa
Copy link
Member

nagisa commented Feb 20, 2022

Yeah.

@steffahn
Copy link
Member Author

Done rebasing, and CI is passing.

@nagisa
Copy link
Member

nagisa commented Feb 20, 2022

Could you also squash the commits together so that a more meaningful history is formed once the merge happens? In particular commits such as those dealing with rustfmt idiosyncrasies, addressing review comments and similar don't really have a lasting historical value. From what I can tell this PR could be 1 to 3 commits, one for lint changes and then the others for adjusting the test suite.

@steffahn
Copy link
Member Author

I thought about this… I’m having a hard time finding any reasonable split, besides integrating everything into a single commit. E.g. tests are already separated by being changes in different files. I guess I can just put everything into a single commit if that’s preferred over the status quo; what do you think?

@nagisa
Copy link
Member

nagisa commented Feb 20, 2022

A single commit would be good too. It would be awesome if its message is made to contain the text from your long explanation comment too. That way the motivation doesn't get lost when github eventually decides to pull the plug.

Main motivation: Fixes some issues with the current behavior. This PR is
more-or-less completely re-implementing the unused_unsafe lint; it’s also only
done in the MIR-version of the lint, the set of tests for the `-Zthir-unsafeck`
version no longer succeeds (and is thus disabled, see `lint-unused-unsafe.rs`).

On current nightly,
```rs
unsafe fn unsf() {}

fn inner_ignored() {
    unsafe {
        #[allow(unused_unsafe)]
        unsafe {
            unsf()
        }
    }
}
```

doesn’t create any warnings. This situation is not unrealistic to come by, the
inner `unsafe` block could e.g. come from a macro. Actually, this PR even
includes removal of one unused `unsafe` in the standard library that was missed
in a similar situation. (The inner `unsafe` coming from an external macro hides
    the warning, too.)

The reason behind this problem is how the check currently works:
* While generating MIR, it already skips nested unsafe blocks (i.e. unsafe
  nested in other unsafe) so that the inner one is always the one considered
  unused
* To differentiate the cases of no unsafe operations inside the `unsafe` vs.
  a surrounding `unsafe` block, there’s some ad-hoc magic walking up the HIR to
  look for surrounding used `unsafe` blocks.

There’s a lot of problems with this approach besides the one presented above.
E.g. the MIR-building uses checks for `unsafe_op_in_unsafe_fn` lint to decide
early whether or not `unsafe` blocks in an `unsafe fn` are redundant and ought
to be removed.
```rs
unsafe fn granular_disallow_op_in_unsafe_fn() {
    unsafe {
        #[deny(unsafe_op_in_unsafe_fn)]
        {
            unsf();
        }
    }
}
```
```
error: call to unsafe function is unsafe and requires unsafe block (error E0133)
  --> src/main.rs:13:13
   |
13 |             unsf();
   |             ^^^^^^ call to unsafe function
   |
note: the lint level is defined here
  --> src/main.rs:11:16
   |
11 |         #[deny(unsafe_op_in_unsafe_fn)]
   |                ^^^^^^^^^^^^^^^^^^^^^^
   = note: consult the function's documentation for information on how to avoid undefined behavior

warning: unnecessary `unsafe` block
  --> src/main.rs:10:5
   |
9  | unsafe fn granular_disallow_op_in_unsafe_fn() {
   | --------------------------------------------- because it's nested under this `unsafe` fn
10 |     unsafe {
   |     ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

```
Here, the intermediate `unsafe` was ignored, even though it contains a unsafe
operation that is not allowed to happen in an `unsafe fn` without an additional `unsafe` block.

Also closures were problematic and the workaround/algorithms used on current
nightly didn’t work properly. (I skipped trying to fully understand what it was
supposed to do, because this PR uses a completely different approach.)
```rs
fn nested() {
    unsafe {
        unsafe { unsf() }
    }
}
```
```
warning: unnecessary `unsafe` block
  --> src/main.rs:10:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default
```

vs

```rs
fn nested() {
    let _ = || unsafe {
        let _ = || unsafe { unsf() };
    };
}
```
```
warning: unnecessary `unsafe` block
 --> src/main.rs:9:16
  |
9 |     let _ = || unsafe {
  |                ^^^^^^ unnecessary `unsafe` block
  |
  = note: `#[warn(unused_unsafe)]` on by default

warning: unnecessary `unsafe` block
  --> src/main.rs:10:20
   |
10 |         let _ = || unsafe { unsf() };
   |                    ^^^^^^ unnecessary `unsafe` block
```

*note that this warning kind-of suggests that **both** unsafe blocks are redundant*

--------------------------------------------------------------------------------

I also dislike the fact that it always suggests keeping the outermost `unsafe`.
E.g. for
```rs
fn granularity() {
    unsafe {
        unsafe { unsf() }
        unsafe { unsf() }
        unsafe { unsf() }
    }
}
```
I prefer if `rustc` suggests removing the more-course outer-level `unsafe`
instead of the fine-grained inner `unsafe` blocks, which it currently does on nightly:
```
warning: unnecessary `unsafe` block
  --> src/main.rs:10:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

warning: unnecessary `unsafe` block
  --> src/main.rs:11:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsafe { unsf() }
11 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block

warning: unnecessary `unsafe` block
  --> src/main.rs:12:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
...
12 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
```

--------------------------------------------------------------------------------

Needless to say, this PR addresses all these points. For context, as far as my
understanding goes, the main advantage of skipping inner unsafe blocks was that
a test case like
```rs
fn top_level_used() {
    unsafe {
        unsf();
        unsafe { unsf() }
        unsafe { unsf() }
        unsafe { unsf() }
    }
}
```
should generate some warning because there’s redundant nested `unsafe`, however
every single `unsafe` block _does_ contain some statement that uses it. Of course
this PR doesn’t aim change the warnings on this kind of code example, because
the current behavior, warning on all the inner `unsafe` blocks, makes sense in this case.

As mentioned, during MIR building all the unsafe blocks *are* kept now, and usage
is attributed to them. The way to still generate a warning like
```
warning: unnecessary `unsafe` block
  --> src/main.rs:11:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
10 |         unsf();
11 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default

warning: unnecessary `unsafe` block
  --> src/main.rs:12:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
...
12 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block

warning: unnecessary `unsafe` block
  --> src/main.rs:13:9
   |
9  |     unsafe {
   |     ------ because it's nested under this `unsafe` block
...
13 |         unsafe { unsf() }
   |         ^^^^^^ unnecessary `unsafe` block
```

in this case is by emitting a `unused_unsafe` warning for all of the `unsafe`
blocks that are _within a **used** unsafe block_.

The previous code had a little HIR traversal already anyways to collect a set of
all the unsafe blocks (in order to afterwards determine which ones are unused
afterwards). This PR uses such a traversal to do additional things including logic
like _always_ warn for an `unsafe` block that’s inside of another **used**
unsafe block. The traversal is expanded to include nested closures in the same go,
this simplifies a lot of things.

The whole logic around `unsafe_op_in_unsafe_fn` is a little complicated, there’s
some test cases of corner-cases in this PR. (The implementation involves
differentiating between whether a used unsafe block was used exclusively by
operations where `allow(unsafe_op_in_unsafe_fn)` was active.) The main goal was
to make sure that code should compile successfully if all the `unused_unsafe`-warnings
are addressed _simultaneously_ (by removing the respective `unsafe` blocks)
no matter how complicated the patterns of `unsafe_op_in_unsafe_fn` being
disallowed and allowed throughout the function are.

--------------------------------------------------------------------------------

One noteworthy design decision I took here: An `unsafe` block
with `allow(unused_unsafe)` **is considered used** for the purposes of
linting about redundant contained unsafe blocks. So while
```rs

fn granularity() {
    unsafe { //~ ERROR: unnecessary `unsafe` block
        unsafe { unsf() }
        unsafe { unsf() }
        unsafe { unsf() }
    }
}
```
warns for the outer `unsafe` block,
```rs

fn top_level_ignored() {
    #[allow(unused_unsafe)]
    unsafe {
        #[deny(unused_unsafe)]
        {
            unsafe { unsf() } //~ ERROR: unnecessary `unsafe` block
            unsafe { unsf() } //~ ERROR: unnecessary `unsafe` block
            unsafe { unsf() } //~ ERROR: unnecessary `unsafe` block
        }
    }
}
```
warns on the inner ones.
@steffahn
Copy link
Member Author

steffahn commented Feb 20, 2022

Alright, I’ve added the motivation to the commit message.

As you can see, the code is unchanged: https://github.com/rust-lang/rust/compare/99a1aa904aceb120220a46954c5d270290d4b471..8f8689fb31a4ca67b348198a082dcc81acbb89ba, so CI will still pass.

@nagisa
Copy link
Member

nagisa commented Feb 20, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Feb 20, 2022

📌 Commit 8f8689f has been approved by nagisa

@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 20, 2022
@bors
Copy link
Contributor

bors commented Feb 20, 2022

⌛ Testing commit 8f8689f with merge 45e2c28...

@bors
Copy link
Contributor

bors commented Feb 20, 2022

☀️ Test successful - checks-actions
Approved by: nagisa
Pushing 45e2c28 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Feb 20, 2022
@bors bors merged commit 45e2c28 into rust-lang:master Feb 20, 2022
@rustbot rustbot added this to the 1.61.0 milestone Feb 20, 2022
@steffahn steffahn deleted the better_unsafe_diagnostics branch February 21, 2022 00:26
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (45e2c28): comparison url.

Summary: This benchmark run did not return any relevant results. 11 results were found to be statistically significant but too small to be relevant.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

@rustbot label: -perf-regression

@rustbot rustbot removed the perf-regression Performance regression. label Feb 21, 2022
matthewjasper added a commit to matthewjasper/rust that referenced this pull request Oct 25, 2023
Updates THIR behavior to match the changes from rust-lang#93678
matthewjasper added a commit to matthewjasper/rust that referenced this pull request Oct 25, 2023
Updates THIR behavior to match the changes from rust-lang#93678
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Oct 25, 2023
…r=oli-obk

Update THIR unused_unsafe lint

Updates THIR unsafeck behaviour to match the changes from rust-lang#93678
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Oct 25, 2023
Rollup merge of rust-lang#117158 - matthewjasper:thir-unused-unsafe, r=oli-obk

Update THIR unused_unsafe lint

Updates THIR unsafeck behaviour to match the changes from rust-lang#93678
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. 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
8 participants