2020-01-05 15:46:44 +00:00
|
|
|
//! Values computed by queries that use MIR.
|
|
|
|
|
2023-09-13 12:15:40 +10:00
|
|
|
use crate::mir;
|
2022-05-25 23:32:27 +02:00
|
|
|
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
|
2023-03-17 20:48:34 +00:00
|
|
|
use rustc_data_structures::fx::FxIndexMap;
|
2023-02-21 15:21:57 +01:00
|
|
|
use rustc_data_structures::unord::UnordSet;
|
2022-01-23 12:34:26 -06:00
|
|
|
use rustc_errors::ErrorGuaranteed;
|
2020-01-05 15:46:44 +00:00
|
|
|
use rustc_hir as hir;
|
2022-05-08 15:53:19 +02:00
|
|
|
use rustc_hir::def_id::LocalDefId;
|
2020-01-05 15:46:44 +00:00
|
|
|
use rustc_index::bit_set::BitMatrix;
|
2023-04-19 10:57:17 +00:00
|
|
|
use rustc_index::{Idx, IndexVec};
|
2023-06-18 08:19:16 +00:00
|
|
|
use rustc_span::symbol::Symbol;
|
2020-07-14 12:12:01 +10:00
|
|
|
use rustc_span::Span;
|
2023-03-28 12:32:57 -07:00
|
|
|
use rustc_target::abi::{FieldIdx, VariantIdx};
|
2020-01-05 15:46:44 +00:00
|
|
|
use smallvec::SmallVec;
|
2020-06-19 20:19:19 -07:00
|
|
|
use std::cell::Cell;
|
|
|
|
use std::fmt::{self, Debug};
|
2020-01-05 15:46:44 +00:00
|
|
|
|
2023-09-16 09:36:22 +02:00
|
|
|
use super::{ConstValue, SourceInfo};
|
2020-01-05 15:46:44 +00:00
|
|
|
|
2021-01-03 09:19:16 -05:00
|
|
|
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub enum UnsafetyViolationKind {
|
2021-04-25 18:41:14 +02:00
|
|
|
/// Unsafe operation outside `unsafe`.
|
2020-01-05 15:46:44 +00:00
|
|
|
General,
|
2020-05-03 23:11:34 +02:00
|
|
|
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
|
|
|
|
/// Has to be handled as a lint for backwards compatibility.
|
2020-05-13 23:43:21 +02:00
|
|
|
UnsafeFn,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
2023-11-26 19:55:01 +01:00
|
|
|
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
2020-07-14 12:12:01 +10:00
|
|
|
pub enum UnsafetyViolationDetails {
|
2022-04-26 10:43:00 +00:00
|
|
|
CallToUnsafeFunction,
|
2020-07-14 12:12:01 +10:00
|
|
|
UseOfInlineAssembly,
|
|
|
|
InitializingTypeWith,
|
|
|
|
CastOfPointerToInt,
|
|
|
|
UseOfMutableStatic,
|
|
|
|
UseOfExternStatic,
|
|
|
|
DerefOfRawPointer,
|
|
|
|
AccessToUnionField,
|
|
|
|
MutationOfLayoutConstrainedField,
|
|
|
|
BorrowOfLayoutConstrainedField,
|
2023-11-26 19:55:01 +01:00
|
|
|
CallToFunctionWith {
|
|
|
|
/// Target features enabled in callee's `#[target_feature]` but missing in
|
|
|
|
/// caller's `#[target_feature]`.
|
|
|
|
missing: Vec<Symbol>,
|
|
|
|
/// Target features in `missing` that are enabled at compile time
|
|
|
|
/// (e.g., with `-C target-feature`).
|
|
|
|
build_enabled: Vec<Symbol>,
|
|
|
|
},
|
2020-07-14 12:12:01 +10:00
|
|
|
}
|
|
|
|
|
2023-11-26 19:55:01 +01:00
|
|
|
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub struct UnsafetyViolation {
|
|
|
|
pub source_info: SourceInfo,
|
2020-05-13 23:43:21 +02:00
|
|
|
pub lint_root: hir::HirId,
|
2020-01-05 15:46:44 +00:00
|
|
|
pub kind: UnsafetyViolationKind,
|
2020-07-14 12:12:01 +10:00
|
|
|
pub details: UnsafetyViolationDetails,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
Improve `unused_unsafe` lint
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.
2022-02-03 22:16:06 +01:00
|
|
|
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
|
|
|
|
pub enum UnusedUnsafe {
|
|
|
|
/// `unsafe` block contains no unsafe operations
|
|
|
|
/// > ``unnecessary `unsafe` block``
|
|
|
|
Unused,
|
|
|
|
/// `unsafe` block nested under another (used) `unsafe` block
|
|
|
|
/// > ``… because it's nested under this `unsafe` block``
|
|
|
|
InUnsafeBlock(hir::HirId),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub struct UnsafetyCheckResult {
|
|
|
|
/// Violations that are propagated *upwards* from this function.
|
Improve `unused_unsafe` lint
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.
2022-02-03 22:16:06 +01:00
|
|
|
pub violations: Vec<UnsafetyViolation>,
|
|
|
|
|
|
|
|
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
|
2023-02-21 15:21:57 +01:00
|
|
|
pub used_unsafe_blocks: UnordSet<hir::HirId>,
|
Improve `unused_unsafe` lint
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.
2022-02-03 22:16:06 +01:00
|
|
|
|
|
|
|
/// This is `Some` iff the item is not a closure.
|
|
|
|
pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rustc_index::newtype_index! {
|
2022-12-18 20:53:08 +01:00
|
|
|
#[derive(HashStable)]
|
2023-11-21 16:35:26 +11:00
|
|
|
#[encodable]
|
2022-12-18 21:37:38 +01:00
|
|
|
#[debug_format = "_{}"]
|
2023-10-19 16:06:43 +00:00
|
|
|
pub struct CoroutineSavedLocal {}
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
2024-02-15 01:07:20 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2023-10-19 16:06:43 +00:00
|
|
|
pub struct CoroutineSavedTy<'tcx> {
|
2022-09-11 17:24:53 +02:00
|
|
|
pub ty: Ty<'tcx>,
|
|
|
|
/// Source info corresponding to the local in the original MIR body.
|
|
|
|
pub source_info: SourceInfo,
|
2023-01-21 10:03:12 +00:00
|
|
|
/// Whether the local should be ignored for trait bound computations.
|
|
|
|
pub ignore_for_traits: bool,
|
2022-09-11 17:24:53 +02:00
|
|
|
}
|
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
/// The layout of coroutine state.
|
2024-02-15 01:07:20 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq)]
|
|
|
|
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2023-10-19 16:06:43 +00:00
|
|
|
pub struct CoroutineLayout<'tcx> {
|
2023-10-19 21:46:28 +00:00
|
|
|
/// The type of every local stored inside the coroutine.
|
2023-10-19 16:06:43 +00:00
|
|
|
pub field_tys: IndexVec<CoroutineSavedLocal, CoroutineSavedTy<'tcx>>,
|
2020-01-05 15:46:44 +00:00
|
|
|
|
2023-06-18 08:19:16 +00:00
|
|
|
/// The name for debuginfo.
|
2023-10-19 16:06:43 +00:00
|
|
|
pub field_names: IndexVec<CoroutineSavedLocal, Option<Symbol>>,
|
2023-06-18 08:19:16 +00:00
|
|
|
|
2020-01-05 15:46:44 +00:00
|
|
|
/// Which of the above fields are in each variant. Note that one field may
|
|
|
|
/// be stored in multiple variants.
|
2023-10-19 16:06:43 +00:00
|
|
|
pub variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>>,
|
2020-01-05 15:46:44 +00:00
|
|
|
|
2020-06-17 16:04:25 -07:00
|
|
|
/// The source that led to each variant being created (usually, a yield or
|
|
|
|
/// await).
|
|
|
|
pub variant_source_info: IndexVec<VariantIdx, SourceInfo>,
|
|
|
|
|
2020-01-05 15:46:44 +00:00
|
|
|
/// Which saved locals are storage-live at the same time. Locals that do not
|
|
|
|
/// have conflicts with each other are allowed to overlap in the computed
|
|
|
|
/// layout.
|
2023-02-14 00:01:37 +00:00
|
|
|
#[type_foldable(identity)]
|
|
|
|
#[type_visitable(ignore)]
|
2023-10-19 16:06:43 +00:00
|
|
|
pub storage_conflicts: BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal>,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
2023-10-19 16:06:43 +00:00
|
|
|
impl Debug for CoroutineLayout<'_> {
|
2020-06-19 20:19:19 -07:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
/// Prints an iterator of (key, value) tuples as a map.
|
|
|
|
struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
|
|
|
|
impl<'a, K, V> MapPrinter<'a, K, V> {
|
|
|
|
fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
|
|
|
|
Self(Cell::new(Some(Box::new(iter))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
fmt.debug_map().entries(self.0.take().unwrap()).finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
/// Prints the coroutine variant name.
|
2020-06-19 20:19:19 -07:00
|
|
|
struct GenVariantPrinter(VariantIdx);
|
|
|
|
impl From<VariantIdx> for GenVariantPrinter {
|
|
|
|
fn from(idx: VariantIdx) -> Self {
|
|
|
|
GenVariantPrinter(idx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Debug for GenVariantPrinter {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2023-10-19 16:06:43 +00:00
|
|
|
let variant_name = ty::CoroutineArgs::variant_name(self.0);
|
2020-06-19 20:19:19 -07:00
|
|
|
if fmt.alternate() {
|
|
|
|
write!(fmt, "{:9}({:?})", variant_name, self.0)
|
|
|
|
} else {
|
2023-07-25 22:00:13 +02:00
|
|
|
write!(fmt, "{variant_name}")
|
2020-06-19 20:19:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Forces its contents to print in regular mode instead of alternate mode.
|
|
|
|
struct OneLinePrinter<T>(T);
|
|
|
|
impl<T: Debug> Debug for OneLinePrinter<T> {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-19 16:06:43 +00:00
|
|
|
fmt.debug_struct("CoroutineLayout")
|
2020-06-19 20:19:19 -07:00
|
|
|
.field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
|
|
|
|
.field(
|
|
|
|
"variant_fields",
|
|
|
|
&MapPrinter::new(
|
|
|
|
self.variant_fields
|
|
|
|
.iter_enumerated()
|
|
|
|
.map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.field("storage_conflicts", &self.storage_conflicts)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Debug, TyEncodable, TyDecodable, HashStable)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub struct BorrowCheckResult<'tcx> {
|
2019-12-25 09:50:07 +00:00
|
|
|
/// All the opaque types that are restricted to concrete types
|
2020-07-17 08:47:04 +00:00
|
|
|
/// by this function. Unlike the value in `TypeckResults`, this has
|
2019-12-25 09:50:07 +00:00
|
|
|
/// unerased regions.
|
2023-03-17 20:48:34 +00:00
|
|
|
pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
2020-01-05 15:46:44 +00:00
|
|
|
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
|
2023-03-28 12:32:57 -07:00
|
|
|
pub used_mut_upvars: SmallVec<[FieldIdx; 8]>,
|
2022-01-23 12:34:26 -06:00
|
|
|
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The result of the `mir_const_qualif` query.
|
|
|
|
///
|
2024-01-27 13:47:29 +01:00
|
|
|
/// Each field (except `tainted_by_errors`) corresponds to an implementer of the `Qualif` trait in
|
2021-01-05 20:08:11 +01:00
|
|
|
/// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each
|
2020-01-05 15:46:44 +00:00
|
|
|
/// `Qualif`.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub struct ConstQualifs {
|
|
|
|
pub has_mut_interior: bool,
|
2021-10-17 00:00:00 +00:00
|
|
|
pub needs_drop: bool,
|
2021-10-17 00:00:00 +00:00
|
|
|
pub needs_non_const_drop: bool,
|
2022-01-23 12:34:26 -06:00
|
|
|
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// After we borrow check a closure, we are left with various
|
|
|
|
/// requirements that we have inferred between the free regions that
|
|
|
|
/// appear in the closure's signature or on its field types. These
|
|
|
|
/// requirements are then verified and proved by the closure's
|
|
|
|
/// creating function. This struct encodes those requirements.
|
|
|
|
///
|
2020-03-11 22:24:20 +00:00
|
|
|
/// The requirements are listed as being between various `RegionVid`. The 0th
|
|
|
|
/// region refers to `'static`; subsequent region vids refer to the free
|
2023-10-19 21:46:28 +00:00
|
|
|
/// regions that appear in the closure (or coroutine's) type, in order of
|
2020-03-11 22:24:20 +00:00
|
|
|
/// appearance. (This numbering is actually defined by the `UniversalRegions`
|
|
|
|
/// struct in the NLL region checker. See for example
|
|
|
|
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
|
|
|
|
/// closure's signature and captures are erased.
|
2020-01-05 15:46:44 +00:00
|
|
|
///
|
2023-07-11 22:35:29 +01:00
|
|
|
/// Example: If type check produces a closure with the closure args:
|
2020-01-05 15:46:44 +00:00
|
|
|
///
|
|
|
|
/// ```text
|
2023-07-11 22:35:29 +01:00
|
|
|
/// ClosureArgs = [
|
2020-03-11 22:24:20 +00:00
|
|
|
/// 'a, // From the parent.
|
|
|
|
/// 'b,
|
|
|
|
/// i8, // the "closure kind"
|
|
|
|
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
|
|
|
|
/// &'<erased> String, // some upvar
|
2020-01-05 15:46:44 +00:00
|
|
|
/// ]
|
|
|
|
/// ```
|
|
|
|
///
|
2020-03-11 22:24:20 +00:00
|
|
|
/// We would "renumber" each free region to a unique vid, as follows:
|
2020-01-05 15:46:44 +00:00
|
|
|
///
|
|
|
|
/// ```text
|
2023-07-11 22:35:29 +01:00
|
|
|
/// ClosureArgs = [
|
2020-03-11 22:24:20 +00:00
|
|
|
/// '1, // From the parent.
|
|
|
|
/// '2,
|
|
|
|
/// i8, // the "closure kind"
|
|
|
|
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
|
|
|
|
/// &'4 String, // some upvar
|
2020-01-05 15:46:44 +00:00
|
|
|
/// ]
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Now the code might impose a requirement like `'1: '2`. When an
|
|
|
|
/// instance of the closure is created, the corresponding free regions
|
|
|
|
/// can be extracted from its type and constrained to have the given
|
|
|
|
/// outlives relationship.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub struct ClosureRegionRequirements<'tcx> {
|
|
|
|
/// The number of external regions defined on the closure. In our
|
|
|
|
/// example above, it would be 3 -- one for `'static`, then `'1`
|
|
|
|
/// and `'2`. This is just used for a sanity check later on, to
|
|
|
|
/// make sure that the number of regions we see at the callsite
|
|
|
|
/// matches.
|
|
|
|
pub num_external_vids: usize,
|
|
|
|
|
|
|
|
/// Requirements between the various free regions defined in
|
|
|
|
/// indices.
|
|
|
|
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Indicates an outlives-constraint between a type or between two
|
|
|
|
/// free regions declared on the closure.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub struct ClosureOutlivesRequirement<'tcx> {
|
|
|
|
// This region or type ...
|
|
|
|
pub subject: ClosureOutlivesSubject<'tcx>,
|
|
|
|
|
|
|
|
// ... must outlive this one.
|
|
|
|
pub outlived_free_region: ty::RegionVid,
|
|
|
|
|
|
|
|
// If not, report an error here ...
|
|
|
|
pub blame_span: Span,
|
|
|
|
|
|
|
|
// ... due to this reason.
|
2022-10-27 16:15:11 +00:00
|
|
|
pub category: ConstraintCategory<'tcx>,
|
2020-01-05 15:46:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 23:32:27 +02:00
|
|
|
// Make sure this enum doesn't unintentionally grow
|
|
|
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
2022-10-27 16:15:11 +00:00
|
|
|
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
2022-05-25 23:32:27 +02:00
|
|
|
|
2020-01-05 15:46:44 +00:00
|
|
|
/// Outlives-constraints can be categorized to determine whether and why they
|
|
|
|
/// are interesting (for error reporting). Order of variants indicates sort
|
|
|
|
/// order of the category, thereby influencing diagnostic output.
|
|
|
|
///
|
2021-01-05 20:08:11 +01:00
|
|
|
/// See also `rustc_const_eval::borrow_check::constraints`.
|
2020-01-05 15:46:44 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
2023-09-14 09:46:18 +10:00
|
|
|
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
|
2022-10-27 16:15:11 +00:00
|
|
|
pub enum ConstraintCategory<'tcx> {
|
2020-05-23 21:40:55 -04:00
|
|
|
Return(ReturnConstraint),
|
2020-01-05 15:46:44 +00:00
|
|
|
Yield,
|
|
|
|
UseAsConst,
|
|
|
|
UseAsStatic,
|
|
|
|
TypeAnnotation,
|
2023-11-12 13:48:47 +01:00
|
|
|
Cast {
|
|
|
|
/// Whether this is an unsizing cast and if yes, this contains the target type.
|
|
|
|
/// Region variables are erased to ReErased.
|
|
|
|
unsize_to: Option<Ty<'tcx>>,
|
|
|
|
},
|
2020-01-05 15:46:44 +00:00
|
|
|
|
|
|
|
/// A constraint that came from checking the body of a closure.
|
|
|
|
///
|
|
|
|
/// We try to get the category that the closure used when reporting this.
|
|
|
|
ClosureBounds,
|
2022-05-25 23:32:27 +02:00
|
|
|
|
|
|
|
/// Contains the function type if available.
|
2022-10-27 16:15:11 +00:00
|
|
|
CallArgument(Option<Ty<'tcx>>),
|
2020-01-05 15:46:44 +00:00
|
|
|
CopyBound,
|
|
|
|
SizedBound,
|
|
|
|
Assignment,
|
2021-09-06 16:59:24 -05:00
|
|
|
/// A constraint that came from a usage of a variable (e.g. in an ADT expression
|
|
|
|
/// like `Foo { field: my_val }`)
|
|
|
|
Usage,
|
2020-01-05 15:46:44 +00:00
|
|
|
OpaqueType,
|
2023-03-28 12:32:57 -07:00
|
|
|
ClosureUpvar(FieldIdx),
|
2020-01-05 15:46:44 +00:00
|
|
|
|
2021-08-28 18:45:37 -05:00
|
|
|
/// A constraint from a user-written predicate
|
|
|
|
/// with the provided span, written on the item
|
|
|
|
/// with the given `DefId`
|
2021-09-27 10:45:34 -05:00
|
|
|
Predicate(Span),
|
2021-08-28 18:45:37 -05:00
|
|
|
|
2020-01-05 15:46:44 +00:00
|
|
|
/// A "boring" constraint (caused by the given location) is one that
|
|
|
|
/// the user probably doesn't want to see described in diagnostics,
|
|
|
|
/// because it is kind of an artifact of the type system setup.
|
|
|
|
Boring,
|
|
|
|
// Boring and applicable everywhere.
|
|
|
|
BoringNoLocation,
|
|
|
|
|
|
|
|
/// A constraint that doesn't correspond to anything the user sees.
|
|
|
|
Internal,
|
|
|
|
}
|
|
|
|
|
2020-05-23 21:40:55 -04:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
2022-09-16 16:15:41 -04:00
|
|
|
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
|
2020-05-23 21:40:55 -04:00
|
|
|
pub enum ReturnConstraint {
|
|
|
|
Normal,
|
2023-03-28 12:32:57 -07:00
|
|
|
ClosureUpvar(FieldIdx),
|
2020-05-23 21:40:55 -04:00
|
|
|
}
|
|
|
|
|
2020-01-05 15:46:44 +00:00
|
|
|
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
|
|
|
|
/// that must outlive some region.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
2020-01-05 15:46:44 +00:00
|
|
|
pub enum ClosureOutlivesSubject<'tcx> {
|
|
|
|
/// Subject is a type, typically a type parameter, but could also
|
|
|
|
/// be a projection. Indicates a requirement like `T: 'a` being
|
|
|
|
/// passed to the caller, where the type here is `T`.
|
2023-03-03 03:56:42 +03:00
|
|
|
Ty(ClosureOutlivesSubjectTy<'tcx>),
|
2020-01-05 15:46:44 +00:00
|
|
|
|
|
|
|
/// Subject is a free region from the closure. Indicates a requirement
|
|
|
|
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
|
|
|
Region(ty::RegionVid),
|
|
|
|
}
|
|
|
|
|
2023-03-03 03:56:42 +03:00
|
|
|
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
|
|
|
|
///
|
2023-03-04 11:19:56 +03:00
|
|
|
/// This abstraction is necessary because the type may include `ReVar` regions,
|
|
|
|
/// which is what we use internally within NLL code, and they can't be used in
|
|
|
|
/// a query response.
|
|
|
|
///
|
|
|
|
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
|
|
|
|
/// type is not recognized as a binder for late-bound region.
|
2023-03-03 03:56:42 +03:00
|
|
|
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
|
|
|
pub struct ClosureOutlivesSubjectTy<'tcx> {
|
|
|
|
inner: Ty<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
2023-03-04 11:19:56 +03:00
|
|
|
/// All regions of `ty` must be of kind `ReVar` and must represent
|
|
|
|
/// universal regions *external* to the closure.
|
|
|
|
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
|
2023-03-03 03:56:42 +03:00
|
|
|
let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
|
|
|
|
ty::ReVar(vid) => {
|
2023-08-03 15:56:56 +00:00
|
|
|
let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon };
|
2023-11-13 14:00:05 +00:00
|
|
|
ty::Region::new_bound(tcx, depth, br)
|
2023-03-03 03:56:42 +03:00
|
|
|
}
|
|
|
|
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
|
|
|
|
});
|
|
|
|
|
|
|
|
Self { inner }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn instantiate(
|
|
|
|
self,
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
|
|
|
|
) -> Ty<'tcx> {
|
|
|
|
tcx.fold_regions(self.inner, |r, depth| match r.kind() {
|
2023-11-13 14:00:05 +00:00
|
|
|
ty::ReBound(debruijn, br) => {
|
2023-03-03 03:56:42 +03:00
|
|
|
debug_assert_eq!(debruijn, depth);
|
|
|
|
map(ty::RegionVid::new(br.var.index()))
|
|
|
|
}
|
|
|
|
_ => bug!("unexpected region {r:?}"),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-12 18:14:28 +02:00
|
|
|
/// The constituent parts of a mir constant of kind ADT or array.
|
|
|
|
#[derive(Copy, Clone, Debug, HashStable)]
|
2022-09-19 17:00:38 +02:00
|
|
|
pub struct DestructuredConstant<'tcx> {
|
2022-04-12 18:14:28 +02:00
|
|
|
pub variant: Option<VariantIdx>,
|
2023-06-28 09:34:26 +00:00
|
|
|
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
|
2022-04-12 18:14:28 +02:00
|
|
|
}
|
|
|
|
|
2023-09-13 12:15:40 +10:00
|
|
|
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
|
|
|
|
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
|
|
|
|
/// have had a chance to potentially remove some of them.
|
|
|
|
///
|
|
|
|
/// Used by the `coverage_ids_info` query.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
|
2023-09-13 12:15:40 +10:00
|
|
|
pub struct CoverageIdsInfo {
|
|
|
|
/// Coverage codegen needs to know the highest counter ID that is ever
|
|
|
|
/// incremented within a function, so that it can set the `num-counters`
|
|
|
|
/// argument of the `llvm.instrprof.increment` intrinsic.
|
|
|
|
///
|
|
|
|
/// This may be less than the highest counter ID emitted by the
|
|
|
|
/// InstrumentCoverage MIR pass, if the highest-numbered counter increments
|
|
|
|
/// were removed by MIR optimizations.
|
|
|
|
pub max_counter_id: mir::coverage::CounterId,
|
2020-06-21 23:29:08 -07:00
|
|
|
}
|