Merge from rustc

This commit is contained in:
Ralf Jung 2023-01-15 16:46:17 -05:00
commit b237952297
374 changed files with 4610 additions and 1510 deletions

View file

@ -8,3 +8,5 @@ a06baa56b95674fc626b3c3fd680d6a65357fe60
283abbf0e7d20176f76006825b5c52e9a4234e4c
# format libstd/sys
c34fbfaad38cf5829ef5cfe780dc9d58480adeaa
# move tests
cf2dff2b1e3fa55fa5415d524200070d0d7aacfe

View file

@ -1,46 +0,0 @@
---
name: Diagnostic issue
about: Create a bug report or feature request for a change to `rustc`'s error output
labels: A-diagnostics, T-compiler
---
<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
If you cannot produce a minimal reproduction case (something that would work in
isolation), please provide the steps or even link to a repository that causes
the problematic output to occur.
-->
Given the following code: <!-- Please provide a link to play.rust-lang.org -->
```rust
<code>
```
The current output is:
```
<rustc output>
```
<!-- The following is not always necessary. -->
Ideally the output should look like:
```
<proposed output>
```
<!--
If the problem is not self-explanatory, please provide a rationale for the
change.
-->
<!--
If dramatically different output is caused by small changes, consider also
adding them here.
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions. The output might also be
different depending on the Edition.
-->

65
.github/ISSUE_TEMPLATE/diagnostics.yaml vendored Normal file
View file

@ -0,0 +1,65 @@
name: Diagnostic issue
description: Create a bug report or feature request for a change to `rustc`'s error output
labels: ["A-diagnostics", "T-compiler"]
body:
- type: markdown
attributes:
value: |
Thank you for filing a diagnostics bug report! 🐛
Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug.
If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur.
- type: textarea
id: code
attributes:
label: Code
description: Please provide code that can reproduce the problem
placeholder: code
render: Rust
validations:
required: true
- type: textarea
id: output
attributes:
label: Current output
description: Please provide the `rustc` output you see
placeholder: rustc output
render: Shell
validations:
required: true
- type: textarea
id: desired-output
attributes:
label: Desired output
description: Please provide what the output *should* be
placeholder: proposed output
render: Shell
validations:
required: false
- type: textarea
id: rationale
attributes:
label: Rationale and extra context
description: If the problem is not self-explanatory, please provide a rationale for the change.
validations:
required: false
- type: textarea
id: other-output
attributes:
label: Other cases
description: If dramatically different output is caused by small changes, consider also adding them here.
render: Rust
validations:
required: false
- type: markdown
attributes:
value: |
If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition.
- type: textarea
id: extra
attributes:
label: Anything else?
description: If you have more details you want to give us to reproduce this issue, please add it here
validations:
required: false

View file

@ -1,31 +0,0 @@
---
name: Documentation problem
about: Create a report for a documentation problem.
labels: A-docs
---
<!--
Thank you for finding a documentation problem! 📚
Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
Note: If your issue is for one of these, please use their dedicated issue tracker instead:
- The Rust Book: https://github.com/rust-lang/book/issues
- Rust by Example: https://github.com/rust-lang/rust-by-example/issues
- The Edition Guide: https://github.com/rust-lang/edition-guide/issues
- The Cargo Book: https://github.com/rust-lang/cargo/issues
- The Clippy Book: https://github.com/rust-lang/rust-clippy/issues
- The Reference: https://github.com/rust-lang/reference/issues
- The Rustonomicon: https://github.com/rust-lang/nomicon/issues
- The Embedded Book: https://github.com/rust-embedded/book/issues
All other documentation issues should be filed here.
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
-->
### Location
### Summary

View file

