Introduce `TypeVisitor::BreakTy`
Implements MCP rust-lang/compiler-team#383.
r? `@ghost`
cc `@lcnr` `@oli-obk`
~~Blocked on FCP in rust-lang/compiler-team#383.~~
RFC-2229: Implement Precise Capture Analysis
### This PR introduces
- Feature gate for RFC-2229 (incomplete) `capture_disjoint_field`
- Rustc Attribute to print out the capture analysis `rustc_capture_analysis`
- Precise capture analysis
### Description of the analysis
1. If the feature gate is not set then all variables that are not local to the closure will be added to the list of captures. (This is for backcompat)
2. The rest of the analysis is based entirely on how the captured `Place`s are used within the closure. Precise information (i.e. projections) about the `Place` is maintained throughout.
3. To reduce the amount of information we need to keep track of, we do a minimization step. In this step, we determine a list such that no Place within this list represents an ancestor path to another entry in the list. Check rust-lang/project-rfc-2229#9 for more detailed examples.
4. To keep the compiler functional as before we implement a Bridge between the results of this new analysis to existing data structures used for closure captures. Note the new capture analysis results are only part of MaybeTypeckTables that is the information is only available during typeck-ing.
### Known issues
- Statements like `let _ = x` will make the compiler ICE when used within a closure with the feature enabled. More generally speaking the issue is caused by `let` statements that create no bindings and are init'ed using a Place expression.
### Testing
We removed the code that would handle the case where the feature gate is not set, to enable the feature as default and did a bors try and perf run. More information here: #78762
### Thanks
This has been slowly in the works for a while now.
I want to call out `@Azhng` `@ChrisPardy` `@null-sleep` `@jenniferwills` `@logmosier` `@roxelo` for working on this and the previous PRs that led up to this, `@nikomatsakis` for guiding us.
Closesrust-lang/project-rfc-2229#7Closesrust-lang/project-rfc-2229#9Closesrust-lang/project-rfc-2229#6Closesrust-lang/project-rfc-2229#19
r? `@nikomatsakis`
Allow making `RUSTC_BOOTSTRAP` conditional on the crate name
Motivation: This came up in the [Zulip stream](https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/Require.20users.20to.20confirm.20they.20know.20RUSTC_.E2.80.A6.20compiler-team.23350/near/208403962) for https://github.com/rust-lang/compiler-team/issues/350.
See also https://github.com/rust-lang/cargo/pull/6608#issuecomment-458546258; this implements https://github.com/rust-lang/cargo/issues/6627.
The goal is for this to eventually allow prohibiting setting `RUSTC_BOOTSTRAP` in build.rs (https://github.com/rust-lang/cargo/issues/7088).
## User-facing changes
- `RUSTC_BOOTSTRAP=1` still works; there is no current plan to remove this.
- Things like `RUSTC_BOOTSTRAP=0` no longer activate nightly features. In practice this shouldn't be a big deal, since `RUSTC_BOOTSTRAP` is the opposite of stable and everyone uses `RUSTC_BOOTSTRAP=1` anyway.
- `RUSTC_BOOTSTRAP=x` will enable nightly features only for crate `x`.
- `RUSTC_BOOTSTRAP=x,y` will enable nightly features only for crates `x` and `y`.
## Implementation changes
The main change is that `UnstableOptions::from_environment` now requires
an (optional) crate name. If the crate name is unknown (`None`), then the new feature is not available and you still have to use `RUSTC_BOOTSTRAP=1`. In practice this means the feature is only available for `--crate-name`, not for `#![crate_name]`; I'm interested in supporting the second but I'm not sure how.
Other major changes:
- Added `Session::is_nightly_build()`, which uses the `crate_name` of
the session
- Added `nightly_options::match_is_nightly_build`, a convenience method
for looking up `--crate-name` from CLI arguments.
`Session::is_nightly_build()`should be preferred where possible, since
it will take into account `#![crate_name]` (I think).
- Added `unstable_features` to `rustdoc::RenderOptions`
I'm not sure whether this counts as T-compiler or T-lang; _technically_ RUSTC_BOOTSTRAP is an implementation detail, but it's been used so much it seems like this counts as a language change too.
r? `@joshtriplett`
cc `@Mark-Simulacrum` `@hsivonen`
Normalize function type during validation
During inlining, the callee body is normalized and has types revealed,
but some of locals corresponding to the arguments might come from the
caller body which is not. As a result the caller body does not pass
validation without additional normalization.
Closes#78442.
Lower intrinsics calls: forget, size_of, unreachable, wrapping_*
This allows constant propagation to evaluate `size_of` and `wrapping_*`,
and unreachable propagation to propagate a call to `unreachable`.
The lowering is performed as a MIR optimization, rather than during MIR
building to preserve the special status of intrinsics with respect to
unsafety checks and promotion.
Currently enabled by default to determine the performance impact (no
significant impact expected). In practice only useful when combined with
inlining since intrinsics are rarely used directly (with exception of
`unreachable` and `discriminant_value` used by built-in derive macros).
Closes#32716.
This allows constant propagation to evaluate `size_of` and `wrapping_*`,
and unreachable propagation to propagate a call to `unreachable`.
The lowering is performed as a MIR optimization, rather than during MIR
building to preserve the special status of intrinsics with respect to
unsafety checks and promotion.
During inlining, the callee body is normalized and has types revealed,
but some of locals corresponding to the arguments might come from the
caller body which is not. As a result the caller body does not pass
validation without additional normalization.
The inliner looks if a sanitizer is enabled before considering
`no_sanitize` attribute as possible source of incompatibility.
The MIR inlining could happen in a crate with sanitizer disabled, but
code generation in a crate with sanitizer enabled, thus the attribute
would be incorrectly ignored.
To avoid the issue never inline functions with different `no_sanitize`
attributes.
Support inlining diverging function calls
The existing heuristic does penalize diverging calls to some degree, but since
it never inlined them previously it might need some further modifications.
Additionally introduce storage markers for all temporaries created by
the inliner. The temporary introduced for destination rebrorrow, didn't
use them previously.
Add flags customizing behaviour of MIR inlining
* `-Zinline-mir-threshold` to change the default threshold.
* `-Zinline-mir-hint-threshold` to change the threshold used by
functions with inline hint.
Having those as configurable flags makes it possible to experiment with with
different inlining thresholds and substantially increase test coverage of MIR
inlining when used with increased thresholds (for example, necessary to test
#78844).
The discussion seems to have resolved that this lint is a bit "noisy" in
that applying it in all places would result in a reduction in
readability.
A few of the trivial functions (like `Path::new`) are fine to leave
outside of closures.
The general rule seems to be that anything that is obviously an
allocation (`Box`, `Vec`, `vec![]`) should be in a closure, even if it
is a 0-sized allocation.
Add comments to explain memory usage optimization
Add explanatory comments so that people understand that it's just an optimization and doesn't affect behavior.
rustc_target: Further cleanup use of target options
Follow up to https://github.com/rust-lang/rust/pull/77729.
Implements items 2 and 4 from the list in https://github.com/rust-lang/rust/pull/77729#issue-500228243.
The first commit collapses uses of `target.options.foo` into `target.foo`.
The second commit renames some target options to avoid tautology:
`target.target_endian` -> `target.endian`
`target.target_c_int_width` -> `target.c_int_width`
`target.target_os` -> `target.os`
`target.target_env` -> `target.env`
`target.target_vendor` -> `target.vendor`
`target.target_family` -> `target.os_family`
`target.target_mcount` -> `target.mcount`
r? `@Mark-Simulacrum`
Assert that a return place is not used for indexing during integration
The inliner integrates call destination place with callee return place
by remapping the local and adding extra projections as necessary.
If a call destination place contains any projections (which is already
possible) and a return place is used in an indexing projection (most
likely doesn't happen yet) the end result would be incorrect.
Add an assertion to ensure that potential issue won't go unnoticed in
the presence of more sophisticated copy propagation scheme.
* `-Zinline-mir-threshold` to change the default threshold.
* `-Zinline-mir-hint-threshold` to change the threshold used by
functions with inline hint.
inliner: Break inlining cycles
Keep track of all instances inlined so far. When examining a new call
sites from an inlined body, skip those where callee had been inlined
already to avoid potential inlining cycles.
Fixes#78573.
Improve lifetime name annotations for closures & async functions
* Don't refer to async functions as "generators" in error output
* Where possible, emit annotations pointing exactly at the `&` in the return type of closures (when they have explicit return types) and async functions, like we do for arguments.
Addresses #74072, but I wouldn't call that *closed* until annotations are identical for async and non-async functions.
* Emit a better annotation when the lifetime doesn't appear in the full name type, which currently happens for opaque types like `impl Future`. Addresses #74497, but further improves could probably be made (why *doesn't* it appear in the type as `impl Future + '1`?)
This is included in the same PR because the changes to `give_name_if_anonymous_region_appears_in_output` would introduce ICE otherwise (it would return `None` in cases where it didn't previously, which then gets `unwrap`ped)
gsgdt [https://crates.io/crates/gsgdt] is a crate which provides an
interface for stringly typed graphs. It also provides generation of
graphviz dot format from said graph.
inliner: Use substs_for_mir_body
Changes from 68965 extended the kind of instances that are being
inlined. For some of those, the `instance_mir` returns a MIR body that
is already expressed in terms of the types found in substitution array,
and doesn't need further substitution.
Use `substs_for_mir_body` to take that into account.
Resolves#78529.
Resolves#78560.
Additionally introduce storage markers for all temporaries created by
the inliner. The temporary introduced for destination rebrorrow, didn't
use them previously.
When examining candidates for inlining, reject those that are determined
to be recursive either because of self-recursive calls or calls to any
instances already inlined.
with an eye on merging `TargetOptions` into `Target`.
`TargetOptions` as a separate structure is mostly an implementation detail of `Target` construction, all its fields logically belong to `Target` and available from `Target` through `Deref` impls.
Rollup of 19 pull requests
Successful merges:
- #76097 (Stabilize hint::spin_loop)
- #76227 (Stabilize `Poll::is_ready` and `is_pending` as const)
- #78065 (make concurrency helper more pleasant to read)
- #78570 (Remove FIXME comment in print_type_sizes ui test suite)
- #78572 (Use SOCK_CLOEXEC and accept4() on more platforms.)
- #78658 (Add a tool to run `x.py` from any subdirectory)
- #78706 (Fix run-make tests running when LLVM is disabled)
- #78728 (Constantify `UnsafeCell::into_inner` and related)
- #78775 (Bump Rustfmt and RLS)
- #78788 (Correct unsigned equivalent of isize to be usize)
- #78811 (Make some std::io functions `const`)
- #78828 (use single char patterns for split() (clippy::single_char_pattern))
- #78841 (Small cleanup in `TypeFoldable` derive macro)
- #78842 (Honor the rustfmt setting in config.toml)
- #78843 (Less verbose debug logging from inlining integrator)
- #78852 (Convert a bunch of intra-doc links)
- #78860 (rustc_resolve: Use `#![feature(format_args_capture)]`)
- #78861 (typo and formatting)
- #78865 (Don't fire `CONST_ITEM_MUTATION` lint when borrowing a deref)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Don't fire `CONST_ITEM_MUTATION` lint when borrowing a deref
Fixes#78819
This extends the check for dereferences added in PR #77324
to cover mutable borrows, as well as direct writes. If we're operating
on a dereference of a `const` item, we shouldn't be firing the lint.
Less verbose debug logging from inlining integrator
The inlining integrator produces relatively verbose and uninteresting
logs. Move them from a debug log level to a trace level, so that they
can be easily isolated from others.
revert #75443, update mir validator
This PR reverts rust-lang#75443 to fix rust-lang#75992 and instead uses rust-lang#75419 to fix rust-lang#75313.
Adapts rust-lang#75419 to correctly deal with unevaluated constants as otherwise some `feature(const_evaluatable_checked)` tests would ICE.
Note that rust-lang#72793 was also fixed by rust-lang#75443, but as that issue only concerns `feature(type_alias_impl_trait)` I deleted that test case for now and would reopen that issue.
rust-lang#75443 may have also allowed some other code to now successfully compile which would make this revert a breaking change after 2 stable versions, but I hope that this is a purely theoretical concern.
See https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/generator.20upvars/near/214617274 for more reasoning about this.
r? `@nikomatsakis` `@eddyb` `@RalfJung`
Fixes#78819
This extends the check for dereferences added in PR #77324
to cover mutable borrows, as well as direct writes. If we're operating
on a dereference of a `const` item, we shouldn't be firing the lint.
The inlining integrator produces relatively verbose and uninteresting
logs. Move them from a debug log level to a trace level, so that they
can be easily isolated from others.
The main change is that `UnstableOptions::from_environment` now requires
an (optional) crate name. If the crate name is unknown (`None`), then the new feature is not available and you still have to use `RUSTC_BOOTSTRAP=1`. In practice this means the feature is only available for `--crate-name`, not for `#![crate_name]`; I'm interested in supporting the second but I'm not sure how.
Other major changes:
- Added `Session::is_nightly_build()`, which uses the `crate_name` of
the session
- Added `nightly_options::match_is_nightly_build`, a convenience method
for looking up `--crate-name` from CLI arguments.
`Session::is_nightly_build()`should be preferred where possible, since
it will take into account `#![crate_name]` (I think).
- Added `unstable_features` to `rustdoc::RenderOptions`
There is a user-facing change here: things like `RUSTC_BOOTSTRAP=0` no
longer active nightly features. In practice this shouldn't be a big
deal, since `RUSTC_BOOTSTRAP` is the opposite of stable and everyone
uses `RUSTC_BOOTSTRAP=1` anyway.
- Add tests
Check against `Cheat`, not whether nightly features are allowed.
Nightly features are always allowed on the nightly channel.
- Only call `is_nightly_build()` once within a function
- Use booleans consistently for rustc_incremental
Sessions can't be passed through threads, so `read_file` couldn't take a
session. To be consistent, also take a boolean in `write_file_header`.
The inliner integrates call destination place with callee return place
by remapping the local and adding extra projections as necessary.
If a call destination place contains any projections (which is already
possible) and a return place is used in an indexing projection (most
likely doesn't happen yet) the end result would be incorrect.
Add an assertion to ensure that potential issue won't go unnoticed in
the presence of more sophisticated copy propagation scheme.
inliner: Copy unevaluated constants only after successful inlining
Inliner copies the unevaluated constants from the callee body to the
caller at the point where decision to inline is yet to be made. The
constants will be unnecessary if inlining were to fail.
Organize the code moving items from callee to the caller together in one
place to avoid the issue.
Working expression optimization, and some improvements to branch-level source coverage
This replaces PR #78040 after reorganizing the original commits (by request) into a more logical sequence of major changes.
Most of the work is in the MIR `transform/coverage/` directory (originally, `transform/instrument_coverage.rs`).
Note this PR includes some significant additional debugging capabilities, to help myself and any future developer working on coverage improvements or issues.
In particular, there's a new Graphviz (.dot file) output for the coverage graph (the `BasicCoverageBlock` control flow graph) that provides ways to get some very good insight into the relationships between the MIR, the coverage graph BCBs, coverage spans, and counters. (There are also some cool debugging options, available via environment variable, to alter how some data in the graph appears.)
And the code for this Graphviz view is actually generic... it can be used by any implementation of the Rust `Graph` traits.
Finally (for now), I also now output information from `llvm-cov` that shows the actual counters and spans it found in the coverage map, and their counts (from the `--debug` flag). I found this to be enormously helpful in debugging some coverage issues, so I kept it in the test results as well for additional context.
`@tmandry` `@wesleywiser`
r? `@tmandry`
Here's an example of the new coverage graph:
* Within each `BasicCoverageBlock` (BCB), you can see each `CoverageSpan` and its contributing statements (MIR `Statement`s and/or `Terminator`s)
* Each `CoverageSpan` has a `Counter` or and `Expression`, and `Expression`s show their Add/Subtract operation with nested operations. (This can be changed to show the Counter and Expression IDs instead, or in addition to, the BCB.)
* The terminators of all MIR `BasicBlock`s in the BCB, including one final `Terminator`
* If an "edge counter" is required (because we need to count an edge between blocks, in some cases) the edge's Counter or Expression is shown next to its label. (Not shown in the example below.) (FYI, Edge Counters are converted into a new MIR `BasicBlock` with `Goto`)
<img width="1116" alt="Screen Shot 2020-10-17 at 12 23 29 AM" src="https://user-images.githubusercontent.com/3827298/96331095-616cb480-100f-11eb-8212-60f2d433e2d8.png">
r? `@tmandry`
FYI: `@wesleywiser`
Implementing the Graph traits for the BasicCoverageBlock
graph.
optimized replacement of counters with expressions plus new BCB graphviz
* Avoid adding coverage to unreachable blocks.
* Special case for Goto at the end of the body. Make it non-reportable.
Improved debugging and formatting options (from env)
Don't automatically add counters to BCBs without CoverageSpans. They may
still get counters but only if there are dependencies from
other BCBs that have spans, I think.
Make CodeRegions optional for Counters too. It is
possible to inject counters (`llvm.instrprof.increment` intrinsic calls
without corresponding code regions in the coverage map. An expression
can still uses these counter values.
Refactored instrument_coverage.rs -> instrument_coverage/mod.rs, and
then broke up the mod into multiple files.
Compiling with coverage, with the expression optimization, works on
the json5format crate and its dependencies.
Refactored debug features from mod.rs to debug.rs
Changes from 68965 extended the kind of instances that are being
inlined. For some of those, the `instance_mir` returns a MIR body that
is already expressed in terms of the types found in substitution array,
and doesn't need further substitution.
Use `substs_for_mir_body` to take that into account.
Inliner copies the unevaluated constants from the callee body to the
caller at the point where decision to inline is yet to be made. The
constants will be unnecessary if inlining were to fail.
Organize the code moving items from callee to the caller together in one
place to avoid the issue.
Corrected suggestion for generic parameters in `function_item_references` lint
This commit handles functions with generic type parameters like you pointed out as well as const generics. Also this is probably a minor thing, but the type alias you used in the example doesn't show up so the suggestion right now would be `size_of::<[u8; 16]> as fn() ->`. This is because the lint checker works with MIR instead of HIR. I don't think we can get the alias at that point, but let me know if I'm wrong and there's a way to fix this. Also I put you as the reviewer, but I'm not sure if you want to review it or if it makes more sense to ask one of the original reviewers of this lint.
closes#78571
Properly handle lint spans after MIR inlining
The first commit shows what happens when we apply mir inlining and then cause lints on the inlined MIR.
The second commit fixes that.
r? `@wesleywiser`
Retagging: do not retag 'raw reborrows'
When doing `&raw const (*raw_ptr).field`, we do not want any retagging; the original provenance should be fully preserved.
Fixes https://github.com/rust-lang/miri/issues/1608
Test added by https://github.com/rust-lang/miri/pull/1614
Not sure whom to ask for review on this... `@oli-obk` can you have a look? Or maybe highfive makes a good choice.^^
This lint was incorrectly suggesting casting a function to a pointer without
specifying generic type parameters or const generics. This would cause a
compiler error since the missing parameters couldn't be inferred. This commit
fixed the suggestion and added a few tests with generics.
Add option to customize the nll-facts' folder location
This PR adds a `nll-facts-dir` option to specify the location of the directory in which NLL facts are dumped into. It works the same way `dump-mir-dir` controls the location used by the `dump-mir` option.
The validator in visit_local asserts that local has a stroage when used,
but visit_local is never called so validation is ineffective.
Use super_statement and super_terminator to ensure that locals are visited.
Move "mutable thing in const" check from interning to validity
This moves the check for mutable things (such as `UnsafeCell` or `&mut`) in a`const` from interning to validity. That means we can give more targeted error messages (pointing out *where* the problem lies), and we can simplify interning a bit.
Also fix the interning mode used for promoteds in statics.
r? @oli-obk
Separate unsized locals
Closes#71694
Takes over again #72029 and #74971
cc @RalfJung @oli-obk @pnkfelix @eddyb as they've participated in previous reviews of this PR.
When a function argument bound by `Pointer` is an associated type, we only
perform substitutions using the parameters from the callsite but don't attempt
to normalize since it may not succeed. A simplified version of the scenario that
triggered this error was added as a test case. Also fixed `Pointer::fmt` which
was being double-counted when called outside of macros and added a test case for
this.
Removed test for the unhandled case of calls to `fn f<T>(x: &T)` where `x` is a
function reference and is formatted as a pointer in `f`. This compiles since
`&T` implements `Pointer`, but is unlikely to occur in practice. Also tweaked
the lint's wording and modified tests accordingly.
The lint checks arguments in calls to `transmute` or functions that have
`Pointer` as a trait bound and displays a warning if the argument is a function
reference. Also checks for `std::fmt::Pointer::fmt` to handle formatting macros
although it doesn't depend on the exact expansion of the macro or formatting
internals. `std::fmt::Pointer` and `std::fmt::Pointer::fmt` were also added as
diagnostic items and symbols.
Working with MIR let's us exclude expressions like `&fn_name as &dyn Something`
and `(&fn_name)()`. Also added ABI, unsafety and whether a function is variadic
in the lint suggestion, included the `&` in the span of the lint and updated the
test.
Remove unused set-discriminant statements and assignments regardless of rvalue
* Represent use counts with u32
* Unify use count visitors
* Change RemoveStatements visitor into a function
* Remove unused set-discriminant statements
* Use exhaustive match to clarify what is being optimized
* Remove unused assignments regardless of rvalue kind
rustc_mir: track inlined callees in SourceScopeData.
We now record which MIR scopes are the roots of *other* (inlined) functions's scope trees, which allows us to generate the correct debuginfo in codegen, similar to what LLVM inlining generates.
This PR makes the `ui` test `backtrace-debuginfo` pass, if the MIR inliner is turned on by default.
Also, `#[track_caller]` is now correct in the face of MIR inlining (cc `@anp).`
Fixes#76997.
r? `@rust-lang/wg-mir-opt`
Update affected ui & incremental tests to use a user declared variable
bindings instead of temporaries. The former are preserved because of
debuginfo, the latter are not.
The simplify locals implementation uses two different visitors to update
the locals use counts. The DeclMarker calculates the initial use counts.
The StatementDeclMarker updates the use counts as statements are being
removed from the block.
Replace them with a single visitor that can operate in either mode,
ensuring consistency of behaviour.
Additionally use exhaustive match to clarify what is being optimized.
No functional changes intended.