@ -0,0 +1,38 @@
name: Documentation problem
description: Create a report for a documentation problem.
labels: ["A-docs"]
body:
- type: markdown
attributes:
value: |
Thank you for finding a documentation problem! 📚
Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
Note: If your issue is for one of these, please use their dedicated issue tracker instead:
- [The Rust Book](https://github.com/rust-lang/book/issues)
- [Rust by Example](https://github.com/rust-lang/rust-by-example/issues)
- [The Edition Guide](https://github.com/rust-lang/edition-guide/issues)
- [The Cargo Book](https://github.com/rust-lang/cargo/issues)
- [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues)
- [The Reference](https://github.com/rust-lang/reference/issues)
- [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
- [The Embedded Book](https://github.com/rust-embedded/book/issues)
All other documentation issues should be filed here.
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
- type: textarea
id: location
attributes:
label: Location
validations:
required: true
- type: textarea
id: summary
attributes:
label: Summary
validations:
required: true

View file

@ -1,52 +0,0 @@
---
name: Internal Compiler Error
about: Create a report for an internal compiler error in rustc.
labels: C-bug, I-ICE, T-compiler
---
<!--
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
how to create smaller examples.
http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-->
### Code
```Rust
<code>
```
### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->
`rustc --version --verbose`:
```
<version>
```
### Error output
```
<output>
```
<!--
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
-->
<details><summary><strong>Backtrace</strong></summary>
<p>
```
<backtrace>
```
</p>
</details>

82
.github/ISSUE_TEMPLATE/ice.yaml vendored Normal file
View file

@ -0,0 +1,82 @@
name: Internal Compiler Error
description: Create a report for an internal compiler error in `rustc`
labels: ["C-bug", "I-ICE", "T-compiler"]
title: "[ICE]: "
body:
- type: markdown
attributes:
value: |
Thank you for finding an Internal Compiler Error! 🧊
If possible, try to provide a minimal verifiable example.
You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples.
- type: textarea
id: code
attributes:
label: Code
description: Please provide code or a link to a repository that can reproduce the problem
placeholder: code
render: Rust
validations:
required: false
- type: checkboxes
attributes:
label: Affected release channels
description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions
options:
- label: Previous Stable
required: false
- label: Current Stable
required: false
- label: Current Beta
required: false
- label: Current Nightly
required: false
- type: textarea
id: version
attributes:
label: Rust Version
description: Please provide the `rustc` version, `rustc --version --verbose`
placeholder: |
$ rustc --version --verbose
rustc 1.XX.Y (SHORTHASH DATE)
binary: rustc
commit-hash: LONGHASHVALUE
commit-date: DATE
host: PLATFORMTRIPLE
release: 1.XX.Y
LLVM version: XX.YY.ZZ
render: Shell
validations:
required: true
- type: textarea
id: output
attributes:
label: Current error output
description: Please provide the `rustc` output you see
placeholder: output
render: Shell
validations:
required: false
- type: textarea
id: backtrace
attributes:
label: Backtrace
description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build`
render: Shell
validations:
required: true
- type: textarea
id: extra
attributes:
label: Anything else?
description: If you have more details you want to give us to reproduce this issue, please add it here
validations:
required: false

View file

@ -35,6 +35,17 @@ dependencies = [
"version_check",
]
[[package]]
name = "ahash"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -107,7 +118,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
dependencies = [
"object",
"object 0.29.0",
]
[[package]]
@ -193,7 +204,7 @@ dependencies = [
"cfg-if",
"libc",
"miniz_oxide",
"object",
"object 0.29.0",
"rustc-demangle",
]
@ -340,7 +351,7 @@ dependencies = [
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
"clap 4.0.15",
"clap 4.0.32",
"crates-io",
"curl",
"curl-sys",
@ -644,26 +655,27 @@ dependencies = [
[[package]]
name = "clap"
version = "4.0.15"
version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"atty",
"bitflags",
"clap_derive 4.0.13",
"clap_derive 4.0.21",
"clap_lex 0.3.0",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
"terminal_size",
]
[[package]]
name = "clap_complete"
version = "3.1.1"
version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [
"clap 3.2.20",
"clap 4.0.32",
]
[[package]]
@ -681,9 +693,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.0.13"
version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck",
"proc-macro-error",
@ -1773,9 +1785,9 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.26.1"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"compiler_builtins",
"fallible-iterator",
@ -1886,12 +1898,21 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
"ahash 0.7.4",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "hashbrown"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
dependencies = [
"ahash 0.8.2",
]
[[package]]
name = "heck"
version = "0.4.0"
@ -2128,12 +2149,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "indexmap"
version = "1.9.1"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
"hashbrown 0.12.3",
"rustc-rayon",
"serde",
]
@ -2273,7 +2294,7 @@ name = "jsondoclint"
version = "0.1.0"
dependencies = [
"anyhow",
"clap 4.0.15",
"clap 4.0.32",
"fs-err",
"rustdoc-json-types",
"serde",
@ -2529,21 +2550,21 @@ dependencies = [
[[package]]
name = "mdbook"
version = "0.4.21"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9"
checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4"
dependencies = [
"ammonia",
"anyhow",
"chrono",
"clap 3.2.20",
"clap 4.0.32",
"clap_complete",
"elasticlunr-rs",
"env_logger 0.9.0",
"env_logger 0.10.0",
"handlebars 4.3.3",
"lazy_static",
"log",
"memchr",
"once_cell",
"opener",
"pulldown-cmark 0.9.2",
"regex",
@ -2739,15 +2760,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"compiler_builtins",
"crc32fast",
"flate2",
"hashbrown",
"indexmap",
"memchr",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "object"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a"
dependencies = [
"crc32fast",
"flate2",
"hashbrown 0.13.1",
"indexmap",
"memchr",
]
[[package]]
name = "odht"
version = "0.3.1"
@ -3013,9 +3043,9 @@ dependencies = [
[[package]]
name = "pest"
version = "2.3.0"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4"
dependencies = [
"thiserror",
"ucd-trie",
@ -3023,9 +3053,9 @@ dependencies = [
[[package]]
name = "pest_derive"
version = "2.3.0"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603"
dependencies = [
"pest",
"pest_generator",
@ -3033,9 +3063,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.3.0"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7"
dependencies = [
"pest",
"pest_meta",
@ -3046,13 +3076,13 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.3.0"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065"
dependencies = [
"once_cell",
"pest",
"sha-1",
"sha1",
]
[[package]]
@ -3498,7 +3528,7 @@ dependencies = [
name = "rustbook"
version = "0.1.0"
dependencies = [
"clap 3.2.20",
"clap 4.0.32",
"env_logger 0.7.1",
"mdbook",
]
@ -3790,7 +3820,7 @@ dependencies = [
"cstr",
"libc",
"measureme",
"object",
"object 0.30.1",
"rustc-demangle",
"rustc_ast",
"rustc_attr",
@ -3825,7 +3855,7 @@ dependencies = [
"itertools",
"jobserver",
"libc",
"object",
"object 0.30.1",
"pathdiff",
"regex",
"rustc_arena",
@ -4273,6 +4303,7 @@ version = "0.0.0"
dependencies = [
"rustc_span",
"tracing",
"tracing-core",
"tracing-subscriber",
"tracing-tree",
]
@ -4683,7 +4714,7 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"scoped-tls",
"sha-1",
"sha1",
"sha2",
"tracing",
"unicode-width",
@ -5092,17 +5123,6 @@ dependencies = [
"serde",
]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha1"
version = "0.10.5"
@ -5305,11 +5325,11 @@ dependencies = [
"core",
"dlmalloc",
"fortanix-sgx-abi",
"hashbrown",
"hashbrown 0.12.3",
"hermit-abi 0.2.6",
"libc",
"miniz_oxide",
"object",
"object 0.29.0",
"panic_abort",
"panic_unwind",
"profiler_builtins",
@ -5477,6 +5497,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
"windows-sys",
]
[[package]]
name = "termize"
version = "0.1.1"
@ -5528,18 +5558,18 @@ checksum = "ceb05e71730d396f960f8f3901cdb41be2d339b303e9d7d3a07c5ff0536e671b"
[[package]]
name = "thiserror"
version = "1.0.33"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.33"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@ -5548,13 +5578,13 @@ dependencies = [
[[package]]
name = "thorin-dwp"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
checksum = "da8fbf660a019b6bf11ea95762041464aa9099cc293b6a66d77cea5107619671"
dependencies = [
"gimli",
"hashbrown",
"object",
"hashbrown 0.12.3",
"object 0.30.1",
"tracing",
]
@ -5571,6 +5601,7 @@ dependencies = [
name = "tidy"
version = "0.1.0"
dependencies = [
"cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.14.0",
"ignore",
"lazy_static",
@ -5692,9 +5723,9 @@ dependencies = [
[[package]]
name = "topological-sort"
version = "0.1.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
[[package]]
name = "tracing"
@ -5820,9 +5851,9 @@ dependencies = [
[[package]]
name = "ucd-trie"
version = "0.1.3"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "ui_test"
@ -6089,9 +6120,9 @@ checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
[[package]]
name = "version_check"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vte"

View file

@ -1100,7 +1100,7 @@ pub enum FieldsShape {
/// named `inverse_memory_index`.
///
// FIXME(eddyb) build a better abstraction for permutations, if possible.
// FIXME(camlorn) also consider small vector optimization here.
// FIXME(camlorn) also consider small vector optimization here.
memory_index: Vec<u32>,
},
}

View file

@ -416,8 +416,7 @@ fn compute_hir_hash(
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
let sess = tcx.sess;
let krate = tcx.untracked_crate.steal();
let mut resolver = tcx.resolver_for_lowering(()).steal();
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
let mut owners = IndexVec::from_fn_n(

View file

@ -6,6 +6,7 @@ use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::sym;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
@ -29,6 +30,7 @@ use crate::borrowck_errors;
use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
use crate::diagnostics::find_all_local_uses;
use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@ -356,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, body_id),
..
})) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
})) = hir.find(self.mir_hir_id())
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
{
let place = &self.move_data.move_paths[mpi].place;
@ -948,7 +950,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
first_borrow_desc = "immutable ";
self.cannot_reborrow_already_borrowed(
let mut err = self.cannot_reborrow_already_borrowed(
span,
&desc_place,
&msg_place,
@ -958,7 +960,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"immutable",
&msg_borrow,
None,
)
);
self.suggest_binding_for_closure_capture_self(
&mut err,
issued_borrow.borrowed_place,
&issued_spans,
);
err
}
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
@ -1240,6 +1248,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
fn suggest_binding_for_closure_capture_self(
&self,
err: &mut Diagnostic,
borrowed_place: Place<'tcx>,
issued_spans: &UseSpans<'tcx>,
) {
let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
let hir = self.infcx.tcx.hir();
// check whether the borrowed place is capturing `self` by mut reference
let local = borrowed_place.local;
let Some(_) = self
.body
.local_decls
.get(local)
.map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
struct ExpressionFinder<'hir> {
capture_span: Span,
closure_change_spans: Vec<Span>,
closure_arg_span: Option<Span>,
in_closure: bool,
suggest_arg: String,
hir: rustc_middle::hir::map::Map<'hir>,
closure_local_id: Option<hir::HirId>,
closure_call_changes: Vec<(Span, String)>,
}
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
if e.span.contains(self.capture_span) {
if let hir::ExprKind::Closure(&hir::Closure {
movability: None,
body,
fn_arg_span,
fn_decl: hir::FnDecl{ inputs, .. },
..
}) = e.kind &&
let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
self.suggest_arg = "this: &Self".to_string();
if inputs.len() > 0 {
self.suggest_arg.push_str(", ");
}
self.in_closure = true;
self.closure_arg_span = fn_arg_span;
self.visit_expr(body);
self.in_closure = false;
}
}
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
seg.ident.name == kw::SelfLower && self.in_closure {
self.closure_change_spans.push(e.span);
}
}
hir::intravisit::walk_expr(self, e);
}
fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
let Some(init) = local.init
{
if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
movability: None,
..
}), .. } = init &&
init.span.contains(self.capture_span) {
self.closure_local_id = Some(*hir_id);
}
}
hir::intravisit::walk_local(self, local);
}
fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
if let hir::StmtKind::Semi(e) = s.kind &&
let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
let Res::Local(hir_id) = seg.res &&
Some(hir_id) == self.closure_local_id {
let (span, arg_str) = if args.len() > 0 {
(args[0].span.shrink_to_lo(), "self, ".to_string())
} else {
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
(span, "(self)".to_string())
};
self.closure_call_changes.push((span, arg_str));
}
hir::intravisit::walk_stmt(self, s);
}
}
if let Some(hir::Node::ImplItem(
hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
)) = hir.find(self.mir_hir_id()) &&
let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
let mut finder = ExpressionFinder {
capture_span: *capture_kind_span,
closure_change_spans: vec![],
closure_arg_span: None,
in_closure: false,
suggest_arg: String::new(),
closure_local_id: None,
closure_call_changes: vec![],
hir,
};
finder.visit_expr(expr);
if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
return;
}
let mut sugg = vec![];
let sm = self.infcx.tcx.sess.source_map();
if let Some(span) = finder.closure_arg_span {
sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
}
for span in finder.closure_change_spans {
sugg.push((span, "this".to_string()));
}
for (span, suggest) in finder.closure_call_changes {
sugg.push((span, suggest));
}
err.multipart_suggestion_verbose(
"try explicitly pass `&Self` into the Closure as an argument",
sugg,
Applicability::MachineApplicable,
);
}
}
/// Returns the description of the root place for a conflicting borrow and the full
/// descriptions of the places that caused the conflict.
///

View file

@ -1094,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
match local_decl.local_info.as_deref() {

View file

@ -79,7 +79,7 @@ impl<'tcx> RegionErrors<'tcx> {
#[track_caller]
pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
let val = val.into();
self.1.sess.delay_span_bug(DUMMY_SP, "{val:?}");
self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}"));
self.0.push(val);
}
pub fn is_empty(&self) -> bool {

View file

@ -209,7 +209,7 @@ fn place_components_conflict<'tcx>(
match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
// The array length is like additional fields on the
// The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any
// borrowed place (at least in MIR as it is currently.)

View file

@ -235,7 +235,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// # Parameters
///
/// - `def_id`, the `impl Trait` type
/// - `substs`, the substs used to instantiate this opaque type
/// - `substs`, the substs used to instantiate this opaque type
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `opaque_defn.concrete_ty`
#[instrument(level = "debug", skip(self))]

View file

@ -11,7 +11,10 @@ bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
measureme = "10.0.0"
object = { version = "0.29.0", default-features = false, features = ["std", "read"] }
object = { version = "0.30.1", default-features = false, features = [
"std",
"read",
] }
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
rustc-demangle = "0.1.21"

View file

@ -15,7 +15,7 @@ tracing = "0.1"
libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
thorin-dwp = "0.3"
thorin-dwp = "0.4"
pathdiff = "0.2.0"
serde_json = "1.0.59"
snap = "1"
@ -44,6 +44,6 @@ rustc_session = { path = "../rustc_session" }
rustc_const_eval = { path = "../rustc_const_eval" }
[dependencies.object]
version = "0.29.0"
version = "0.30.1"
default-features = false
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]

View file

@ -1231,12 +1231,21 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
sess.emit_fatal(errors::LinkerFileStem);
});
// Remove any version postfix.
let stem = stem
.rsplit_once('-')
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
.unwrap_or(stem);
// GCC can have an optional target prefix.
let flavor = if stem == "emcc" {
LinkerFlavor::EmCc
} else if stem == "gcc"
|| stem.ends_with("-gcc")
|| stem == "g++"
|| stem.ends_with("-g++")
|| stem == "clang"
|| stem.ends_with("-clang")
|| stem == "clang++"
{
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {

View file

@ -100,7 +100,13 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
let architecture = match &sess.target.arch[..] {
"arm" => Architecture::Arm,
"aarch64" => Architecture::Aarch64,
"aarch64" => {
if sess.target.pointer_width == 32 {
Architecture::Aarch64_Ilp32
} else {
Architecture::Aarch64
}
}
"x86" => Architecture::I386,
"s390x" => Architecture::S390x,
"mips" => Architecture::Mips,
@ -165,11 +171,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
e_flags
}
Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
// copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
// that the `+d` target feature represents whether the double
// float abi is enabled.
let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
Architecture::Riscv32 | Architecture::Riscv64 => {
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
let mut e_flags: u32 = 0x0;
let features = &sess.target.options.features;
// Check if compressed is enabled
if features.contains("+c") {
e_flags |= elf::EF_RISCV_RVC;
}
// Select the appropriate floating-point ABI
if features.contains("+d") {
e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
} else if features.contains("+f") {
e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
} else {
e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
}
e_flags
}
_ => 0,

View file

@ -231,6 +231,10 @@ fn run_compiler(
registry: diagnostics_registry(),
};
if !tracing::dispatcher::has_been_set() {
init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
}
match make_input(config.opts.error_format, &matches.free) {
Err(reported) => return Err(reported),
Ok(Some((input, input_file_path))) => {
@ -1300,7 +1304,14 @@ pub fn install_ice_hook() {
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
if let Err(error) = rustc_log::init_rustc_env_logger() {
init_rustc_env_logger_with_backtrace_option(&None);
}
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
/// choose a target module you wish to show backtraces along with its logging.
pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
early_error(ErrorOutputType::default(), &error.to_string());
}
}
@ -1366,7 +1377,6 @@ mod signal_handler {
pub fn main() -> ! {
let start_time = Instant::now();
let start_rss = get_resident_set_size();
init_rustc_env_logger();
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
install_ice_hook();

View file

@ -46,3 +46,14 @@ hir_typeck_add_missing_parentheses_in_range = you must surround the range in par
hir_typeck_op_trait_generic_params =
`{$method_name}` must not have any generic parameters
hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`

View file

@ -41,3 +41,6 @@ interface_rustc_error_unexpected_annotation =
interface_failed_writing_file =
failed to write file {$path}: {$error}"
interface_proc_macro_crate_panic_abort =
building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic

View file

@ -4,6 +4,9 @@
-passes_see_issue =
see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
passes_incorrect_do_not_recommend_location =
`#[do_not_recommend]` can only be placed on trait implementations
passes_outer_crate_level_attr =
crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`

View file

@ -31,11 +31,11 @@ use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::iter;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::rc::Rc;
pub(crate) use rustc_span::hygiene::MacroKind;
@ -1423,8 +1423,10 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
if let [variant] = &*enum_def.variants {
if variant.ident.name == sym::Input {
let filename = sess.source_map().span_to_filename(item.ident.span);
if let FileName::Real(RealFileName::LocalPath(path)) = filename {
if let Some(c) = path
if let FileName::Real(real) = filename {
if let Some(c) = real
.local_path()
.unwrap_or(Path::new(""))
.components()
.flat_map(|c| c.as_os_str().to_str())
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))

View file

@ -27,6 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
@ -510,9 +511,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return tcx.const_error(ty).into();
}
if !infer_args && has_default {
tcx.bound_const_param_default(param.def_id)
.subst(tcx, substs.unwrap())
.into()
tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()
@ -1643,8 +1642,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
fn report_ambiguous_associated_type(
&self,
span: Span,
type_str: &str,
trait_str: &str,
types: &[String],
traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
@ -1655,19 +1654,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.keys()
.any(|full_span| full_span.contains(span))
{
err.span_suggestion(
err.span_suggestion_verbose(
span.shrink_to_lo(),
"you are looking for the module in `std`, not the primitive type",
"std::",
Applicability::MachineApplicable,
);
} else {
err.span_suggestion(
span,
"use fully-qualified syntax",
format!("<{} as {}>::{}", type_str, trait_str, name),
Applicability::HasPlaceholders,
);
match (types, traits) {
([], []) => {
err.span_suggestion_verbose(
span,
&format!(
"if there were a type named `Type` that implements a trait named \
`Trait` with associated type `{name}`, you could use the \
fully-qualified path",
),
format!("<Type as Trait>::{name}"),
Applicability::HasPlaceholders,
);
}
([], [trait_str]) => {
err.span_suggestion_verbose(
span,
&format!(
"if there were a type named `Example` that implemented `{trait_str}`, \
you could use the fully-qualified path",
),
format!("<Example as {trait_str}>::{name}"),
Applicability::HasPlaceholders,
);
}
([], traits) => {
err.span_suggestions(
span,
&format!(
"if there were a type named `Example` that implemented one of the \
traits with associated type `{name}`, you could use the \
fully-qualified path",
),
traits
.iter()
.map(|trait_str| format!("<Example as {trait_str}>::{name}"))
.collect::<Vec<_>>(),
Applicability::HasPlaceholders,
);
}
([type_str], []) => {
err.span_suggestion_verbose(
span,
&format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for `{type_str}`, you could use the fully-qualified path",
),
format!("<{type_str} as Example>::{name}"),
Applicability::HasPlaceholders,
);
}
(types, []) => {
err.span_suggestions(
span,
&format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for one of the types, you could use the fully-qualified \
path",
),
types
.into_iter()
.map(|type_str| format!("<{type_str} as Example>::{name}")),
Applicability::HasPlaceholders,
);
}
(types, traits) => {
let mut suggestions = vec![];
for type_str in types {
for trait_str in traits {
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
}
}
err.span_suggestions(
span,
"use the fully-qualified path",
suggestions,
Applicability::MachineApplicable,
);
}
}
}
err.emit()
}
@ -1994,7 +2066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
|| traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
|| "Self".to_string(),
assoc_ident,
span,
@ -2050,12 +2122,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.emit()
} else if let Err(reported) = qself_ty.error_reported() {
reported
} else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
// `<impl Trait as OtherTrait>::Assoc` makes no sense.
struct_span_err!(
tcx.sess,
tcx.def_span(alias_ty.def_id),
E0667,
"`impl Trait` is not allowed in path parameters"
)
.emit() // Already reported in an earlier stage.
} else {
// Find all the `impl`s that `qself_ty` has for any trait that has the
// associated type, so that we suggest the right one.
let infcx = tcx.infer_ctxt().build();
// We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
// to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
let param_env = ty::ParamEnv::empty();
let traits: Vec<_> = self
.tcx()
.all_traits()
.filter(|trait_def_id| {
// Consider only traits with the associated type
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
.is_accessible_from(self.item_def_id(), tcx)
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id);
trait_ref.map_or(false, |trait_ref| {
let impl_ = trait_ref.subst(
tcx,
infcx.fresh_substs_for_item(span, impl_def_id),
);
infcx
.can_eq(
param_env,
tcx.erase_regions(impl_.self_ty()),
tcx.erase_regions(qself_ty),
)
.is_ok()
})
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
})
.map(|trait_def_id| tcx.def_path_str(trait_def_id))
.collect();
// Don't print `TyErr` to the user.
self.report_ambiguous_associated_type(
span,
&qself_ty.to_string(),
"Trait",
&[qself_ty.to_string()],
&traits,
assoc_ident.name,
)
};
@ -2173,16 +2297,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let is_part_of_self_trait_constraints = def_id == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
"Self"
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
vec!["Self".to_string()]
} else {
"Type"
// Find all the types that have an `impl` for the trait.
tcx.all_impls(trait_def_id)
.filter(|impl_def_id| {
// Consider only accessible traits
tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
})
.filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
.map(|impl_| impl_.subst_identity().self_ty())
// We don't care about blanket impls.
.filter(|self_ty| !self_ty.has_non_region_param())
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
.collect()
};
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
// references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
let reported = self.report_ambiguous_associated_type(
span,
type_name,
&path_str,
&type_names,
&[path_str],
item_segment.ident.name,
);
return tcx.ty_error_with_guaranteed(reported)
@ -3167,7 +3305,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
if self_ty.span.can_be_used_for_suggestions() {
diag.multipart_suggestion_verbose(
label,
sugg,
Applicability::MachineApplicable,
);
}
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();

View file

@ -540,7 +540,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
tcx,
it.span,
it.owner_id.def_id,
impl_trait_ref,
impl_trait_ref.subst_identity(),
&impl_.items,
);
check_on_unimplemented(tcx, it);

View file

@ -2,7 +2,9 @@ use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_errors::{
pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
@ -320,15 +322,6 @@ fn compare_method_predicate_entailment<'tcx>(
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
));
}
let emit_implied_wf_lint = || {
infcx.tcx.struct_span_lint_hir(
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
impl_m_hir_id,
infcx.tcx.def_span(impl_m.def_id),
"impl method assumes more implied bounds than the corresponding trait method",
|lint| lint,
);
};
// Check that all obligations are satisfied by the implementation's
// version.
@ -346,7 +339,7 @@ fn compare_method_predicate_entailment<'tcx>(
)
.map(|()| {
// If the skip-mode was successful, emit a lint.
emit_implied_wf_lint();
emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
});
}
CheckImpliedWfMode::Skip => {
@ -382,8 +375,16 @@ fn compare_method_predicate_entailment<'tcx>(
CheckImpliedWfMode::Skip,
)
.map(|()| {
let bad_args = extract_bad_args_for_implies_lint(
tcx,
&errors,
(trait_m, trait_sig),
// Unnormalized impl sig corresponds to the HIR types written
(impl_m, unnormalized_impl_sig),
impl_m_hir_id,
);
// If the skip-mode was successful, emit a lint.
emit_implied_wf_lint();
emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
});
}
CheckImpliedWfMode::Skip => {
@ -400,6 +401,141 @@ fn compare_method_predicate_entailment<'tcx>(
Ok(())
}
fn extract_bad_args_for_implies_lint<'tcx>(
tcx: TyCtxt<'tcx>,
errors: &[infer::RegionResolutionError<'tcx>],
(trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
(impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
hir_id: hir::HirId,
) -> Vec<(Span, Option<String>)> {
let mut blame_generics = vec![];
for error in errors {
// Look for the subregion origin that contains an input/output type
let origin = match error {
infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
};
// Extract (possible) input/output types from origin
match origin {
infer::SubregionOrigin::Subtype(trace) => {
if let Some((a, b)) = trace.values.ty() {
blame_generics.extend([a, b]);
}
}
infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
_ => {}
}
}
let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
let opt_ret_ty = match fn_decl.output {
hir::FnRetTy::DefaultReturn(_) => None,
hir::FnRetTy::Return(ty) => Some(ty),
};
// Map late-bound regions from trait to impl, so the names are right.
let mapping = std::iter::zip(
tcx.fn_sig(trait_m.def_id).bound_vars(),
tcx.fn_sig(impl_m.def_id).bound_vars(),
)
.filter_map(|(impl_bv, trait_bv)| {
if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
&& let ty::BoundVariableKind::Region(trait_bv) = trait_bv
{
Some((impl_bv, trait_bv))
} else {
None
}
})
.collect();
// For each arg, see if it was in the "blame" of any of the region errors.
// If so, then try to produce a suggestion to replace the argument type with
// one from the trait.
let mut bad_args = vec![];
for (idx, (ty, hir_ty)) in
std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
.enumerate()
{
let expected_ty = trait_sig.inputs_and_output[idx]
.fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
if blame_generics.iter().any(|blame| ty.contains(*blame)) {
let expected_ty_sugg = expected_ty.to_string();
bad_args.push((
hir_ty.span,
// Only suggest something if it actually changed.
(expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
));
}
}
bad_args
}
struct RemapLateBound<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
}
impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReFree(fr) = *r {
self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
bound_region: self
.mapping
.get(&fr.bound_region)
.copied()
.unwrap_or(fr.bound_region),
..fr
}))
} else {
r
}
}
}
fn emit_implied_wf_lint<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
hir_id: hir::HirId,
bad_args: Vec<(Span, Option<String>)>,
) {
let span: MultiSpan = if bad_args.is_empty() {
tcx.def_span(impl_m.def_id).into()
} else {
bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
};
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
hir_id,
span,
"impl method assumes more implied bounds than the corresponding trait method",
|lint| {
let bad_args: Vec<_> =
bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
if !bad_args.is_empty() {
lint.multipart_suggestion(
format!(
"replace {} type{} to make the impl signature compatible",
pluralize!("this", bad_args.len()),
pluralize!(bad_args.len())
),
bad_args,
Applicability::MaybeIncorrect,
);
}
lint
},
);
}
#[derive(Debug, PartialEq, Eq)]
enum CheckImpliedWfMode {
/// Checks implied well-formedness of the impl method. If it fails, we will
@ -480,7 +616,8 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(def_id).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
let param_env = tcx.param_env(def_id);
// First, check a few of the same things as `compare_impl_method`,
@ -1548,7 +1685,8 @@ pub(super) fn compare_impl_const_raw(
) -> Result<(), ErrorGuaranteed> {
let impl_const_item = tcx.associated_item(impl_const_item_def);
let trait_const_item = tcx.associated_item(trait_const_item_def);
let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
let impl_trait_ref =
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity();
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());

View file

@ -182,7 +182,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
hir::ItemKind::Impl(ref impl_) => {
let is_auto = tcx
.impl_trait_ref(def_id)
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
let mut err =
@ -1253,8 +1253,12 @@ fn check_impl<'tcx>(
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().subst_identity();
let trait_ref = wfcx.normalize(
ast_trait_ref.path.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
trait_ref,
);
let trait_pred = ty::TraitPredicate {
trait_ref,
constness: match constness {
@ -1263,7 +1267,7 @@ fn check_impl<'tcx>(
},
polarity: ty::ImplPolarity::Positive,
};
let obligations = traits::wf::trait_obligations(
let mut obligations = traits::wf::trait_obligations(
wfcx.infcx,
wfcx.param_env,
wfcx.body_id,
@ -1271,6 +1275,13 @@ fn check_impl<'tcx>(
ast_trait_ref.path.span,
item,
);
for obligation in &mut obligations {
if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
&& pred.self_ty().skip_binder() == trait_ref.self_ty()
{
obligation.cause.span = ast_self_ty.span;
}
}
debug!(?obligations);
wfcx.register_obligations(obligations);
}
@ -1339,7 +1350,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
// is incorrect when dealing with unused substs, for example
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error.
let default_ct = tcx.const_param_default(param.def_id);
let default_ct = tcx.const_param_default(param.def_id).subst_identity();
if !default_ct.needs_subst() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
@ -1385,7 +1396,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
GenericParamDefKind::Const { .. } => {
// If the param has a default, ...
if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id);
let default_ct = tcx.const_param_default(param.def_id).subst_identity();
// ... and it's not a dependent default, ...
if !default_ct.needs_subst() {
// ... then substitute it with the default.

View file

@ -192,7 +192,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
let source = tcx.type_of(impl_did);
assert!(!source.has_escaping_bound_vars());
let target = {
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
trait_ref.substs.type_at(1)
@ -354,7 +354,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
});
let source = tcx.type_of(impl_did);
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.substs.type_at(1);
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);

View file

@ -128,7 +128,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
let impls = tcx.hir().trait_impls(def_id);
for &impl_def_id in impls {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
check_impl(tcx, impl_def_id, trait_ref);
check_object_overlap(tcx, impl_def_id, trait_ref);

View file

@ -21,7 +21,7 @@ pub(crate) fn orphan_check_impl(
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
trait_ref.error_reported()?;
let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);

View file

@ -14,6 +14,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_ref = trait_ref.subst_identity();
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");

View file

@ -1339,18 +1339,22 @@ fn suggest_impl_trait<'tcx>(
None
}
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
icx.astconv().instantiate_mono_trait_ref(
ast_trait_ref,
selfty,
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
)
}),
hir::ItemKind::Impl(ref impl_) => impl_
.of_trait
.as_ref()
.map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
icx.astconv().instantiate_mono_trait_ref(
ast_trait_ref,
selfty,
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
)
})
.map(ty::EarlyBinder),
_ => bug!(),
}
}

View file

@ -87,7 +87,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
Node::Item(item) => match item.kind {
ItemKind::Impl(ref impl_) => {
if impl_.defaultness.is_default() {
is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
is_default_impl_trait =
tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
}
&impl_.generics
}
@ -251,7 +252,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
// for details.
if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
let self_ty = tcx.type_of(def_id);
let trait_ref = tcx.impl_trait_ref(def_id);
let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
cgp::setup_constraining_predicates(
tcx,
&mut predicates,

View file

@ -114,34 +114,46 @@ fn diagnostic_hir_wf_check<'tcx>(
// Get the starting `hir::Ty` using our `WellFormedLoc`.
// We will walk 'into' this type to try to find
// a more precise span for our predicate.
let ty = match loc {
let tys = match loc {
WellFormedLoc::Ty(_) => match hir.get(hir_id) {
hir::Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Type(ty) => Some(ty),
hir::ImplItemKind::Const(ty, _) => Some(ty),
hir::ImplItemKind::Type(ty) => vec![ty],
hir::ImplItemKind::Const(ty, _) => vec![ty],
ref item => bug!("Unexpected ImplItem {:?}", item),
},
hir::Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Type(_, ty) => ty,
hir::TraitItemKind::Const(ty, _) => Some(ty),
hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(),
hir::TraitItemKind::Const(ty, _) => vec![ty],
ref item => bug!("Unexpected TraitItem {:?}", item),
},
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty),
hir::ItemKind::Impl(ref impl_) => {
assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_);
Some(impl_.self_ty)
}
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait {
Some(t) => t
.path
.segments
.last()
.iter()
.flat_map(|seg| seg.args().args)
.filter_map(|arg| {
if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None }
})
.chain([impl_.self_ty])
.collect(),
None => {
vec![impl_.self_ty]
}
},
ref item => bug!("Unexpected item {:?}", item),
},
hir::Node::Field(field) => Some(field.ty),
hir::Node::Field(field) => vec![field.ty],
hir::Node::ForeignItem(ForeignItem {
kind: ForeignItemKind::Static(ty, _), ..
}) => Some(*ty),
}) => vec![*ty],
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Type { default: Some(ty), .. },
..
}) => Some(*ty),
}) => vec![*ty],
ref node => bug!("Unexpected node {:?}", node),
},
WellFormedLoc::Param { function: _, param_idx } => {
@ -149,16 +161,16 @@ fn diagnostic_hir_wf_check<'tcx>(
// Get return type
if param_idx as usize == fn_decl.inputs.len() {
match fn_decl.output {
hir::FnRetTy::Return(ty) => Some(ty),
hir::FnRetTy::Return(ty) => vec![ty],
// The unit type `()` is always well-formed
hir::FnRetTy::DefaultReturn(_span) => None,
hir::FnRetTy::DefaultReturn(_span) => vec![],
}
} else {
Some(&fn_decl.inputs[param_idx as usize])
vec![&fn_decl.inputs[param_idx as usize]]
}
}
};
if let Some(ty) = ty {
for ty in tys {
visitor.visit_ty(ty);
}
visitor.cause

View file

@ -85,7 +85,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
}
let impl_generics = tcx.generics_of(impl_def_id);
let impl_predicates = tcx.predicates_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(

View file

@ -90,7 +90,7 @@ pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
let trait_def = tcx.trait_def(trait_ref.def_id);
let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
@ -207,7 +207,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
let impl_generic_predicates = tcx.predicates_of(impl_def_id);
let mut unconstrained_parameters = FxHashSet::default();
let mut constrained_params = FxHashSet::default();
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
// Unfortunately the functions in `constrained_generic_parameters` don't do
// what we want here. We want only a list of constrained parameters while
@ -370,7 +370,7 @@ fn check_predicates<'tcx>(
});
// Include the well-formed predicates of the type parameters of the impl.
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
let infcx = &tcx.infer_ctxt().build();
let obligations = wf::obligations(
infcx,

View file

@ -659,8 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
if let Some((maybe_def, output_ty, _)) =
self.extract_callable_info(callee_expr, callee_ty)
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
{
let descr = match maybe_def {

View file

@ -1,4 +1,7 @@
use crate::coercion::CoerceMany;
use crate::errors::{
LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
};
use crate::gather_locals::GatherLocalsVisitor;
use crate::FnCtxt;
use crate::GeneratorTypes;
@ -9,8 +12,9 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::check::fn_maybe_err;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use std::cell::RefCell;
@ -168,6 +172,10 @@ pub(super) fn check_fn<'a, 'tcx>(
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() {
check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
}
gen_ty
}
@ -223,3 +231,126 @@ fn check_panic_info_fn(
tcx.sess.span_err(span, "should have no const parameters");
}
}
fn check_lang_start_fn<'tcx>(
tcx: TyCtxt<'tcx>,
fn_sig: ty::FnSig<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
def_id: LocalDefId,
) {
let inputs = fn_sig.inputs();
let arg_count = inputs.len();
if arg_count != 4 {
tcx.sess.emit_err(LangStartIncorrectNumberArgs {
params_span: tcx.def_span(def_id),
found_param_count: arg_count,
});
}
// only check args if they should exist by checking the count
// note: this does not handle args being shifted or their order swapped very nicely
// but it's a lang item, users shouldn't frequently encounter this
// first arg is `main: fn() -> T`
if let Some(&main_arg) = inputs.get(0) {
// make a Ty for the generic on the fn for diagnostics
// FIXME: make the lang item generic checks check for the right generic *kind*
// for example `start`'s generic should be a type parameter
let generics = tcx.generics_of(def_id);
let fn_generic = generics.param_at(0, tcx);
let generic_tykind =
ty::Param(ty::ParamTy { index: fn_generic.index, name: fn_generic.name });
let generic_ty = tcx.mk_ty(generic_tykind);
let expected_fn_sig =
tcx.mk_fn_sig([].iter(), &generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
// we emit the same error to suggest changing the arg no matter what's wrong with the arg
let emit_main_fn_arg_err = || {
tcx.sess.emit_err(LangStartIncorrectParam {
param_span: decl.inputs[0].span,
param_num: 1,
expected_ty: expected_ty,
found_ty: main_arg,
});
};
if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
let main_fn_inputs = main_fn_sig.inputs();
if main_fn_inputs.iter().count() != 0 {
emit_main_fn_arg_err();
}
let output = main_fn_sig.output();
output.map_bound(|ret_ty| {
// if the output ty is a generic, it's probably the right one
if !matches!(ret_ty.kind(), ty::Param(_)) {
emit_main_fn_arg_err();
}
});
} else {
emit_main_fn_arg_err();
}
}
// second arg is isize
if let Some(&argc_arg) = inputs.get(1) {
if argc_arg != tcx.types.isize {
tcx.sess.emit_err(LangStartIncorrectParam {
param_span: decl.inputs[1].span,
param_num: 2,
expected_ty: tcx.types.isize,
found_ty: argc_arg,
});
}
}
// third arg is `*const *const u8`
if let Some(&argv_arg) = inputs.get(2) {
let mut argv_is_okay = false;
if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
if outer_ptr.mutbl.is_not() {
if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
argv_is_okay = true;
}
}
}
}
if !argv_is_okay {
let inner_ptr_ty =
tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
let expected_ty =
tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
tcx.sess.emit_err(LangStartIncorrectParam {
param_span: decl.inputs[2].span,
param_num: 3,
expected_ty,
found_ty: argv_arg,
});
}
}
// fourth arg is `sigpipe: u8`
if let Some(&sigpipe_arg) = inputs.get(3) {
if sigpipe_arg != tcx.types.u8 {
tcx.sess.emit_err(LangStartIncorrectParam {
param_span: decl.inputs[3].span,
param_num: 4,
expected_ty: tcx.types.u8,
found_ty: sigpipe_arg,
});
}
}
// output type is isize
if fn_sig.output() != tcx.types.isize {
tcx.sess.emit_err(LangStartIncorrectRetTy {
ret_span: decl.output.span(),
expected_ty: tcx.types.isize,
found_ty: fn_sig.output(),
});
}
}

View file

@ -85,6 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
}
/// Requires that the two types unify, and prints an error message if
@ -1941,4 +1942,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(block.span, "this block is missing a tail expression");
}
}
fn check_wrong_return_type_due_to_generic_arg(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
checked_ty: Ty<'tcx>,
) {
let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
enum CallableKind {
Function,
Method,
Constructor,
}
let mut maybe_emit_help = |def_id: hir::def_id::DefId,
callable: rustc_span::symbol::Ident,
args: &[hir::Expr<'_>],
kind: CallableKind| {
let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
let fn_ty = self.tcx.bound_type_of(def_id).0;
if !fn_ty.is_fn() {
return;
}
let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
if matches!(arg.kind(), ty::Param(_))
&& fn_sig.output().contains(arg)
&& self.node_ty(args[arg_idx].hir_id) == checked_ty
{
let mut multi_span: MultiSpan = parent_expr.span.into();
multi_span.push_span_label(
args[arg_idx].span,
format!(
"this argument influences the {} of `{}`",
if matches!(kind, CallableKind::Constructor) {
"type"
} else {
"return type"
},
callable
),
);
err.span_help(
multi_span,
format!(
"the {} `{}` due to the type of the argument passed",
match kind {
CallableKind::Function => "return type of this call is",
CallableKind::Method => "return type of this call is",
CallableKind::Constructor => "type constructed contains",
},
checked_ty
),
);
}
};
match parent_expr.kind {
hir::ExprKind::Call(fun, args) => {
let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
let hir::def::Res::Def(kind, def_id) = path.res else { return; };
let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
CallableKind::Constructor
} else {
CallableKind::Function
};
maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
}
hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
}
_ => return,
}
}
}

View file

@ -172,3 +172,36 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
);
}
}
#[derive(Diagnostic)]
#[diag(hir_typeck_lang_start_incorrect_number_params)]
#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)]
#[note(hir_typeck_lang_start_expected_sig_note)]
pub struct LangStartIncorrectNumberArgs {
#[primary_span]
pub params_span: Span,
pub found_param_count: usize,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_lang_start_incorrect_param)]
pub struct LangStartIncorrectParam<'tcx> {
#[primary_span]
#[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
pub param_span: Span,
pub param_num: usize,
pub expected_ty: Ty<'tcx>,
pub found_ty: Ty<'tcx>,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_lang_start_incorrect_ret_ty)]
pub struct LangStartIncorrectRetTy<'tcx> {
#[primary_span]
#[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
pub ret_span: Span,
pub expected_ty: Ty<'tcx>,
pub found_ty: Ty<'tcx>,
}

View file

@ -417,7 +417,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// Named constants have to be equated with the value
// being matched, so that's a read of the value being matched.
//
// FIXME: We don't actually reads for ZSTs.
// FIXME: We don't actually reads for ZSTs.
needs_to_be_read = true;
}
_ => {

View file

@ -1224,9 +1224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
GenericParamDefKind::Const { has_default } => {
if !infer_args && has_default {
tcx.bound_const_param_default(param.def_id)
.subst(tcx, substs.unwrap())
.into()
tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
self.fcx.var_for_def(self.span, param)
}

View file

@ -11,7 +11,6 @@ use rustc_hir::{
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{
@ -23,9 +22,9 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::NormalizeExt;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
@ -94,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
) -> bool {
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
else { return false; };
if can_satisfy(output) {
let (sugg_call, mut applicability) = match inputs.len() {
@ -163,99 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// because the callable type must also be well-formed to be called.
pub(in super::super) fn extract_callable_info(
&self,
expr: &Expr<'_>,
found: Ty<'tcx>,
ty: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
// Autoderef is useful here because sometimes we box callables, etc.
let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
match *found.kind() {
ty::FnPtr(fn_sig) =>
Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
ty::FnDef(def_id, _) => {
let fn_sig = found.fn_sig(self.tcx);
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
}
ty::Closure(def_id, substs) => {
let fn_sig = substs.as_closure().sig();
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
Some((
DefIdOrName::DefId(def_id),
pred.kind().rebind(proj.term.ty().unwrap()),
pred.kind().rebind(args.as_slice()),
))
} else {
None
}
})
}
ty::Dynamic(data, _, ty::Dyn) => {
data.iter().find_map(|pred| {
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
&& Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
// for existential projection, substs are shifted over by 1
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
{
Some((
DefIdOrName::Name("trait object"),
pred.rebind(proj.term.ty().unwrap()),
pred.rebind(args.as_slice()),
))
} else {
None
}
})
}
ty::Param(param) => {
let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
Some((
DefIdOrName::DefId(def_id),
pred.kind().rebind(proj.term.ty().unwrap()),
pred.kind().rebind(args.as_slice()),
))
} else {
None
}
})
}
_ => None,
}
}) else { return None; };
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
let inputs = inputs
.skip_binder()
.iter()
.map(|ty| {
self.replace_bound_vars_with_fresh_vars(
expr.span,
infer::FnCall,
inputs.rebind(*ty),
)
})
.collect();
// We don't want to register any extra obligations, which should be
// implied by wf, but also because that would possibly result in
// erroneous errors later on.
let infer::InferOk { value: output, obligations: _ } =
self.at(&self.misc(expr.span), self.param_env).normalize(output);
if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
}
pub fn suggest_two_fn_call(
@ -267,9 +176,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs_ty: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
) -> bool {
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
else { return false; };
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
else { return false; };
if can_satisfy(lhs_output_ty, rhs_output_ty) {

View file

@ -232,7 +232,7 @@ pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
pub enum Mode {
// An expression of the form `receiver.method_name(...)`.
// Autoderefs are performed on `receiver`, lookup is done based on the
// `self` argument of the method, and static methods aren't considered.
// `self` argument of the method, and static methods aren't considered.
MethodCall,
// An expression of the form `Type::item` or `<T>::item`.
// No autoderefs are performed, lookup is done based on the type each
@ -1587,11 +1587,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((
o.predicate,
None,
Some(o.cause),
));
let parent_o = o.clone();
let implied_obligations =
traits::elaborate_obligations(self.tcx, vec![o]);
for o in implied_obligations {
let parent = if o == parent_o {
None
} else {
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
== self.tcx.lang_items().sized_trait()
{
// We don't care to talk about implicit `Sized` bounds.
continue;
}
Some(parent_o.predicate)
};
if !self.predicate_may_hold(&o) {
possibly_unsatisfied_predicates.push((
o.predicate,
parent,
Some(o.cause),
));
}
}
}
}
}

View file

@ -505,19 +505,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => None,
};
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
if let Some(g) = kind.generics() {
let key = (
g.tail_span_for_predicate_suggestion(),
g.add_where_or_trailing_comma(),
);
type_params
.entry(key)
.or_insert_with(FxHashSet::default)
.insert(obligation.to_owned());
}
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
&& let Some(g) = kind.generics()
{
let key = (
g.tail_span_for_predicate_suggestion(),
g.add_where_or_trailing_comma(),
);
type_params
.entry(key)
.or_insert_with(FxHashSet::default)
.insert(obligation.to_owned());
return true;
}
}
false
};
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
let msg = format!(
@ -692,7 +694,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"auto trait is invoked with no method error, but no error reported?",
);
}
Some(_) => unreachable!(),
Some(Node::Item(hir::Item {
ident, kind: hir::ItemKind::Trait(..), ..
})) => {
skip_list.insert(p);
let entry = spanned_predicates.entry(ident.span);
let entry = entry.or_insert_with(|| {
(FxHashSet::default(), FxHashSet::default(), Vec::new())
});
entry.0.insert(cause.span);
entry.1.insert((ident.span, ""));
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
entry.2.push(p);
}
Some(node) => unreachable!("encountered `{node:?}`"),
None => (),
}
}
@ -719,19 +734,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
unsatisfied_bounds = true;
}
let mut suggested_bounds = FxHashSet::default();
// The requirements that didn't have an `impl` span to show.
let mut bound_list = unsatisfied_predicates
.iter()
.filter_map(|(pred, parent_pred, _cause)| {
let mut suggested = false;
format_pred(*pred).map(|(p, self_ty)| {
collect_type_param_suggestions(self_ty, *pred, &p);
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
// We don't suggest `PartialEq` when we already suggest `Eq`.
} else if !suggested_bounds.contains(pred) {
if collect_type_param_suggestions(self_ty, *pred, &p) {
suggested = true;
suggested_bounds.insert(pred);
}
}
(
match parent_pred {
None => format!("`{}`", &p),
Some(parent_pred) => match format_pred(*parent_pred) {
None => format!("`{}`", &p),
Some((parent_p, _)) => {
collect_type_param_suggestions(self_ty, *parent_pred, &p);
if !suggested
&& !suggested_bounds.contains(pred)
&& !suggested_bounds.contains(parent_pred)
{
if collect_type_param_suggestions(
self_ty,
*parent_pred,
&p,
) {
suggested_bounds.insert(pred);
}
}
format!("`{}`\nwhich is required by `{}`", p, parent_p)
}
},
@ -1037,7 +1072,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// the impl, if local to crate (item may be defaulted), else nothing.
let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
self.associated_value(impl_trait_ref.def_id, item_name)
self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
}) else {
continue;
};
@ -1055,7 +1090,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let insertion = match self.tcx.impl_trait_ref(impl_did) {
None => String::new(),
Some(trait_ref) => {
format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
format!(
" of the trait `{}`",
self.tcx.def_path_str(trait_ref.skip_binder().def_id)
)
}
};
@ -1086,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let Some(sugg_span) = sugg_span
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
let path = self.tcx.def_path_str(trait_ref.def_id);
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
let ty = match item.kind {
ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
@ -2581,7 +2619,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
})
.any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
let imp_simp =
simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
@ -2662,8 +2700,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found: Ty<'tcx>,
expected: Ty<'tcx>,
) -> bool {
let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
else { return false; };
let Some((_def_id_or_name, output, _inputs)) =
self.extract_callable_info(found) else {
return false;
};
if !self.can_coerce(output, expected) {
return false;

View file

@ -1782,9 +1782,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// like when you have two references but one is `usize` and the other
// is `f32`. In those cases we still want to show the `note`. If the
// value from `ef` is `Infer(_)`, then we ignore it.
if !ef.expected.is_ty_infer() {
if !ef.expected.is_ty_or_numeric_infer() {
ef.expected != values.expected
} else if !ef.found.is_ty_infer() {
} else if !ef.found.is_ty_or_numeric_infer() {
ef.found != values.found
} else {
false
@ -1923,6 +1923,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(ty::Tuple(fields), _) => {
self.emit_tuple_wrap_err(&mut err, span, found, fields)
}
// If a byte was expected and the found expression is a char literal
// containing a single ASCII character, perhaps the user meant to write `b'c'` to
// specify a byte literal
(ty::Uint(ty::UintTy::U8), ty::Char) => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
&& code.chars().next().map_or(false, |c| c.is_ascii())
{
err.span_suggestion(
span,
"if you meant to write a byte literal, prefix with `b`",
format!("b'{}'", escape_literal(code)),
Applicability::MachineApplicable,
);
}
}
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
// specify a character literal (issue #92479)

View file

@ -78,7 +78,7 @@ impl InferenceDiagnosticsData {
}
fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
if in_type.is_ty_infer() {
if in_type.is_ty_or_numeric_infer() {
""
} else if self.name == "_" {
// FIXME: Consider specializing this message if there is a single `_`
@ -195,12 +195,12 @@ fn ty_to_string<'tcx>(
// invalid pseudo-syntax, we want the `fn`-pointer output instead.
(ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
(_, Some(def_id))
if ty.is_ty_infer()
if ty.is_ty_or_numeric_infer()
&& infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) =>
{
"Vec<_>".to_string()
}
_ if ty.is_ty_infer() => "/* Type */".to_string(),
_ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(),
// FIXME: The same thing for closures, but this only works when the closure
// does not capture anything.
//
@ -680,7 +680,7 @@ impl<'tcx> InferSourceKind<'tcx> {
| InferSourceKind::ClosureReturn { ty, .. } => {
if ty.is_closure() {
("closure", closure_as_fn_str(infcx, ty))
} else if !ty.is_ty_infer() {
} else if !ty.is_ty_or_numeric_infer() {
("normal", ty_to_string(infcx, ty, None))
} else {
("other", String::new())
@ -813,7 +813,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
self.attempt += 1;
if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source
&& let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind
&& ty.is_ty_infer()
&& ty.is_ty_or_numeric_infer()
{
// Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of
// `let x: _ = iter.collect();`, as this is a very common case.

View file

@ -320,6 +320,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.impl_trait_ref(impl_def_id)
else { return; };
let trait_substs = trait_ref
.subst_identity()
// Replace the explicit self type with `Self` for better suggestion rendering
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
.substs;

View file

@ -1,7 +1,7 @@
use smallvec::smallvec;
use crate::infer::outlives::components::{push_outlives_components, Component};
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
use rustc_span::symbol::Ident;
@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> {
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());
let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
// when parent predicate is non-const, elaborate it to non-const predicates.
if data.constness == ty::BoundConstness::NotConst {
pred = pred.without_const(tcx);
}
let cause = obligation.cause.clone().derived_cause(
bound_predicate.rebind(data),
|derived| {
traits::ImplDerivedObligation(Box::new(
traits::ImplDerivedObligationCause {
derived,
impl_def_id: data.def_id(),
span,
},
))
},
);
predicate_obligation(
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
obligation.param_env,
obligation.cause.clone(),
cause,
)
});
debug!(?data, ?obligations, "super_predicates");

View file

@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" }
rustc_privacy = { path = "../rustc_privacy" }
rustc_query_impl = { path = "../rustc_query_impl" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }

View file

@ -87,3 +87,7 @@ pub struct FailedWritingFile<'a> {
pub path: &'a Path,
pub error: io::Error,
}
#[derive(Diagnostic)]
#[diag(interface_proc_macro_crate_panic_abort)]
pub struct ProcMacroCratePanicAbort;

View file

@ -1,7 +1,8 @@
use crate::errors::{
CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
TempsDirError,
};
use crate::interface::{Compiler, Result};
use crate::proc_macro_decls;
@ -36,6 +37,7 @@ use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::FileName;
use rustc_target::spec::PanicStrategy;
use rustc_trait_selection::traits;
use std::any::Any;
@ -380,6 +382,10 @@ pub fn configure_and_expand(
}
}
if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
sess.emit_warning(ProcMacroCratePanicAbort);
}
// For backwards compatibility, we don't try to run proc macro injection
// if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
// specified. This should only affect users who manually invoke 'rustdoc', as
@ -817,23 +823,26 @@ pub fn create_global_ctxt<'tcx>(
lint_store,
arena,
hir_arena,
untracked_resolutions,
untracked,
krate,
dep_graph,
queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
queries.as_dyn(),
rustc_query_impl::query_callbacks(arena),
crate_name,
outputs,
)
})
});
let mut qcx = QueryContext { gcx };
qcx.enter(|tcx| {
tcx.feed_unit_query()
.resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering)))
let feed = tcx.feed_unit_query();
feed.resolver_for_lowering(
tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
);
feed.resolutions(tcx.arena.alloc(untracked_resolutions));
feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs)));
feed.features_query(sess.features_untracked());
let feed = tcx.feed_local_crate();
feed.crate_name(crate_name);
});
qcx
}

View file

@ -748,6 +748,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(link_only, true);
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
tracked!(log_backtrace, Some("filter".to_string()));
tracked!(maximal_hir_to_mir_coverage, true);
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);

View file

@ -11,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) {
}
fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
if !tcx.features().enabled(sym::lint_reasons) {
return;
}

View file

@ -1105,6 +1105,7 @@ impl UnusedDelimLint for UnusedBraces {
|| matches!(expr.kind, ast::ExprKind::Lit(_)))
&& !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty()
&& !expr.span.from_expansion()
&& !value.span.from_expansion()
&& !inner.span.from_expansion()
{

View file

@ -4033,10 +4033,10 @@ declare_lint! {
///
/// This can be used to implement an unsound API if used incorrectly.
pub IMPLIED_BOUNDS_ENTAILMENT,
Warn,
Deny,
"impl method assumes more implied bounds than its corresponding trait method",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
reason: FutureIncompatibilityReason::FutureReleaseError,
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}

View file

@ -7,6 +7,7 @@ edition = "2021"
tracing = "0.1.28"
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
tracing-tree = "0.2.0"
tracing-core = "0.1.28"
[dev-dependencies]
rustc_span = { path = "../rustc_span" }

View file

@ -45,16 +45,34 @@
use std::env::{self, VarError};
use std::fmt::{self, Display};
use std::io::{self, IsTerminal};
use tracing_core::{Event, Subscriber};
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
use tracing_subscriber::fmt::{
format::{self, FormatEvent, FormatFields},
FmtContext,
};
use tracing_subscriber::layer::SubscriberExt;
pub fn init_rustc_env_logger() -> Result<(), Error> {
init_env_logger("RUSTC_LOG")
init_rustc_env_logger_with_backtrace_option(&None)
}
pub fn init_rustc_env_logger_with_backtrace_option(
backtrace_target: &Option<String>,
) -> Result<(), Error> {
init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target)
}
/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) -> Result<(), Error> {
init_env_logger_with_backtrace_option(env, &None)
}
pub fn init_env_logger_with_backtrace_option(
env: &str,
backtrace_target: &Option<String>,
) -> Result<(), Error> {
let filter = match env::var(env) {
Ok(env) => EnvFilter::new(env),
_ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
@ -88,11 +106,47 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
let layer = layer.with_thread_ids(true).with_thread_names(true);
let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
match backtrace_target {
Some(str) => {
let fmt_layer = tracing_subscriber::fmt::layer()
.with_writer(io::stderr)
.without_time()
.event_format(BacktraceFormatter { backtrace_target: str.to_string() });
let subscriber = subscriber.with(fmt_layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
}
None => {
tracing::subscriber::set_global_default(subscriber).unwrap();
}
};
Ok(())
}
struct BacktraceFormatter {
backtrace_target: String,
}
impl<S, N> FormatEvent<S, N> for BacktraceFormatter
where
S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
N: for<'a> FormatFields<'a> + 'static,
{
fn format_event(
&self,
_ctx: &FmtContext<'_, S, N>,
mut writer: format::Writer<'_>,
event: &Event<'_>,
) -> fmt::Result {
let target = event.metadata().target();
if !target.contains(&self.backtrace_target) {
return Ok(());
}
let backtrace = std::backtrace::Backtrace::capture();
writeln!(writer, "stack backtrace: \n{:?}", backtrace)
}
}
pub fn stdout_isatty() -> bool {
io::stdout().is_terminal()
}

View file

@ -1555,7 +1555,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.tables.impl_defaultness.set(def_id.index, *defaultness);
self.tables.constness.set(def_id.index, *constness);
let trait_ref = self.tcx.impl_trait_ref(def_id);
let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
if let Some(trait_ref) = trait_ref {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
@ -1899,6 +1899,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
let trait_ref = trait_ref.subst_identity();
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),

View file

@ -359,8 +359,8 @@ define_tables! {
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>,
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
impl_trait_ref: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::TraitRef<'static>>>>,
const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,

View file

@ -30,7 +30,12 @@ macro_rules! arena_types {
[decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
[decode] borrowck_result:
rustc_middle::mir::BorrowCheckResult<'tcx>,
[] resolver: rustc_data_structures::steal::Steal<rustc_middle::ty::ResolverAstLowering>,
[] resolver: rustc_data_structures::steal::Steal<(
rustc_middle::ty::ResolverAstLowering,
rustc_data_structures::sync::Lrc<rustc_ast::Crate>,
)>,
[] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>,
[] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
[decode] code_region: rustc_middle::mir::coverage::CodeRegion,
[] const_allocs: rustc_middle::mir::interpret::Allocation,

View file

@ -102,6 +102,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
self.impl_trait_ref(def_id)
.map(|t| t.subst_identity())
.map(ImplSubject::Trait)
.unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
}

View file

@ -27,12 +27,12 @@ rustc_queries! {
}
query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
eval_always
feedable
no_hash
desc { "getting the resolver outputs" }
}
query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
query resolver_for_lowering(_: ()) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
feedable
no_hash
desc { "getting the resolver for lowering" }
@ -142,7 +142,7 @@ rustc_queries! {
/// Given the def_id of a const-generic parameter, computes the associated default const
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
query const_param_default(param: DefId) -> ty::Const<'tcx> {
query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param) }
cache_on_disk_if { param.is_local() }
separate_provide_extern
@ -737,7 +737,7 @@ rustc_queries! {
/// Given an `impl_id`, return the trait it implements.
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
query impl_trait_ref(impl_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
cache_on_disk_if { impl_id.is_local() }
separate_provide_extern
@ -1673,7 +1673,7 @@ rustc_queries! {
/// Gets the name of the crate.
query crate_name(_: CrateNum) -> Symbol {
eval_always
feedable
desc { "fetching what a crate is named" }
separate_provide_extern
}
@ -1857,7 +1857,7 @@ rustc_queries! {
/// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
/// has been destroyed.
query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
eval_always
feedable
desc { "getting output filenames" }
}
@ -2041,7 +2041,7 @@ rustc_queries! {
}
query features_query(_: ()) -> &'tcx rustc_feature::Features {
eval_always
feedable
desc { "looking up enabled feature gates" }
}

View file

@ -239,7 +239,7 @@ impl<'tcx> Const<'tcx> {
}
}
pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> {
let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(ac), .. },
@ -250,5 +250,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
"`const_param_default` expected a generic parameter with a constant"
),
};
Const::from_anon_const(tcx, default_def_id)
ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
}

View file

@ -51,7 +51,7 @@ use rustc_macros::HashStable;
use rustc_query_system::dep_graph::DepNodeIndex;
use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::config::{CrateType, OutputFilenames};
use rustc_session::config::CrateType;
use rustc_session::cstore::{CrateStoreDyn, Untracked};
use rustc_session::lint::Lint;
use rustc_session::Limit;
@ -74,7 +74,6 @@ use std::hash::{Hash, Hasher};
use std::iter;
use std::mem;
use std::ops::{Bound, Deref};
use std::sync::Arc;
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
@ -363,6 +362,9 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> {
TyCtxtFeed { tcx: self, key: () }
}
pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> {
TyCtxtFeed { tcx: self, key: LOCAL_CRATE }
}
}
impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
@ -428,11 +430,6 @@ pub struct GlobalCtxt<'tcx> {
pub consts: CommonConsts<'tcx>,
untracked: Untracked,
/// Output of the resolver.
pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
/// The entire crate as AST. This field serves as the input for the hir_crate query,
/// which lowers it from AST to HIR. It must not be read or used by anything else.
pub untracked_crate: Steal<Lrc<ast::Crate>>,
/// This provides access to the incremental compilation on-disk cache for query results.
/// Do not access this directly. It is only meant to be used by
@ -457,17 +454,11 @@ pub struct GlobalCtxt<'tcx> {
/// Merge this with `selection_cache`?
pub evaluation_cache: traits::EvaluationCache<'tcx>,
/// The definite name of the current crate after taking into account
/// attributes, commandline parameters, etc.
crate_name: Symbol,
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
/// Stores memory for globals (statics/consts).
pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
output_filenames: Arc<OutputFilenames>,
}
impl<'tcx> TyCtxt<'tcx> {
@ -592,15 +583,11 @@ impl<'tcx> TyCtxt<'tcx> {
lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
arena: &'tcx WorkerLocal<Arena<'tcx>>,
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
untracked_resolutions: ty::ResolverGlobalCtxt,
untracked: Untracked,
krate: Lrc<ast::Crate>,
dep_graph: DepGraph,
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
queries: &'tcx dyn query::QueryEngine<'tcx>,
query_kinds: &'tcx [DepKindStruct<'tcx>],
crate_name: Symbol,
output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
s.emit_fatal(err);
@ -622,8 +609,6 @@ impl<'tcx> TyCtxt<'tcx> {
lifetimes: common_lifetimes,
consts: common_consts,
untracked,
untracked_resolutions,
untracked_crate: Steal::new(krate),
on_disk_cache,
queries,
query_caches: query::QueryCaches::default(),
@ -632,10 +617,8 @@ impl<'tcx> TyCtxt<'tcx> {
pred_rcache: Default::default(),
selection_cache: Default::default(),
evaluation_cache: Default::default(),
crate_name,
data_layout,
alloc_map: Lock::new(interpret::AllocMap::new()),
output_filenames: Arc::new(output_filenames),
}
}
@ -810,7 +793,7 @@ impl<'tcx> TyCtxt<'tcx> {
// statements within the query system and we'd run into endless
// recursion otherwise.
let (crate_name, stable_crate_id) = if def_id.is_local() {
(self.crate_name, self.sess.local_stable_crate_id())
(self.crate_name(LOCAL_CRATE), self.sess.local_stable_crate_id())
} else {
let cstore = &*self.untracked.cstore;
(cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
@ -2407,13 +2390,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
}
pub fn provide(providers: &mut ty::query::Providers) {
providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
providers.module_reexports =
|tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
providers.crate_name = |tcx, id| {
assert_eq!(id, LOCAL_CRATE);
tcx.crate_name
};
providers.maybe_unused_trait_imports =
|tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
providers.maybe_unused_extern_crates =
@ -2424,8 +2402,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.output_filenames = |tcx, ()| &tcx.output_filenames;
providers.features_query = |tcx, ()| tcx.sess.features_untracked();
providers.is_panic_runtime = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)

View file

@ -88,7 +88,7 @@ impl GenericParamDef {
Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into()))
}
GenericParamDefKind::Const { has_default } if has_default => {
Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into()))
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
}
_ => None,
}

View file

@ -2187,8 +2187,10 @@ impl<'tcx> TyCtxt<'tcx> {
) -> Option<ImplOverlapKind> {
// If either trait impl references an error, they're allowed to overlap,
// as one of them essentially doesn't exist.
if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error())
|| self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error())
if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error())
|| self
.impl_trait_ref(def_id2)
.map_or(false, |tr| tr.subst_identity().references_error())
{
return Some(ImplOverlapKind::Permitted { marker: false });
}
@ -2218,7 +2220,7 @@ impl<'tcx> TyCtxt<'tcx> {
let is_marker_overlap = {
let is_marker_impl = |def_id: DefId| -> bool {
let trait_ref = self.impl_trait_ref(def_id);
trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
};
is_marker_impl(def_id1) && is_marker_impl(def_id2)
};
@ -2364,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
/// If it implements no trait, returns `None`.
pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
self.impl_trait_ref(def_id).map(|tr| tr.def_id)
self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
}
/// If the given `DefId` describes an item belonging to a trait,

View file

@ -32,6 +32,10 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
}
impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
}
#[macro_export]
macro_rules! trivially_parameterized_over_tcx {
($($ty:ty),+ $(,)?) => {

View file

@ -116,7 +116,7 @@ pub trait Printer<'tcx>: Sized {
DefPathData::Impl => {
let generics = self.tcx().generics_of(def_id);
let self_ty = self.tcx().bound_type_of(def_id);
let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
(
self_ty.subst(self.tcx(), substs),

View file

@ -7,8 +7,8 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
use crate::ty::visit::ValidateBoundVars;
use crate::ty::InferTy::*;
use crate::ty::{
self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
TypeVisitor,
self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
use crate::ty::{List, ParamEnv};
use hir::def::DefKind;
@ -1106,6 +1106,17 @@ impl<'tcx, T> Binder<'tcx, T> {
if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
}
pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option<T>
where
T: TypeFoldable<'tcx>,
{
if !self.0.has_escaping_bound_vars() {
Some(self.skip_binder())
} else {
self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok()
}
}
/// Splits the contents into two things that share the same binder
/// level as the original, returning two distinct binders.
///
@ -1135,6 +1146,81 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
}
}
struct SkipBindersAt<'tcx> {
tcx: TyCtxt<'tcx>,
index: ty::DebruijnIndex,
}
impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
type Error = ();
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
where
T: ty::TypeFoldable<'tcx>,
{
self.index.shift_in(1);
let value = t.try_map_bound(|t| t.try_fold_with(self));
self.index.shift_out(1);
value
}
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !ty.has_escaping_bound_vars() {
Ok(ty)
} else if let ty::Bound(index, bv) = *ty.kind() {
if index == self.index {
Err(())
} else {
Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
}
} else {
ty.try_super_fold_with(self)
}
}
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
if !r.has_escaping_bound_vars() {
Ok(r)
} else if let ty::ReLateBound(index, bv) = r.kind() {
if index == self.index {
Err(())
} else {
Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
}
} else {
r.try_super_fold_with(self)
}
}
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
if !ct.has_escaping_bound_vars() {
Ok(ct)
} else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
if index == self.index {
Err(())
} else {
Ok(self.tcx().mk_const(
ty::ConstKind::Bound(index.shifted_out(1), bv),
ct.ty().try_fold_with(self)?,
))
}
} else {
ct.try_super_fold_with(self)
}
}
fn try_fold_predicate(
&mut self,
p: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> {
if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
}
}
/// Represents the projection of an associated type.
///
/// For a projection, this would be `<Ty as Trait<...>>::N`.
@ -1686,7 +1772,7 @@ impl<'tcx> Ty<'tcx> {
}
#[inline]
pub fn is_ty_infer(self) -> bool {
pub fn is_ty_or_numeric_infer(self) -> bool {
matches!(self.kind(), Infer(_))
}

View file

@ -202,7 +202,7 @@ impl<'tcx> GenericArg<'tcx> {
pub fn is_non_region_infer(self) -> bool {
match self.unpack() {
GenericArgKind::Lifetime(_) => false,
GenericArgKind::Type(ty) => ty.is_ty_infer(),
GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
GenericArgKind::Const(ct) => ct.is_ct_infer(),
}
}
@ -713,6 +713,10 @@ impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder<T> {
let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
self.0.fold_with(&mut folder)
}
pub fn subst_identity(self) -> T {
self.0
}
}
///////////////////////////////////////////////////////////////////////////

View file

@ -193,7 +193,7 @@ pub struct TypeckResults<'tcx> {
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
/// as `&[u8]`, depending on the pattern in which they are used.
/// as `&[u8]`, depending on the pattern in which they are used.
/// This hashset records all instances where we behave
/// like this to allow `const_to_pat` to reliably handle this situation.
pub treat_byte_string_as_slice: ItemLocalSet,

View file

@ -652,13 +652,6 @@ impl<'tcx> TyCtxt<'tcx> {
ty::EarlyBinder(self.fn_sig(def_id))
}
pub fn bound_impl_trait_ref(
self,
def_id: DefId,
) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
}
pub fn bound_explicit_item_bounds(
self,
def_id: DefId,
@ -673,10 +666,6 @@ impl<'tcx> TyCtxt<'tcx> {
ty::EarlyBinder(self.item_bounds(def_id))
}
pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
ty::EarlyBinder(self.const_param_default(def_id))
}
pub fn bound_predicates_of(
self,
def_id: DefId,

View file

@ -94,6 +94,18 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
}
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
}
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
}
}
// item_and_field_ids should form a cycle where each field contains the
// type in the next element in the list
pub fn recursive_type_error(

View file

@ -1352,6 +1352,8 @@ fn create_mono_items_for_default_impls<'tcx>(
);
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_ref = trait_ref.subst_identity();
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);

View file

@ -79,7 +79,7 @@ impl<'a> StringReader<'a> {
/// preceded by whitespace.
fn next_token(&mut self) -> (Token, bool) {
let mut preceded_by_whitespace = false;
let mut swallow_next_invalid = 0;
// Skip trivial (whitespace & comments) tokens
loop {
let token = self.cursor.advance_token();
@ -232,19 +232,34 @@ impl<'a> StringReader<'a> {
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
let c = self.str_from(start).chars().next().unwrap();
// Don't emit diagnostics for sequences of the same invalid token
if swallow_next_invalid > 0 {
swallow_next_invalid -= 1;
continue;
}
let mut it = self.str_from_to_end(start).chars();
let c = it.next().unwrap();
let repeats = it.take_while(|c1| *c1 == c).count();
let mut err =
self.struct_err_span_char(start, self.pos, "unknown start of token", c);
self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
// FIXME: the lexer could be used to turn the ASCII version of unicode
// homoglyphs, instead of keeping a table in `check_for_substitution`into the
// token. Ideally, this should be inside `rustc_lexer`. However, we should
// first remove compound tokens like `<<` from `rustc_lexer`, and then add
// fancier error recovery to it, as there will be less overall work to do this
// way.
let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
if c == '\x00' {
err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
}
if repeats > 0 {
if repeats == 1 {
err.note(format!("character appears once more"));
} else {
err.note(format!("character appears {repeats} more times"));
}
swallow_next_invalid = repeats;
}
err.emit();
if let Some(token) = token {
token
@ -486,6 +501,11 @@ impl<'a> StringReader<'a> {
&self.src[self.src_index(start)..self.src_index(end)]
}
/// Slice of the source text spanning from `start` until the end
fn str_from_to_end(&self, start: BytePos) -> &str {
&self.src[self.src_index(start)..]
}
fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
Err(RawStrError::InvalidStarter { bad_char }) => {

View file

@ -337,10 +337,11 @@ pub(super) fn check_for_substitution<'a>(
pos: BytePos,
ch: char,
err: &mut Diagnostic,
count: usize,
) -> Option<token::TokenKind> {
let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else {
let msg = format!("substitution character not found for '{}'", ch);
@ -369,7 +370,12 @@ pub(super) fn check_for_substitution<'a>(
"Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
ch, u_name, ascii_char, ascii_name
);
err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
err.span_suggestion(
span,
&msg,
ascii_char.to_string().repeat(count),
Applicability::MaybeIncorrect,
);
}
token.clone()
}

View file

@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr {
pub(super) enum LhsExpr {
NotYetParsed,
AttributesParsed(AttrWrapper),
AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
AlreadyParsed { expr: P<Expr>, starts_statement: bool },
}
impl From<Option<AttrWrapper>> for LhsExpr {
@ -97,11 +97,11 @@ impl From<Option<AttrWrapper>> for LhsExpr {
}
impl From<P<Expr>> for LhsExpr {
/// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
/// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`.
///
/// This conversion does not allocate.
fn from(expr: P<Expr>) -> Self {
LhsExpr::AlreadyParsed(expr, false)
LhsExpr::AlreadyParsed { expr, starts_statement: false }
}
}
@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
lhs: LhsExpr,
) -> PResult<'a, P<Expr>> {
let mut starts_stmt = false;
let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs {
starts_stmt = starts_statement;
expr
} else {
@ -562,17 +562,23 @@ impl<'a> Parser<'a> {
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
match this.token.uninterpolate().kind {
token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
// `!expr`
token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
// `~expr`
token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
// `-expr`
token::BinOp(token::Minus) => {
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
} // `-expr`
}
// `*expr`
token::BinOp(token::Star) => {
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
} // `*expr`
}
// `&expr` and `&&expr`
token::BinOp(token::And) | token::AndAnd => {
make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
}
// `+lit`
token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
let mut err =
LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
@ -587,7 +593,7 @@ impl<'a> Parser<'a> {
this.bump();
this.parse_prefix_expr(None)
} // `+expr`
}
// Recover from `++x`:
token::BinOp(token::Plus)
if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
@ -624,7 +630,7 @@ impl<'a> Parser<'a> {
Ok((span, self.mk_unary(op, expr)))
}
// Recover on `!` suggesting for bitwise negation instead.
/// Recover on `~expr` in favor of `!expr`.
fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
self.sess.emit_err(TildeAsUnaryOperator(lo));
@ -651,7 +657,6 @@ impl<'a> Parser<'a> {
/// Recover on `not expr` in favor of `!expr`.
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
// Emit the error...
let negated_token = self.look_ahead(1, |t| t.clone());
let sub_diag = if negated_token.is_numeric_lit() {
@ -672,7 +677,6 @@ impl<'a> Parser<'a> {
),
});
// ...and recover!
self.parse_unary_expr(lo, UnOp::Not)
}
@ -1471,9 +1475,8 @@ impl<'a> Parser<'a> {
} else if self.eat(&token::Comma) {
// Vector with two or more elements.
let sep = SeqSep::trailing_allowed(token::Comma);
let (remaining_exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
let mut exprs = vec![first_expr];
exprs.extend(remaining_exprs);
let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
exprs.insert(0, first_expr);
ExprKind::Array(exprs)
} else {
// Vector with one element
@ -1593,7 +1596,7 @@ impl<'a> Parser<'a> {
vis.0
};
// Suggestion involves adding a (as of time of writing this, unstable) labeled block.
// Suggestion involves adding a labeled block.
//
// If there are no breaks that may use this label, suggest removing the label and
// recover to the unmodified expression.

View file

@ -469,7 +469,7 @@ impl<'a> Parser<'a> {
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
///
/// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
/// should already have been parsed by now at this point,
/// should already have been parsed by now at this point,
/// if the next token is `@` then we can try to parse the more general form.
///
/// Consult `parse_pat_ident` for the `binding` grammar.

View file

@ -164,7 +164,10 @@ impl<'a> Parser<'a> {
// Perform this outside of the `collect_tokens_trailing_token` closure,
// since our outer attributes do not apply to this part of the expression
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
this.parse_assoc_expr_with(
0,
LhsExpr::AlreadyParsed { expr, starts_statement: true },
)
})?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
} else {
@ -198,7 +201,10 @@ impl<'a> Parser<'a> {
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
let e = self.parse_assoc_expr_with(
0,
LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
)?;
StmtKind::Expr(e)
};
Ok(self.mk_stmt(lo.to(hi), kind))

View file

@ -82,6 +82,7 @@ impl CheckAttrVisitor<'_> {
let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs {
let attr_is_valid = match attr.name_or_empty() {
sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
sym::inline => self.check_inline(hir_id, attr, span, target),
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
@ -241,6 +242,16 @@ impl CheckAttrVisitor<'_> {
);
}
/// Checks if `#[do_not_recommend]` is applied on a trait impl.
fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
if let Target::Impl = target {
true
} else {
self.tcx.sess.emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
false
}
}
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
match target {

View file

@ -266,7 +266,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
{
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().subst_identity();
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
&& let Some(adt_def_id) = adt_def.did().as_local()
{

View file

@ -14,6 +14,13 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
use crate::lang_items::Duplicate;
#[derive(Diagnostic)]
#[diag(passes_incorrect_do_not_recommend_location)]
pub struct IncorrectDoNotRecommendLocation {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(passes_outer_crate_level_attr)]
pub struct OuterCrateLevelAttr;

View file

@ -338,7 +338,7 @@ trait VisibilityLike: Sized {
let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
find.visit(tcx.type_of(def_id));
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
find.visit_trait(trait_ref);
find.visit_trait(trait_ref.subst_identity());
}
find.min
}
@ -838,7 +838,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
GenericParamDefKind::Const { has_default } => {
self.visit(self.ev.tcx.type_of(param.def_id));
if has_default {
self.visit(self.ev.tcx.const_param_default(param.def_id));
self.visit(self.ev.tcx.const_param_default(param.def_id).subst_identity());
}
}
}
@ -858,7 +858,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
fn trait_ref(&mut self) -> &mut Self {
if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
self.visit_trait(trait_ref);
self.visit_trait(trait_ref.subst_identity());
}
self
}

View file

@ -167,7 +167,7 @@ impl<'a> Resolver<'a> {
);
err.emit();
} else if let Some((span, msg, sugg, appl)) = suggestion {
err.span_suggestion(span, msg, sugg, appl);
err.span_suggestion_verbose(span, msg, sugg, appl);
err.emit();
} else if let [segment] = path.as_slice() && is_call {
err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);

View file

@ -2065,7 +2065,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
path: &[Segment],
) -> Option<(Span, &'static str, String, Applicability)> {
let (ident, span) = match path {
[segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => {
[segment]
if !segment.has_generic_args
&& segment.ident.name != kw::SelfUpper
&& segment.ident.name != kw::Dyn =>
{
(segment.ident.to_string(), segment.ident.span)
}
_ => return None,

View file

@ -1137,7 +1137,7 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
}
}
impl Resolver<'_> {
impl<'a> Resolver<'a> {
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
self.node_id_to_def_id.get(&node).copied()
}
@ -1194,6 +1194,10 @@ impl Resolver<'_> {
self.cstore().item_generics_num_lifetimes(def_id, self.session)
}
}
pub fn sess(&self) -> &'a Session {
self.session
}
}
impl<'a> Resolver<'a> {

View file

@ -2091,7 +2091,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
.map(|s| {
// Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
// where KIND is one of "dylib", "framework", "static", "link-arg" and
// where MODIFIERS are a comma separated list of supported modifiers
// where MODIFIERS are a comma separated list of supported modifiers
// (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
// with either + or - to indicate whether it is enabled or disabled.
// The last value specified for a given modifier wins.

View file

@ -1411,6 +1411,8 @@ options! {
"what location details should be tracked when using caller_location, either \
`none`, or a comma separated list of location details, for which \
valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED],
"add a backtrace along with logging"),
ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate (default: no)"),
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],

View file

@ -15,6 +15,6 @@ scoped-tls = "1.0"
unicode-width = "0.1.4"
cfg-if = "1.0"
tracing = "0.1"
sha1 = { package = "sha-1", version = "0.10.0" }
sha1 = "0.10.0"
sha2 = "0.10.1"
md5 = { package = "md-5", version = "0.10.0" }

View file

@ -462,7 +462,7 @@ impl InlineAsmRegClass {
}
/// Returns a suggested template modifier to use for this type and an
/// example of a register named formatted with it.
/// example of a register named formatted with it.
///
/// Such suggestions are useful if a type smaller than the full register
/// size is used and a modifier can be used to point to the subregister of

View file

@ -2,8 +2,8 @@
use super::infcx_ext::InferCtxtExt;
use super::{
fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
EvalCtxt, Goal,
instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, EvalCtxt,
Goal,
};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
@ -121,11 +121,8 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
// canonical wrt the caller.
for Candidate { source, result } in normalized_candidates {
self.infcx.probe(|_| {
let candidate_certainty = fixme_instantiate_canonical_query_response(
&self.infcx,
&orig_values,
result,
);
let candidate_certainty =
instantiate_canonical_query_response(&self.infcx, &orig_values, result);
// FIXME: This is a bit scary if the `normalizes_to_goal` overflows.
//

View file

@ -9,11 +9,12 @@
//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
//! before then or if I still haven't done that before January 2023.
use super::overflow::OverflowData;
use super::CanonicalGoal;
use super::{CanonicalGoal, Certainty, MaybeCause, Response};
use super::{EvalCtxt, QueryResult};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
use rustc_middle::ty::{self, TyCtxt};
use std::{cmp::Ordering, collections::hash_map::Entry};
#[derive(Debug, Clone)]
@ -111,11 +112,11 @@ impl<'tcx> EvalCtxt<'tcx> {
// No entry, simply push this goal on the stack after dealing with overflow.
Entry::Vacant(v) => {
if self.overflow_data.has_overflow(cache.stack.len()) {
return Err(self.deal_with_overflow());
return Err(self.deal_with_overflow(goal));
}
v.insert(ProvisionalEntry {
response: fixme_response_yes_no_constraints(),
response: response_no_constraints(self.tcx, goal, Certainty::Yes),
depth: cache.stack.len(),
});
cache.stack.push(StackElem { goal, has_been_used: false });
@ -150,7 +151,11 @@ impl<'tcx> EvalCtxt<'tcx> {
{
Err(entry.response)
} else {
Err(fixme_response_maybe_no_constraints())
Err(response_no_constraints(
self.tcx,
goal,
Certainty::Maybe(MaybeCause::Ambiguity),
))
}
}
}
@ -248,10 +253,39 @@ impl<'tcx> EvalCtxt<'tcx> {
}
}
fn fixme_response_yes_no_constraints<'tcx>() -> QueryResult<'tcx> {
unimplemented!()
}
pub(super) fn response_no_constraints<'tcx>(
tcx: TyCtxt<'tcx>,
goal: Canonical<'tcx, impl Sized>,
certainty: Certainty,
) -> QueryResult<'tcx> {
let var_values = goal
.variables
.iter()
.enumerate()
.map(|(i, info)| match info.kind {
CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
}
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(i),
kind: ty::BrAnon(i as u32, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
.mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
.into(),
})
.collect();
fn fixme_response_maybe_no_constraints<'tcx>() -> QueryResult<'tcx> {
unimplemented!()
Ok(Canonical {
max_universe: goal.max_universe,
variables: goal.variables,
value: Response {
var_values: CanonicalVarValues { var_values },
external_constraints: Default::default(),
certainty,
},
})
}

View file

@ -62,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
let mut errors = Vec::new();
for i in 0.. {
if !infcx.tcx.recursion_limit().value_within_limit(i) {
unimplemented!("overflow")
unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
}
let mut has_changed = false;

View file

@ -19,15 +19,19 @@
use std::mem;
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::Obligation;
use rustc_middle::infer::canonical::Certainty as OldCertainty;
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
use rustc_span::DUMMY_SP;
use crate::traits::ObligationCause;
use self::cache::response_no_constraints;
use self::infcx_ext::InferCtxtExt;
mod assembly;
@ -119,7 +123,7 @@ pub enum MaybeCause {
}
/// Additional constraints returned on success.
#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
pub struct ExternalConstraints<'tcx> {
// FIXME: implement this.
regions: (),
@ -175,7 +179,7 @@ impl<'tcx> EvalCtxt<'tcx> {
let canonical_response = self.evaluate_canonical_goal(canonical_goal)?;
Ok((
true, // FIXME: check whether `var_values` are an identity substitution.
fixme_instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
))
}
@ -208,7 +212,8 @@ impl<'tcx> EvalCtxt<'tcx> {
// of `PredicateKind` this is the case and it is and faster than instantiating and
// recanonicalizing.
let Goal { param_env, predicate } = canonical_goal.value;
if let Some(kind) = predicate.kind().no_bound_vars() {
if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) {
match kind {
ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
@ -234,7 +239,10 @@ impl<'tcx> EvalCtxt<'tcx> {
| ty::PredicateKind::ConstEvaluatable(_)
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::TypeWellFormedFromEnv(_)
| ty::PredicateKind::Ambiguous => unimplemented!(),
| ty::PredicateKind::Ambiguous => {
// FIXME
response_no_constraints(self.tcx, canonical_goal, Certainty::Yes)
}
}
} else {
let (infcx, goal, var_values) =
@ -248,16 +256,18 @@ impl<'tcx> EvalCtxt<'tcx> {
fn compute_type_outlives_goal(
&mut self,
_goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
) -> QueryResult<'tcx> {
todo!()
// FIXME
response_no_constraints(self.tcx, goal, Certainty::Yes)
}
fn compute_region_outlives_goal(
&mut self,
_goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
) -> QueryResult<'tcx> {
todo!()
// FIXME
response_no_constraints(self.tcx, goal, Certainty::Yes)
}
}
@ -300,10 +310,27 @@ impl<'tcx> EvalCtxt<'tcx> {
}
}
fn fixme_instantiate_canonical_query_response<'tcx>(
_: &InferCtxt<'tcx>,
_: &OriginalQueryValues<'tcx>,
_: CanonicalResponse<'tcx>,
fn instantiate_canonical_query_response<'tcx>(
infcx: &InferCtxt<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
response: CanonicalResponse<'tcx>,
) -> Certainty {
unimplemented!()
let Ok(InferOk { value, obligations }) = infcx
.instantiate_query_response_and_region_obligations(
&ObligationCause::dummy(),
ty::ParamEnv::empty(),
original_values,
&response.unchecked_map(|resp| QueryResponse {
var_values: resp.var_values,
region_constraints: QueryRegionConstraints::default(),
certainty: match resp.certainty {
Certainty::Yes => OldCertainty::Proven,
Certainty::Maybe(_) => OldCertainty::Ambiguous,
},
opaque_types: resp.external_constraints.opaque_types,
value: resp.certainty,
}),
) else { bug!(); };
assert!(obligations.is_empty());
value
}

View file

@ -1,7 +1,9 @@
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::traits::query::NoSolution;
use rustc_middle::ty::TyCtxt;
use rustc_session::Limit;
use super::cache::response_no_constraints;
use super::{Certainty, EvalCtxt, MaybeCause, QueryResult};
/// When detecting a solver overflow, we return ambiguity. Overflow can be
@ -49,9 +51,12 @@ impl OverflowData {
}
impl<'tcx> EvalCtxt<'tcx> {
pub(super) fn deal_with_overflow(&mut self) -> QueryResult<'tcx> {
pub(super) fn deal_with_overflow(
&mut self,
goal: Canonical<'tcx, impl Sized>,
) -> QueryResult<'tcx> {
self.overflow_data.deal_with_overflow();
fixme_response_overflow_no_constraints()
response_no_constraints(self.tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
}
/// A `while`-loop which tracks overflow.
@ -74,7 +79,3 @@ impl<'tcx> EvalCtxt<'tcx> {
Ok(Certainty::Maybe(MaybeCause::Overflow))
}
}
fn fixme_response_overflow_no_constraints<'tcx>() -> QueryResult<'tcx> {
unimplemented!()
}

View file

@ -110,7 +110,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
) {
let tcx = acx.cx.tcx;
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))

View file

@ -73,7 +73,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
) {
let tcx = acx.cx.tcx;
let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))

View file

@ -80,7 +80,7 @@ pub fn overlapping_impls(
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
(Some(a), Some(b)) => iter::zip(a.substs, b.substs)
(Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
.all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
(None, None) => {
let self_ty1 = tcx.type_of(impl1_def_id);
@ -126,7 +126,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
let header = ty::ImplHeader {
impl_def_id,
self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
};
@ -461,7 +461,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
// We only except this routine to be invoked on implementations
// of a trait, not inherent implementations.
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
debug!("orphan_check: trait_ref={:?}", trait_ref);
// If the *trait* is local to the crate, ok.

Some files were not shown because too many files have changed in this diff Show more