diff options
| author | bors <bors@rust-lang.org> | 2023-01-31 11:33:43 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-01-31 11:33:43 +0000 |
| commit | 0aaa9ea5c05519f8e4676333cade3183b60fcc87 (patch) | |
| tree | 34763881e535998c36985e301865ef1aeb9dbf23 | |
| parent | e57962f4f1a5424ca8dc5eaebc4d0d93b7194c22 (diff) | |
| parent | a78e178b659dc1cf29b0482c97006f2e84af8419 (diff) | |
| download | rust-0aaa9ea5c05519f8e4676333cade3183b60fcc87.tar.gz rust-0aaa9ea5c05519f8e4676333cade3183b60fcc87.zip | |
Auto merge of #2772 - RalfJung:rustup, r=RalfJung
Rustup
1501 files changed, 29958 insertions, 9789 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f77656e5c1..552680f06f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -418,14 +418,14 @@ jobs: os: windows-latest-xl - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" SCRIPT: make ci-mingw-subset-1 NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" SCRIPT: make ci-mingw-subset-2 NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 @@ -433,21 +433,21 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: dist-x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin" - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl - name: dist-i686-msvc @@ -465,7 +465,7 @@ jobs: os: windows-latest-xl - name: dist-i686-mingw env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths CUSTOM_MINGW: 1 @@ -474,7 +474,7 @@ jobs: - name: dist-x86_64-mingw env: SCRIPT: python x.py dist bootstrap --include-default-paths - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 diff --git a/Cargo.lock b/Cargo.lock index 8e1a3c57f03..b35892ccd52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,7 +351,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap 4.1.1", + "clap 4.1.4", "crates-io", "curl", "curl-sys", @@ -655,9 +655,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.1" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ "bitflags", "clap_derive 4.1.0", @@ -675,7 +675,7 @@ version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" dependencies = [ - "clap 4.1.1", + "clap 4.1.4", ] [[package]] @@ -724,7 +724,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.68" +version = "0.1.69" dependencies = [ "clippy_lints", "clippy_utils", @@ -766,7 +766,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.68" +version = "0.1.69" dependencies = [ "cargo_metadata 0.14.0", "clippy_utils", @@ -789,7 +789,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.68" +version = "0.1.69" dependencies = [ "arrayvec", "if_chain", @@ -1168,7 +1168,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69" [[package]] name = "declare_clippy_lint" -version = "0.1.68" +version = "0.1.69" dependencies = [ "itertools", "quote", @@ -1799,9 +1799,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.16.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" +checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" dependencies = [ "bitflags", "libc", @@ -2294,7 +2294,7 @@ name = "jsondoclint" version = "0.1.0" dependencies = [ "anyhow", - "clap 4.1.1", + "clap 4.1.4", "fs-err", "rustdoc-json-types", "serde", @@ -2365,9 +2365,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.14.2+1.5.1" +version = "0.14.1+1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" +checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" dependencies = [ "cc", "libc", @@ -2557,7 +2557,7 @@ dependencies = [ "ammonia", "anyhow", "chrono", - "clap 4.1.1", + "clap 4.1.4", "clap_complete", "elasticlunr-rs", "env_logger 0.10.0", @@ -3528,7 +3528,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 4.1.1", + "clap 4.1.4", "env_logger 0.7.1", "mdbook", ] @@ -3672,6 +3672,7 @@ name = "rustc_ast" version = "0.0.0" dependencies = [ "bitflags", + "memchr", "rustc_data_structures", "rustc_index", "rustc_lexer", @@ -3729,6 +3730,7 @@ name = "rustc_ast_pretty" version = "0.0.0" dependencies = [ "rustc_ast", + "rustc_parse_format", "rustc_span", ] @@ -4926,7 +4928,7 @@ dependencies = [ [[package]] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" dependencies = [ "proc-macro2", "quote", @@ -4936,7 +4938,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.1" +version = "1.5.2" dependencies = [ "annotate-snippets", "anyhow", @@ -5214,9 +5216,9 @@ checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "snap" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snapbox" diff --git a/RELEASES.md b/RELEASES.md index 2901bfcc3e3..a63d4e8a043 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,106 @@ +Version 1.67.0 (2023-01-26) +========================== + +<a id="1.67.0-Language"></a> + +Language +-------- + +- [Make `Sized` predicates coinductive, allowing cycles.](https://github.com/rust-lang/rust/pull/100386/) +- [`#[must_use]` annotations on `async fn` also affect the `Future::Output`.](https://github.com/rust-lang/rust/pull/100633/) +- [Elaborate supertrait obligations when deducing closure signatures.](https://github.com/rust-lang/rust/pull/101834/) +- [Invalid literals are no longer an error under `cfg(FALSE)`.](https://github.com/rust-lang/rust/pull/102944/) +- [Unreserve braced enum variants in value namespace.](https://github.com/rust-lang/rust/pull/103578/) + +<a id="1.67.0-Compiler"></a> + +Compiler +-------- + +- [Enable varargs support for calling conventions other than `C` or `cdecl`.](https://github.com/rust-lang/rust/pull/97971/) +- [Add new MIR constant propagation based on dataflow analysis.](https://github.com/rust-lang/rust/pull/101168/) +- [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/) +- [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/) + +Added and removed targets: + +- [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`. +- [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`. +- [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/), + `aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`. +- [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel). + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +<a id="1.67.0-Libraries"></a> + +Libraries +--------- + +- [Merge `crossbeam-channel` into `std::sync::mpsc`.](https://github.com/rust-lang/rust/pull/93563/) +- [Fix inconsistent rounding of 0.5 when formatted to 0 decimal places.](https://github.com/rust-lang/rust/pull/102935/) +- [Derive `Eq` and `Hash` for `ControlFlow`.](https://github.com/rust-lang/rust/pull/103084/) +- [Don't build `compiler_builtins` with `-C panic=abort`.](https://github.com/rust-lang/rust/pull/103786/) + +<a id="1.67.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`{integer}::checked_ilog`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog) +- [`{integer}::checked_ilog2`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog2) +- [`{integer}::checked_ilog10`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog10) +- [`{integer}::ilog`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog) +- [`{integer}::ilog2`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog2) +- [`{integer}::ilog10`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog10) +- [`NonZeroU*::ilog2`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog2) +- [`NonZeroU*::ilog10`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog10) +- [`NonZero*::BITS`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#associatedconstant.BITS) + +These APIs are now stable in const contexts: + +- [`char::from_u32`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_u32) +- [`char::from_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_digit) +- [`char::to_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_digit) +- [`core::char::from_u32`](https://doc.rust-lang.org/stable/core/char/fn.from_u32.html) +- [`core::char::from_digit`](https://doc.rust-lang.org/stable/core/char/fn.from_digit.html) + +<a id="1.67.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- + +- [The layout of `repr(Rust)` types now groups m\*2^n-sized fields with + equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/) + This is intended to be an optimization, but it is also known to increase type + sizes in a few cases for the placement of enum tags. As a reminder, the layout + of `repr(Rust)` types is an implementation detail, subject to change. +- [0.5 now rounds to 0 when formatted to 0 decimal places.](https://github.com/rust-lang/rust/pull/102935/) + This makes it consistent with the rest of floating point formatting that + rounds ties toward even digits. +- [Chains of `&&` and `||` will now drop temporaries from their sub-expressions in + evaluation order, left-to-right.](https://github.com/rust-lang/rust/pull/103293/) + Previously, it was "twisted" such that the _first_ expression dropped its + temporaries _last_, after all of the other expressions dropped in order. +- [Underscore suffixes on string literals are now a hard error.](https://github.com/rust-lang/rust/pull/103914/) + This has been a future-compatibility warning since 1.20.0. +- [Stop passing `-export-dynamic` to `wasm-ld`.](https://github.com/rust-lang/rust/pull/105405/) +- [`main` is now mangled as `__main_void` on `wasm32-wasi`.](https://github.com/rust-lang/rust/pull/105468/) +- [Cargo now emits an error if there are multiple registries in the configuration + with the same index URL.](https://github.com/rust-lang/cargo/pull/10592) + +<a id="1.67.0-Internal-Changes"></a> + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Rewrite LLVM's archive writer in Rust.](https://github.com/rust-lang/rust/pull/97485/) + Version 1.66.1 (2023-01-10) =========================== diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index f4cb459f32f..fe65ad9c6cb 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -267,6 +267,9 @@ impl TargetDataLayout { ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?, ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?, ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?, + // FIXME(erikdesjardins): we should be parsing nonzero address spaces + // this will require replacing TargetDataLayout::{pointer_size,pointer_align} + // with e.g. `fn pointer_size_in(AddressSpace)` [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => { dl.pointer_size = size(s, p)?; dl.pointer_align = align(a, p)?; @@ -861,7 +864,7 @@ pub enum Primitive { Int(Integer, bool), F32, F64, - Pointer, + Pointer(AddressSpace), } impl Primitive { @@ -872,7 +875,10 @@ impl Primitive { Int(i, _) => i.size(), F32 => Size::from_bits(32), F64 => Size::from_bits(64), - Pointer => dl.pointer_size, + // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in + // different address spaces can have different sizes + // (but TargetDataLayout doesn't currently parse that part of the DL string) + Pointer(_) => dl.pointer_size, } } @@ -883,26 +889,12 @@ impl Primitive { Int(i, _) => i.align(dl), F32 => dl.f32_align, F64 => dl.f64_align, - Pointer => dl.pointer_align, + // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in + // different address spaces can have different alignments + // (but TargetDataLayout doesn't currently parse that part of the DL string) + Pointer(_) => dl.pointer_align, } } - - // FIXME(eddyb) remove, it's trivial thanks to `matches!`. - #[inline] - pub fn is_float(self) -> bool { - matches!(self, F32 | F64) - } - - // FIXME(eddyb) remove, it's completely unused. - #[inline] - pub fn is_int(self) -> bool { - matches!(self, Int(..)) - } - - #[inline] - pub fn is_ptr(self) -> bool { - matches!(self, Pointer) - } } /// Inclusive wrap-around range of valid values, that is, if @@ -1188,7 +1180,8 @@ impl FieldsShape { /// An identifier that specifies the address space that some operation /// should operate on. Special address spaces have an effect on code generation, /// depending on the target and the address spaces it implements. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] pub struct AddressSpace(pub u32); impl AddressSpace { @@ -1468,7 +1461,6 @@ pub struct PointeeInfo { pub size: Size, pub align: Align, pub safe: Option<PointerKind>, - pub address_space: AddressSpace, } /// Used in `might_permit_raw_init` to indicate the kind of initialisation diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 9253b7e6891..10d7fa1db60 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bitflags = "1.2.1" +memchr = "2.5.0" rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9317579f70d..8ad3270c510 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -18,6 +18,7 @@ //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. +pub use crate::format::*; pub use crate::util::parser::ExprPrecedence; pub use GenericArgs::*; pub use UnsafeSource::*; @@ -1269,6 +1270,7 @@ impl Expr { ExprKind::Try(..) => ExprPrecedence::Try, ExprKind::Yield(..) => ExprPrecedence::Yield, ExprKind::Yeet(..) => ExprPrecedence::Yeet, + ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Err => ExprPrecedence::Err, } } @@ -1499,6 +1501,9 @@ pub enum ExprKind { /// with a `ByteStr` literal. IncludedBytes(Lrc<[u8]>), + /// A `format_args!()` expression. + FormatArgs(P<FormatArgs>), + /// Placeholder for an expression that wasn't syntactically well formed in some way. Err, } diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_ast/src/format.rs index 01dbffa21b8..d021bea5eca 100644 --- a/compiler/rustc_builtin_macros/src/format/ast.rs +++ b/compiler/rustc_ast/src/format.rs @@ -1,5 +1,5 @@ -use rustc_ast::ptr::P; -use rustc_ast::Expr; +use crate::ptr::P; +use crate::Expr; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -39,7 +39,7 @@ use rustc_span::Span; /// Basically the "AST" for a complete `format_args!()`. /// /// E.g., `format_args!("hello {name}");`. -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArgs { pub span: Span, pub template: Vec<FormatArgsPiece>, @@ -49,7 +49,7 @@ pub struct FormatArgs { /// A piece of a format template string. /// /// E.g. "hello" or "{name}". -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum FormatArgsPiece { Literal(Symbol), Placeholder(FormatPlaceholder), @@ -59,7 +59,7 @@ pub enum FormatArgsPiece { /// /// E.g. `1, 2, name="ferris", n=3`, /// but also implicit captured arguments like `x` in `format_args!("{x}")`. -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArguments { arguments: Vec<FormatArgument>, num_unnamed_args: usize, @@ -67,6 +67,12 @@ pub struct FormatArguments { names: FxHashMap<Symbol, usize>, } +// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930. +#[cfg(parallel_compiler)] +unsafe impl Sync for FormatArguments {} +#[cfg(parallel_compiler)] +unsafe impl Send for FormatArguments {} + impl FormatArguments { pub fn new() -> Self { Self { @@ -121,18 +127,22 @@ impl FormatArguments { &self.arguments[..self.num_explicit_args] } - pub fn into_vec(self) -> Vec<FormatArgument> { - self.arguments + pub fn all_args(&self) -> &[FormatArgument] { + &self.arguments[..] + } + + pub fn all_args_mut(&mut self) -> &mut [FormatArgument] { + &mut self.arguments[..] } } -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArgument { pub kind: FormatArgumentKind, pub expr: P<Expr>, } -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum FormatArgumentKind { /// `format_args(…, arg)` Normal, @@ -152,7 +162,7 @@ impl FormatArgumentKind { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub struct FormatPlaceholder { /// Index into [`FormatArgs::arguments`]. pub argument: FormatArgPosition, @@ -164,7 +174,7 @@ pub struct FormatPlaceholder { pub format_options: FormatOptions, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub struct FormatArgPosition { /// Which argument this position refers to (Ok), /// or would've referred to if it existed (Err). @@ -175,7 +185,7 @@ pub struct FormatArgPosition { pub span: Option<Span>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatArgPositionKind { /// `{}` or `{:.*}` Implicit, @@ -185,7 +195,7 @@ pub enum FormatArgPositionKind { Named, } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)] pub enum FormatTrait { /// `{}` Display, @@ -207,7 +217,7 @@ pub enum FormatTrait { UpperHex, } -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)] pub struct FormatOptions { /// The width. E.g. `{:5}` or `{:width$}`. pub width: Option<FormatCount>, @@ -217,11 +227,33 @@ pub struct FormatOptions { pub alignment: Option<FormatAlignment>, /// The fill character. E.g. the `.` in `{:.>10}`. pub fill: Option<char>, - /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags. - pub flags: u32, + /// The `+` or `-` flag. + pub sign: Option<FormatSign>, + /// The `#` flag. + pub alternate: bool, + /// The `0` flag. E.g. the `0` in `{:02x}`. + pub zero_pad: bool, + /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`. + pub debug_hex: Option<FormatDebugHex>, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatSign { + /// The `+` flag. + Plus, + /// The `-` flag. + Minus, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatDebugHex { + /// The `x` flag in `{:x?}`. + Lower, + /// The `X` flag in `{:X?}`. + Upper, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatAlignment { /// `{:<}` Left, @@ -231,7 +263,7 @@ pub enum FormatAlignment { Center, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` Literal(usize), diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 9c1dfeb1a61..23c32fa96ca 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -16,7 +16,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(negative_impls)] -#![feature(slice_internals)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] @@ -42,6 +41,7 @@ pub mod ast_traits; pub mod attr; pub mod entry; pub mod expand; +pub mod format; pub mod mut_visit; pub mod node_id; pub mod ptr; @@ -51,6 +51,7 @@ pub mod visit; pub use self::ast::*; pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; +pub use self::format::*; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 77f342d1eb3..1dd62626b8f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -297,6 +297,10 @@ pub trait MutVisitor: Sized { fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) { noop_visit_inline_asm_sym(sym, self) } + + fn visit_format_args(&mut self, fmt: &mut FormatArgs) { + noop_visit_format_args(fmt, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -1284,6 +1288,15 @@ pub fn noop_visit_inline_asm_sym<T: MutVisitor>( vis.visit_path(path); } +pub fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) { + for arg in fmt.arguments.all_args_mut() { + if let FormatArgumentKind::Named(name) = &mut arg.kind { + vis.visit_ident(name); + } + vis.visit_expr(&mut arg.expr); + } +} + pub fn noop_visit_expr<T: MutVisitor>( Expr { kind, id, span, attrs, tokens }: &mut Expr, vis: &mut T, @@ -1425,6 +1438,7 @@ pub fn noop_visit_expr<T: MutVisitor>( visit_opt(expr, |expr| vis.visit_expr(expr)); } ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), + ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt), ExprKind::MacCall(mac) => vis.visit_mac_call(mac), ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = se.deref_mut(); diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 4f7099c7be8..81efdaa44b3 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -271,6 +271,7 @@ pub enum ExprPrecedence { Try, InlineAsm, Mac, + FormatArgs, Array, Repeat, @@ -335,7 +336,8 @@ impl ExprPrecedence { | ExprPrecedence::Index | ExprPrecedence::Try | ExprPrecedence::InlineAsm - | ExprPrecedence::Mac => PREC_POSTFIX, + | ExprPrecedence::Mac + | ExprPrecedence::FormatArgs => PREC_POSTFIX, // Never need parens ExprPrecedence::Array diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs index 0eae791b25e..6f57d66b227 100644 --- a/compiler/rustc_ast/src/util/unicode.rs +++ b/compiler/rustc_ast/src/util/unicode.rs @@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool { // U+2069 - E2 81 A9 let mut bytes = s.as_bytes(); loop { - match core::slice::memchr::memchr(0xE2, bytes) { + match memchr::memchr(0xE2, bytes) { Some(idx) => { // bytes are valid UTF-8 -> E2 must be followed by two bytes let ch = &bytes[idx..idx + 3]; diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e8823eff83a..e7b2e4b1cb4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -242,6 +242,9 @@ pub trait Visitor<'ast>: Sized { fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) { walk_inline_asm(self, asm) } + fn visit_format_args(&mut self, fmt: &'ast FormatArgs) { + walk_format_args(self, fmt) + } fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) { walk_inline_asm_sym(self, sym) } @@ -400,8 +403,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); visitor.visit_ty(&mutable_type.ty) } - TyKind::Tup(tuple_element_types) => { - walk_list!(visitor, visit_ty, tuple_element_types); + TyKind::Tup(tys) => { + walk_list!(visitor, visit_ty, tys); } TyKind::BareFn(function_declaration) => { walk_list!(visitor, visit_generic_param, &function_declaration.generic_params); @@ -756,6 +759,15 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA visitor.visit_path(&sym.path, sym.id); } +pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) { + for arg in fmt.arguments.all_args() { + if let FormatArgumentKind::Named(name) = arg.kind { + visitor.visit_ident(name); + } + visitor.visit_expr(&arg.expr); + } +} + pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_attribute, expression.attrs.iter()); @@ -896,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::MacCall(mac) => visitor.visit_mac_call(mac), ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression), ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm), + ExprKind::FormatArgs(f) => visitor.visit_format_args(f), ExprKind::Yield(optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c3611b2f522..cc523fe7d08 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -16,7 +16,7 @@ use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; -use rustc_span::symbol::{sym, Ident}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::DUMMY_SP; use thin_vec::thin_vec; @@ -294,6 +294,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::InlineAsm(asm) => { hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) } + ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), ExprKind::Struct(se) => { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), @@ -1735,7 +1736,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::DropTemps(expr)) } - fn expr_match( + pub(super) fn expr_match( &mut self, span: Span, arg: &'hir hir::Expr<'hir>, @@ -1763,7 +1764,44 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - fn expr_call_mut( + pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + self.expr( + sp, + hir::ExprKind::Lit(hir::Lit { + span: sp, + node: ast::LitKind::Int( + value as u128, + ast::LitIntType::Unsigned(ast::UintTy::Usize), + ), + }), + ) + } + + pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { + self.expr( + sp, + hir::ExprKind::Lit(hir::Lit { + span: sp, + node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)), + }), + ) + } + + pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { + self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) })) + } + + pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> { + self.expr( + sp, + hir::ExprKind::Lit(hir::Lit { + span: sp, + node: ast::LitKind::Str(value, ast::StrStyle::Cooked), + }), + ) + } + + pub(super) fn expr_call_mut( &mut self, span: Span, e: &'hir hir::Expr<'hir>, @@ -1772,7 +1810,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Call(e, args)) } - fn expr_call( + pub(super) fn expr_call( &mut self, span: Span, e: &'hir hir::Expr<'hir>, @@ -1814,6 +1852,27 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + /// `<LangItem>::name` + pub(super) fn expr_lang_item_type_relative( + &mut self, + span: Span, + lang_item: hir::LangItem, + name: Symbol, + ) -> hir::Expr<'hir> { + let path = hir::ExprKind::Path(hir::QPath::TypeRelative( + self.arena.alloc(self.ty( + span, + hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), None)), + )), + self.arena.alloc(hir::PathSegment::new( + Ident::new(name, span), + self.next_id(), + Res::Err, + )), + )); + self.expr(span, path) + } + pub(super) fn expr_ident( &mut self, sp: Span, @@ -1872,12 +1931,25 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(b.span, hir::ExprKind::Block(b, None)) } + pub(super) fn expr_array_ref( + &mut self, + span: Span, + elements: &'hir [hir::Expr<'hir>], + ) -> hir::Expr<'hir> { + let addrof = hir::ExprKind::AddrOf( + hir::BorrowKind::Ref, + hir::Mutability::Not, + self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))), + ); + self.expr(span, addrof) + } + pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> { let hir_id = self.next_id(); hir::Expr { hir_id, kind, span: self.lower_span(span) } } - fn expr_field( + pub(super) fn expr_field( &mut self, ident: Ident, expr: &'hir hir::Expr<'hir>, @@ -1892,7 +1964,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> { + pub(super) fn arm( + &mut self, + pat: &'hir hir::Pat<'hir>, + expr: &'hir hir::Expr<'hir>, + ) -> hir::Arm<'hir> { hir::Arm { hir_id: self.next_id(), pat, diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs new file mode 100644 index 00000000000..e7dd0b18a03 --- /dev/null +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -0,0 +1,398 @@ +use super::LoweringContext; +use rustc_ast as ast; +use rustc_ast::visit::{self, Visitor}; +use rustc_ast::*; +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; +use rustc_span::{ + sym, + symbol::{kw, Ident}, + Span, +}; + +impl<'hir> LoweringContext<'_, 'hir> { + pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> { + expand_format_args(self, sp, fmt) + } +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum ArgumentType { + Format(FormatTrait), + Usize, +} + +/// Generate a hir expression representing an argument to a format_args invocation. +/// +/// Generates: +/// +/// ```text +/// <core::fmt::ArgumentV1>::new_…(arg) +/// ``` +fn make_argument<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + sp: Span, + arg: &'hir hir::Expr<'hir>, + ty: ArgumentType, +) -> hir::Expr<'hir> { + use ArgumentType::*; + use FormatTrait::*; + let new_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatArgument, + match ty { + Format(Display) => sym::new_display, + Format(Debug) => sym::new_debug, + Format(LowerExp) => sym::new_lower_exp, + Format(UpperExp) => sym::new_upper_exp, + Format(Octal) => sym::new_octal, + Format(Pointer) => sym::new_pointer, + Format(Binary) => sym::new_binary, + Format(LowerHex) => sym::new_lower_hex, + Format(UpperHex) => sym::new_upper_hex, + Usize => sym::from_usize, + }, + )); + ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg)) +} + +/// Generate a hir expression for a format_args Count. +/// +/// Generates: +/// +/// ```text +/// <core::fmt::rt::v1::Count>::Is(…) +/// ``` +/// +/// or +/// +/// ```text +/// <core::fmt::rt::v1::Count>::Param(…) +/// ``` +/// +/// or +/// +/// ```text +/// <core::fmt::rt::v1::Count>::Implied +/// ``` +fn make_count<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + sp: Span, + count: &Option<FormatCount>, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, +) -> hir::Expr<'hir> { + match count { + Some(FormatCount::Literal(n)) => { + let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatCount, + sym::Is, + )); + let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]); + ctx.expr_call_mut(sp, count_is, value) + } + Some(FormatCount::Argument(arg)) => { + if let Ok(arg_index) = arg.index { + let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); + let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatCount, + sym::Param, + )); + let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]); + ctx.expr_call_mut(sp, count_param, value) + } else { + ctx.expr(sp, hir::ExprKind::Err) + } + } + None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied), + } +} + +/// Generate a hir expression for a format_args placeholder specification. +/// +/// Generates +/// +/// ```text +/// <core::fmt::rt::v1::Argument::new( +/// …usize, // position +/// '…', // fill +/// <core::fmt::rt::v1::Alignment>::…, // alignment +/// …u32, // flags +/// <core::fmt::rt::v1::Count::…>, // width +/// <core::fmt::rt::v1::Count::…>, // precision +/// ) +/// ``` +fn make_format_spec<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + sp: Span, + placeholder: &FormatPlaceholder, + argmap: &mut FxIndexSet<(usize, ArgumentType)>, +) -> hir::Expr<'hir> { + let position = match placeholder.argument.index { + Ok(arg_index) => { + let (i, _) = + argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); + ctx.expr_usize(sp, i) + } + Err(_) => ctx.expr(sp, hir::ExprKind::Err), + }; + let &FormatOptions { + ref width, + ref precision, + alignment, + fill, + sign, + alternate, + zero_pad, + debug_hex, + } = &placeholder.format_options; + let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); + let align = ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatAlignment, + match alignment { + Some(FormatAlignment::Left) => sym::Left, + Some(FormatAlignment::Right) => sym::Right, + Some(FormatAlignment::Center) => sym::Center, + None => sym::Unknown, + }, + ); + // This needs to match `FlagV1` in library/core/src/fmt/mod.rs. + let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) + | ((sign == Some(FormatSign::Minus)) as u32) << 1 + | (alternate as u32) << 2 + | (zero_pad as u32) << 3 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; + let flags = ctx.expr_u32(sp, flags); + let precision = make_count(ctx, sp, &precision, argmap); + let width = make_count(ctx, sp, &width, argmap); + let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + sp, + hir::LangItem::FormatPlaceholder, + sym::new, + )); + let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]); + ctx.expr_call_mut(sp, format_placeholder_new, args) +} + +fn expand_format_args<'hir>( + ctx: &mut LoweringContext<'_, 'hir>, + macsp: Span, + fmt: &FormatArgs, +) -> hir::ExprKind<'hir> { + let lit_pieces = + ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| { + match piece { + &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)), + &FormatArgsPiece::Placeholder(_) => { + // Inject empty string before placeholders when not already preceded by a literal piece. + if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { + Some(ctx.expr_str(fmt.span, kw::Empty)) + } else { + None + } + } + } + })); + let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces); + + // Whether we'll use the `Arguments::new_v1_formatted` form (true), + // or the `Arguments::new_v1` form (false). + let mut use_format_options = false; + + // Create a list of all _unique_ (argument, format trait) combinations. + // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] + let mut argmap = FxIndexSet::default(); + for piece in &fmt.template { + let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; + if placeholder.format_options != Default::default() { + // Can't use basic form if there's any formatting options. + use_format_options = true; + } + if let Ok(index) = placeholder.argument.index { + if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) { + // Duplicate (argument, format trait) combination, + // which we'll only put once in the args array. + use_format_options = true; + } + } + } + + let format_options = use_format_options.then(|| { + // Generate: + // &[format_spec_0, format_spec_1, format_spec_2] + let elements: Vec<_> = fmt + .template + .iter() + .filter_map(|piece| { + let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; + Some(make_format_spec(ctx, macsp, placeholder, &mut argmap)) + }) + .collect(); + ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) + }); + + let arguments = fmt.arguments.all_args(); + + // If the args array contains exactly all the original arguments once, + // in order, we can use a simple array instead of a `match` construction. + // However, if there's a yield point in any argument except the first one, + // we don't do this, because an ArgumentV1 cannot be kept across yield points. + // + // This is an optimization, speeding up compilation about 1-2% in some cases. + // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609 + let use_simple_array = argmap.len() == arguments.len() + && argmap.iter().enumerate().all(|(i, &(j, _))| i == j) + && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); + + let args = if use_simple_array { + // Generate: + // &[ + // <core::fmt::ArgumentV1>::new_display(&arg0), + // <core::fmt::ArgumentV1>::new_lower_hex(&arg1), + // <core::fmt::ArgumentV1>::new_debug(&arg2), + // … + // ] + let elements: Vec<_> = arguments + .iter() + .zip(argmap) + .map(|(arg, (_, ty))| { + let sp = arg.expr.span.with_ctxt(macsp.ctxt()); + let arg = ctx.lower_expr(&arg.expr); + let ref_arg = ctx.arena.alloc(ctx.expr( + sp, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), + )); + make_argument(ctx, sp, ref_arg, ty) + }) + .collect(); + ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements)) + } else { + // Generate: + // &match (&arg0, &arg1, &…) { + // args => [ + // <core::fmt::ArgumentV1>::new_display(args.0), + // <core::fmt::ArgumentV1>::new_lower_hex(args.1), + // <core::fmt::ArgumentV1>::new_debug(args.0), + // … + // ] + // } + let args_ident = Ident::new(sym::args, macsp); + let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); + let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| { + if let Some(arg) = arguments.get(arg_index) { + let sp = arg.expr.span.with_ctxt(macsp.ctxt()); + let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id); + let arg = ctx.arena.alloc(ctx.expr( + sp, + hir::ExprKind::Field( + args_ident_expr, + Ident::new(sym::integer(arg_index), macsp), + ), + )); + make_argument(ctx, sp, arg, ty) + } else { + ctx.expr(macsp, hir::ExprKind::Err) + } + })); + let elements: Vec<_> = arguments + .iter() + .map(|arg| { + let arg_expr = ctx.lower_expr(&arg.expr); + ctx.expr( + arg.expr.span.with_ctxt(macsp.ctxt()), + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr), + ) + }) + .collect(); + let args_tuple = ctx + .arena + .alloc(ctx.expr(macsp, hir::ExprKind::Tup(ctx.arena.alloc_from_iter(elements)))); + let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); + let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]); + let match_expr = ctx.arena.alloc(ctx.expr_match( + macsp, + args_tuple, + match_arms, + hir::MatchSource::FormatArgs, + )); + ctx.expr( + macsp, + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr), + ) + }; + + if let Some(format_options) = format_options { + // Generate: + // <core::fmt::Arguments>::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // unsafe { ::core::fmt::UnsafeArg::new() } + // ) + let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatArguments, + sym::new_v1_formatted, + )); + let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatUnsafeArg, + sym::new, + )); + let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]); + let hir_id = ctx.next_id(); + let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block { + stmts: &[], + expr: Some(unsafe_arg_new_call), + hir_id, + rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated), + span: macsp, + targeted_by_break: false, + })); + let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]); + hir::ExprKind::Call(new_v1_formatted, args) + } else { + // Generate: + // <core::fmt::Arguments>::new_v1( + // lit_pieces, + // args, + // ) + let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative( + macsp, + hir::LangItem::FormatArguments, + sym::new_v1, + )); + let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]); + hir::ExprKind::Call(new_v1, new_args) + } +} + +fn may_contain_yield_point(e: &ast::Expr) -> bool { + struct MayContainYieldPoint(bool); + + impl Visitor<'_> for MayContainYieldPoint { + fn visit_expr(&mut self, e: &ast::Expr) { + if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { + self.0 = true; + } else { + visit::walk_expr(self, e); + } + } + + fn visit_mac_call(&mut self, _: &ast::MacCall) { + // Macros should be expanded at this point. + unreachable!("unexpanded macro in ast lowering"); + } + + fn visit_item(&mut self, _: &ast::Item) { + // Do not recurse into nested items. + } + } + + let mut visitor = MayContainYieldPoint(false); + visitor.visit_expr(e); + visitor.0 +} diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 63033085bec..f7fe0d771a1 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -275,19 +275,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'hir>, - fd: &'hir FnDecl<'hir>, - b: BodyId, - _: Span, - id: HirId, - ) { - assert_eq!(self.owner, id.owner); - assert_eq!(self.parent_node, id.local_id); - intravisit::walk_fn(self, fk, fd, b, id); - } - fn visit_block(&mut self, block: &'hir Block<'hir>) { self.insert(block.span, block.hir_id, Node::Block(block)); self.with_parent(block.hir_id, |this| { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5d2589cb2b2..2865082bd7a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -67,7 +67,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { current_hir_id_owner: hir::CRATE_OWNER_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_local_id: Default::default(), - local_id_to_def_id: SortedMap::new(), trait_map: Default::default(), // Lowering state. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bc6d2cf12c7..a04a2595293 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -80,6 +80,7 @@ mod asm; mod block; mod errors; mod expr; +mod format; mod index; mod item; mod lifetime_collector; @@ -118,7 +119,6 @@ struct LoweringContext<'a, 'hir> { current_hir_id_owner: hir::OwnerId, item_local_id_counter: hir::ItemLocalId, - local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>, impl_trait_defs: Vec<hir::GenericParam<'hir>>, @@ -416,6 +416,7 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; + tcx.ensure().output_filenames(()); let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); @@ -565,7 +566,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); - let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); @@ -592,7 +592,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; self.node_id_to_local_id = current_node_ids; - self.local_id_to_def_id = current_id_to_def_id; self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; @@ -627,7 +626,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); - let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let trait_map = std::mem::take(&mut self.trait_map); #[cfg(debug_assertions)] @@ -643,13 +641,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); let (nodes, parenting) = index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); - let nodes = hir::OwnerNodes { - hash_including_bodies, - hash_without_bodies, - nodes, - bodies, - local_id_to_def_id, - }; + let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; let attrs = { let hash = self.tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); @@ -708,7 +700,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { assert_ne!(local_id, hir::ItemLocalId::new(0)); if let Some(def_id) = self.opt_local_def_id(ast_node_id) { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.local_id_to_def_id.insert(local_id, def_id); } if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index a3e3e823b08..b4900dc39a8 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" [lib] [dependencies] -rustc_span = { path = "../rustc_span" } rustc_ast = { path = "../rustc_ast" } +rustc_parse_format = { path = "../rustc_parse_format" } +rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 2a18e5164a3..cacfe9eb2f1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -6,6 +6,11 @@ use rustc_ast::token; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{self as ast, BlockCheckMode}; +use rustc_ast::{ + FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign, + FormatTrait, +}; +use std::fmt::Write; impl<'a> State<'a> { fn print_else(&mut self, els: Option<&ast::Expr>) { @@ -527,9 +532,23 @@ impl<'a> State<'a> { } } ast::ExprKind::InlineAsm(a) => { + // FIXME: This should have its own syntax, distinct from a macro invocation. self.word("asm!"); self.print_inline_asm(a); } + ast::ExprKind::FormatArgs(fmt) => { + // FIXME: This should have its own syntax, distinct from a macro invocation. + self.word("format_args!"); + self.popen(); + self.rbox(0, Inconsistent); + self.word(reconstruct_format_args_template_string(&fmt.template)); + for arg in fmt.arguments.all_args() { + self.word_space(","); + self.print_expr(&arg.expr); + } + self.end(); + self.pclose(); + } ast::ExprKind::MacCall(m) => self.print_mac(m), ast::ExprKind::Paren(e) => { self.popen(); @@ -629,3 +648,88 @@ impl<'a> State<'a> { } } } + +pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String { + let mut template = "\"".to_string(); + for piece in pieces { + match piece { + FormatArgsPiece::Literal(s) => { + for c in s.as_str().escape_debug() { + template.push(c); + if let '{' | '}' = c { + template.push(c); + } + } + } + FormatArgsPiece::Placeholder(p) => { + template.push('{'); + let (Ok(n) | Err(n)) = p.argument.index; + write!(template, "{n}").unwrap(); + if p.format_options != Default::default() || p.format_trait != FormatTrait::Display + { + template.push_str(":"); + } + if let Some(fill) = p.format_options.fill { + template.push(fill); + } + match p.format_options.alignment { + Some(FormatAlignment::Left) => template.push_str("<"), + Some(FormatAlignment::Right) => template.push_str(">"), + Some(FormatAlignment::Center) => template.push_str("^"), + None => {} + } + match p.format_options.sign { + Some(FormatSign::Plus) => template.push('+'), + Some(FormatSign::Minus) => template.push('-'), + None => {} + } + if p.format_options.alternate { + template.push('#'); + } + if p.format_options.zero_pad { + template.push('0'); + } + if let Some(width) = &p.format_options.width { + match width { + FormatCount::Literal(n) => write!(template, "{n}").unwrap(), + FormatCount::Argument(FormatArgPosition { + index: Ok(n) | Err(n), .. + }) => { + write!(template, "{n}$").unwrap(); + } + } + } + if let Some(precision) = &p.format_options.precision { + template.push('.'); + match precision { + FormatCount::Literal(n) => write!(template, "{n}").unwrap(), + FormatCount::Argument(FormatArgPosition { + index: Ok(n) | Err(n), .. + }) => { + write!(template, "{n}$").unwrap(); + } + } + } + match p.format_options.debug_hex { + Some(FormatDebugHex::Lower) => template.push('x'), + Some(FormatDebugHex::Upper) => template.push('X'), + None => {} + } + template.push_str(match p.format_trait { + FormatTrait::Display => "", + FormatTrait::Debug => "?", + FormatTrait::LowerExp => "e", + FormatTrait::UpperExp => "E", + FormatTrait::Octal => "o", + FormatTrait::Pointer => "p", + FormatTrait::Binary => "b", + FormatTrait::LowerHex => "x", + FormatTrait::UpperHex => "X", + }); + template.push('}'); + } + } + } + template.push('"'); + template +} diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index a4943d11204..2bbb9618dbf 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -37,7 +37,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc, ); - err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc)); + err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc)); err.span_label(span, format!("use of borrowed {}", borrow_desc)); err } @@ -250,8 +250,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc, ); - err.span_label(borrow_span, format!("borrow of {} occurs here", desc)); - err.span_label(span, format!("assignment to borrowed {} occurs here", desc)); + err.span_label(borrow_span, format!("{} is borrowed here", desc)); + err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc)); err } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 8c4885770ad..2821677c537 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -393,6 +393,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Coverage(..) | mir::StatementKind::Intrinsic(..) + | mir::StatementKind::ConstEvalCounter | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e5a36259fa4..50c0faf4597 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -766,7 +766,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); let cause = ObligationCause::new( span, - self.mir_hir_id(), + self.mir_def_id(), rustc_infer::traits::ObligationCauseCode::MiscObligation, ); let errors = rustc_trait_selection::traits::fully_solve_bound( @@ -1736,7 +1736,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self.local_names, &mut err, "", - None, + Some(borrow_span), None, ); } @@ -2599,7 +2599,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match ty.kind() { ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( self.mir_def_id(), - self.infcx.tcx.fn_sig(self.mir_def_id()), + self.infcx.tcx.fn_sig(self.mir_def_id()).subst_identity(), ), _ => None, } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2095747097b..19855075ced 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,6 +1,8 @@ //! Print diagnostics to explain why values are borrowed. use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir as hir; +use rustc_hir::intravisit::Visitor; use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ @@ -11,6 +13,7 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; +use rustc_trait_selection::traits::error_reporting::FindExprBySpan; use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ @@ -63,6 +66,36 @@ impl<'tcx> BorrowExplanation<'tcx> { borrow_span: Option<Span>, multiple_borrow_span: Option<(Span, Span)>, ) { + if let Some(span) = borrow_span { + let def_id = body.source.def_id(); + if let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(body_id) = node.body_id() + { + let body = tcx.hir().body(body_id); + let mut expr_finder = FindExprBySpan::new(span); + expr_finder.visit_expr(body.value); + if let Some(mut expr) = expr_finder.result { + while let hir::ExprKind::AddrOf(_, _, inner) + | hir::ExprKind::Unary(hir::UnOp::Deref, inner) + | hir::ExprKind::Field(inner, _) + | hir::ExprKind::MethodCall(_, inner, _, _) + | hir::ExprKind::Index(inner, _) = &expr.kind + { + expr = inner; + } + if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind + && let [hir::PathSegment { ident, args: None, .. }] = p.segments + && let hir::def::Res::Local(hir_id) = p.res + && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id) + { + err.span_label( + pat.span, + &format!("binding `{ident}` declared here"), + ); + } + } + } + } match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { let message = match later_use_kind { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1b40b7143cb..8c579bac7e8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - CallKind::Normal { self_arg, desugaring, method_did } => { + CallKind::Normal { self_arg, desugaring, method_did, method_substs } => { let self_arg = self_arg.unwrap(); let tcx = self.infcx.tcx; if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { @@ -1128,15 +1128,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "{place_name} {partially_str}moved due to this method call{loop_message}", ), ); + let infcx = tcx.infer_ctxt().build(); + // Erase and shadow everything that could be passed to the new infcx. let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty); + let method_substs = tcx.erase_regions(method_substs); + if let ty::Adt(def, substs) = ty.kind() && Some(def.did()) == tcx.lang_items().pin_type() && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind() && let self_ty = infcx.replace_bound_vars_with_fresh_vars( fn_call_span, LateBoundRegionConversionTime::FnCall, - tcx.fn_sig(method_did).input(0), + tcx.fn_sig(method_did).subst(tcx, method_substs).input(0), ) && infcx.can_eq(self.param_env, ty, self_ty).is_ok() { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 6db3c858ae7..ea58ad5ae3e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -448,7 +448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); - use_spans.args_span_label(err, format!("move out of {place_desc} occurs here")); + use_spans.args_span_label(err, format!("{place_desc} is moved here")); } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 187861ba127..87db08ef5b5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -813,17 +813,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if *outlived_f != ty::ReStatic { return; } + let suitable_region = self.infcx.tcx.is_suitable_region(f); + let Some(suitable_region) = suitable_region else { return; }; - let fn_returns = self - .infcx - .tcx - .is_suitable_region(f) - .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id)) - .unwrap_or_default(); - - if fn_returns.is_empty() { - return; - } + let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id); let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) { param @@ -839,15 +832,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; let captures = format!("captures data from {arg}"); - return nice_region_error::suggest_new_region_bound( - self.infcx.tcx, - diag, - fn_returns, - lifetime.to_string(), - Some(arg), - captures, - Some((param.param_ty_span, param.param_ty.to_string())), - self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id), + if !fn_returns.is_empty() { + nice_region_error::suggest_new_region_bound( + self.infcx.tcx, + diag, + fn_returns, + lifetime.to_string(), + Some(arg), + captures, + Some((param.param_ty_span, param.param_ty.to_string())), + Some(suitable_region.def_id), + ); + return; + } + + let Some((alias_tys, alias_span)) = self + .infcx + .tcx + .return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; }; + + // in case the return type of the method is a type alias + let mut spans_suggs: Vec<_> = Vec::new(); + for alias_ty in alias_tys { + if alias_ty.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + () + } + if let TyKind::TraitObject(_, lt, _) = alias_ty.kind { + spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); + } + } + spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string())); + diag.multipart_suggestion_verbose( + &format!( + "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias" + ), + spans_suggs, + Applicability::MaybeIncorrect, ); } } diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 6fd9290058c..6217676d5c1 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -91,7 +91,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { LocalMutationIsAllowed::Yes, ); } - StatementKind::Nop + StatementKind::ConstEvalCounter + | StatementKind::Nop | StatementKind::Retag { .. } | StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 73ea7314b75..bc81abe4005 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -609,7 +609,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx StatementKind::AscribeUserType(..) // Doesn't have any language semantics | StatementKind::Coverage(..) - // Does not actually affect borrowck + // These do not actually affect borrowck + | StatementKind::ConstEvalCounter | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 238172ea399..2ae13990a45 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_errors::Diagnostic; use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_hir::CRATE_HIR_ID; use rustc_index::vec::IndexVec; use rustc_infer::infer::outlives::test_type_match; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; @@ -2022,7 +2021,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|constraint| BlameConstraint { category: constraint.category, from_closure: constraint.from_closure, - cause: ObligationCause::new(constraint.span, CRATE_HIR_ID, cause_code.clone()), + cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()), variance_info: constraint.variance_info, outlives_constraint: *constraint, }) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index db5a67a8b44..e0e814cfc0a 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -273,7 +273,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // This logic duplicates most of `check_opaque_meets_bounds`. // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id); // HACK This bubble is required for this tests to pass: // type-alias-impl-trait/issue-67844-nested-opaque.rs let infcx = @@ -290,7 +289,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // the bounds that the function supplies. let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs); if let Err(err) = ocx.eq( - &ObligationCause::misc(instantiated_ty.span, body_id), + &ObligationCause::misc(instantiated_ty.span, def_id), param_env, opaque_ty, definition_ty, @@ -298,7 +297,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { infcx .err_ctxt() .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), + &ObligationCause::misc(instantiated_ty.span, def_id), opaque_ty, definition_ty, err, @@ -309,7 +308,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { ocx.register_obligation(Obligation::misc( infcx.tcx, instantiated_ty.span, - body_id, + def_id, param_env, predicate, )); @@ -368,18 +367,6 @@ fn check_opaque_type_parameter_valid( for (i, arg) in opaque_type_key.substs.iter().enumerate() { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if lt.is_static() => { - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_label( - tcx.def_span(opaque_generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - return false; - } GenericArgKind::Lifetime(lt) => { matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 81bd4c2a783..06087b0c579 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1258,6 +1258,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | StatementKind::StorageDead(..) | StatementKind::Retag { .. } | StatementKind::Coverage(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 8bff66f8d5c..5380913f5c8 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -472,7 +472,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // C-variadic fns also have a `VaList` input that's not listed in the signature // (as it's created inside the body itself, not passed in from outside). if let DefiningTy::FnDef(def_id, _) = defining_ty { - if self.infcx.tcx.fn_sig(def_id).c_variadic() { + if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { let va_list_did = self.infcx.tcx.require_lang_item( LangItem::VaList, Some(self.infcx.tcx.def_span(self.mir_def.did)), @@ -665,7 +665,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } DefiningTy::FnDef(def_id, _) => { - let sig = tcx.fn_sig(def_id); + let sig = tcx.fn_sig(def_id).subst_identity(); let sig = indices.fold_to_region_vids(tcx, sig); sig.inputs_and_output() } diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 93b07801e03..342b1735661 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Continue(_) | ExprKind::Err | ExprKind::Field(_, _) + | ExprKind::FormatArgs(_) | ExprKind::ForLoop(_, _, _, _) | ExprKind::If(_, _, _) | ExprKind::IncludedBytes(..) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 240167146e1..0481a118906 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -17,6 +17,7 @@ pub fn expand_deriving_copy( span, path: path_std!(marker::Copy), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: true, methods: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index ef5a75f428d..42f50d8ade2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -73,6 +73,7 @@ pub fn expand_deriving_clone( span, path: path_std!(clone::Clone), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: bounds, supports_unions: true, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 3e994f037ad..424719f9795 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -27,6 +27,7 @@ pub fn expand_deriving_eq( span, path: path_std!(cmp::Eq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: true, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index a926fca4e65..671f32550d2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -20,6 +20,7 @@ pub fn expand_deriving_ord( span, path: path_std!(cmp::Ord), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 9051fe0b28a..88d454fbc11 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -84,6 +84,7 @@ pub fn expand_deriving_partial_eq( span, path: path_std!(cmp::PartialEq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index c9dc8921262..bcc90442eb7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::MetaItem; +use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -21,6 +21,27 @@ pub fn expand_deriving_partial_ord( let attrs = thin_vec![cx.attr_word(sym::inline, span)]; + // Order in which to perform matching + let tag_then_data = if let Annotatable::Item(item) = item + && let ItemKind::Enum(def, _) = &item.kind { + let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); + match dataful.iter().filter(|&&b| b).count() { + // No data, placing the tag check first makes codegen simpler + 0 => true, + 1..=2 => false, + _ => { + (0..dataful.len()-1).any(|i| { + if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) { + idx >= 2 + } else { + false + } + }) + } + } + } else { + true + }; let partial_cmp_def = MethodDef { name: sym::partial_cmp, generics: Bounds::empty(), @@ -30,7 +51,7 @@ pub fn expand_deriving_partial_ord( attributes: attrs, fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) + cs_partial_cmp(cx, span, substr, tag_then_data) })), }; @@ -38,6 +59,7 @@ pub fn expand_deriving_partial_ord( span, path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: vec![], supports_unions: false, methods: vec![partial_cmp_def], @@ -47,7 +69,12 @@ pub fn expand_deriving_partial_ord( trait_def.expand(cx, mitem, item, push) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { +fn cs_partial_cmp( + cx: &mut ExtCtxt<'_>, + span: Span, + substr: &Substructure<'_>, + tag_then_data: bool, +) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); @@ -74,12 +101,50 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_ let args = vec![field.self_expr.clone(), other_expr.clone()]; cx.expr_call_global(field.span, partial_cmp_path.clone(), args) } - CsFold::Combine(span, expr1, expr2) => { - let eq_arm = - cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); - let neq_arm = - cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + CsFold::Combine(span, mut expr1, expr2) => { + // When the item is an enum, this expands to + // ``` + // match (expr2) { + // Some(Ordering::Equal) => expr1, + // cmp => cmp + // } + // ``` + // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` + // against the enum variants. This means that we begin by comparing the enum tags, + // before either inspecting their contents (if they match), or returning + // the `cmp::Ordering` of comparing the enum tags. + // ``` + // match partial_cmp(self_tag, other_tag) { + // Some(Ordering::Equal) => match (self, other) { + // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), + // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), + // _ => Some(Ordering::Equal) + // } + // cmp => cmp + // } + // ``` + // If we have any certain enum layouts, flipping this results in better codegen + // ``` + // match (self, other) { + // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), + // _ => partial_cmp(self_tag, other_tag) + // } + // ``` + // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 + + if !tag_then_data + && let ExprKind::Match(_, arms) = &mut expr1.kind + && let Some(last) = arms.last_mut() + && let PatKind::Wild = last.pat.kind { + last.body = expr2; + expr1 + } else { + let eq_arm = + cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); + let neq_arm = + cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); + cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + } } CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())), }, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e0f487e8648..897048f6421 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -23,6 +23,7 @@ pub fn expand_deriving_debug( span, path: path_std!(fmt::Debug), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 5f9519dad1b..c783e46eda9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_rustc_decodable( span, path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 18270747296..a6c8b111527 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_default( span, path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 2afeed927ac..a5e2b599df4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -109,6 +109,7 @@ pub fn expand_deriving_rustc_encodable( span, path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 17b7ac0eba1..97de40bac34 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -165,11 +165,12 @@ pub use SubstructureFields::*; use crate::deriving; use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, + self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + Mutability, PatKind, TyKind, VariantData, }; -use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; @@ -191,6 +192,9 @@ pub struct TraitDef<'a> { /// Whether to skip adding the current trait as a bound to the type parameters of the type. pub skip_path_as_bound: bool, + /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct. + pub needs_copy_as_bound_if_packed: bool, + /// Additional bounds required of any type parameters of the type, /// other than the current trait pub additional_bounds: Vec<Ty>, @@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> { } false }); - let has_no_type_params = match &item.kind { - ast::ItemKind::Struct(_, generics) - | ast::ItemKind::Enum(_, generics) - | ast::ItemKind::Union(_, generics) => !generics - .params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), - _ => unreachable!(), - }; - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let copy_fields = - is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id); let newitem = match &item.kind { ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( @@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - copy_fields, + is_packed, ), ast::ItemKind::Enum(enum_def, generics) => { // We ignore `is_packed` here, because `repr(packed)` @@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - copy_fields, + is_packed, ) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> { generics: &Generics, field_tys: Vec<P<ast::Ty>>, methods: Vec<P<ast::AssocItem>>, + is_packed: bool, ) -> P<ast::Item> { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); @@ -607,20 +600,32 @@ impl<'a> TraitDef<'a> { .map(|param| match ¶m.kind { GenericParamKind::Lifetime { .. } => param.clone(), GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = - // extra restrictions on the generics parameters to the - // type being derived upon - self.additional_bounds.iter().map(|p| { - cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)) - }).chain( - // require the current trait - self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone())) - ).chain( - // also add in any bounds from the declaration - param.bounds.iter().cloned() - ).collect(); + // Extra restrictions on the generics parameters to the + // type being derived upon. + let bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .chain( + // Add a bound for the current trait. + self.skip_path_as_bound + .not() + .then(|| cx.trait_bound(trait_path.clone())), + ) + .chain({ + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + } else { + None + } + }) + .chain( + // Also add in any bounds from the declaration. + param.bounds.iter().cloned(), + ) + .collect(); cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) } @@ -692,9 +697,17 @@ impl<'a> TraitDef<'a> { .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) .collect(); - // require the current trait + // Require the current trait. bounds.push(cx.trait_bound(trait_path.clone())); + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + bounds.push( + cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)), + ); + } + let predicate = ast::WhereBoundPredicate { span: self.span, bound_generic_params: field_ty_param.bound_generic_params, @@ -762,7 +775,7 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, from_scratch: bool, - copy_fields: bool, + is_packed: bool, ) -> P<ast::Item> { let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); @@ -790,7 +803,7 @@ impl<'a> TraitDef<'a> { type_ident, &selflike_args, &nonselflike_args, - copy_fields, + is_packed, ) }; @@ -806,7 +819,7 @@ impl<'a> TraitDef<'a> { }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } fn expand_enum_def( @@ -861,7 +874,8 @@ impl<'a> TraitDef<'a> { }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + let is_packed = false; // enums are never packed + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } } @@ -1011,8 +1025,8 @@ impl<'a> MethodDef<'a> { /// ``` /// But if the struct is `repr(packed)`, we can't use something like /// `&self.x` because that might cause an unaligned ref. So for any trait - /// method that takes a reference, if the struct impls `Copy` then we use a - /// local block to force a copy: + /// method that takes a reference, we use a local block to force a copy. + /// This requires that the field impl `Copy`. /// ``` /// # struct A { x: u8, y: u8 } /// impl PartialEq for A { @@ -1027,10 +1041,6 @@ impl<'a> MethodDef<'a> { /// ::core::hash::Hash::hash(&{ self.y }, state) /// } /// } - /// ``` - /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This - /// only works if the fields match the alignment required by the - /// `packed(N)` attribute. (We'll get errors later on if not.) fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, @@ -1039,12 +1049,12 @@ impl<'a> MethodDef<'a> { type_ident: Ident, selflike_args: &[P<Expr>], nonselflike_args: &[P<Expr>], - copy_fields: bool, + is_packed: bool, ) -> BlockOrExpr { assert!(selflike_args.len() == 1 || selflike_args.len() == 2); let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields); + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed); self.call_substructure_method( cx, trait_, @@ -1514,7 +1524,7 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt<'_>, selflike_args: &[P<Expr>], struct_def: &'a VariantData, - copy_fields: bool, + is_packed: bool, ) -> Vec<FieldInfo> { self.create_fields(struct_def, |i, struct_field, sp| { selflike_args @@ -1533,10 +1543,39 @@ impl<'a> TraitDef<'a> { }), ), ); - if copy_fields { - field_expr = cx.expr_block( - cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), - ); + // In general, fields in packed structs are copied via a + // block, e.g. `&{self.0}`. The one exception is `[u8]` + // fields, which cannot be copied and also never cause + // unaligned references. This exception is allowed to + // handle the `FlexZeroSlice` type in the `zerovec` crate + // within `icu4x-0.9.0`. + // + // Once use of `icu4x-0.9.0` has dropped sufficiently, this + // exception should be removed. + let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind && + let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind && + let [seg] = segments.as_slice() && + seg.ident.name == sym::u8 && seg.args.is_none() + { + true + } else { + false + }; + if is_packed { + if is_u8_slice { + cx.sess.parse_sess.buffer_lint_with_diagnostic( + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + sp, + ast::CRATE_NODE_ID, + "byte slice in a packed struct that derives a built-in trait", + rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive + ); + } else { + // Wrap the expression in `{...}`, causing a copy. + field_expr = cx.expr_block( + cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), + ); + } } cx.expr_addr_of(sp, field_expr) }) diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f8570d8f86a..5c2e89c5697 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -24,6 +24,7 @@ pub fn expand_deriving_hash( span, path, skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 9f4bbbc62c8..e93a23394c0 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,7 +1,11 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::Expr; +use rustc_ast::{ + Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, + FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, + FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, +}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; use rustc_expand::base::{self, *}; @@ -12,21 +16,15 @@ use rustc_span::{BytePos, InnerSpan, Span}; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; -mod ast; -use ast::*; - -mod expand; -use expand::expand_parsed_format_args; - // The format_args!() macro is expanded in three steps: // 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, // but doesn't parse the template (the literal) itself. // 2. Second, `make_format_args` will parse the template, the format options, resolve argument references, -// produce diagnostics, and turn the whole thing into a `FormatArgs` structure. -// 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure -// into the expression that the macro expands to. +// produce diagnostics, and turn the whole thing into a `FormatArgs` AST node. +// 3. Much later, in AST lowering (rustc_ast_lowering), that `FormatArgs` structure will be turned +// into the expression of type `core::fmt::Arguments`. -// See format/ast.rs for the FormatArgs structure and glossary. +// See rustc_ast/src/format.rs for the FormatArgs structure and glossary. // Only used in parse_args and report_invalid_references, // to indicate how a referred argument was used. @@ -437,7 +435,16 @@ pub fn make_format_args( format_options: FormatOptions { fill: format.fill, alignment, - flags: format.flags, + sign: format.sign.map(|s| match s { + parse::Sign::Plus => FormatSign::Plus, + parse::Sign::Minus => FormatSign::Minus, + }), + alternate: format.alternate, + zero_pad: format.zero_pad, + debug_hex: format.debug_hex.map(|s| match s { + parse::DebugHex::Lower => FormatDebugHex::Lower, + parse::DebugHex::Upper => FormatDebugHex::Upper, + }), precision, width, }, @@ -850,7 +857,7 @@ fn expand_format_args_impl<'cx>( match parse_args(ecx, sp, tts) { Ok((efmt, args)) => { if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) { - MacEager::expr(expand_parsed_format_args(ecx, format_args)) + MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) } else { MacEager::expr(DummyResult::raw_expr(sp, true)) } diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs deleted file mode 100644 index 9dde5efcb28..00000000000 --- a/compiler/rustc_builtin_macros/src/format/expand.rs +++ /dev/null @@ -1,353 +0,0 @@ -use super::*; -use rustc_ast as ast; -use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{BlockCheckMode, UnsafeSource}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_span::{sym, symbol::kw}; - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -enum ArgumentType { - Format(FormatTrait), - Usize, -} - -fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> { - // Generate: - // ::core::fmt::ArgumentV1::new_…(arg) - use ArgumentType::*; - use FormatTrait::*; - ecx.expr_call_global( - sp, - ecx.std_path(&[ - sym::fmt, - sym::ArgumentV1, - match ty { - Format(Display) => sym::new_display, - Format(Debug) => sym::new_debug, - Format(LowerExp) => sym::new_lower_exp, - Format(UpperExp) => sym::new_upper_exp, - Format(Octal) => sym::new_octal, - Format(Pointer) => sym::new_pointer, - Format(Binary) => sym::new_binary, - Format(LowerHex) => sym::new_lower_hex, - Format(UpperHex) => sym::new_upper_hex, - Usize => sym::from_usize, - }, - ]), - vec![arg], - ) -} - -fn make_count( - ecx: &ExtCtxt<'_>, - sp: Span, - count: &Option<FormatCount>, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, -) -> P<ast::Expr> { - // Generate: - // ::core::fmt::rt::v1::Count::…(…) - match count { - Some(FormatCount::Literal(n)) => ecx.expr_call_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]), - vec![ecx.expr_usize(sp, *n)], - ), - Some(FormatCount::Argument(arg)) => { - if let Ok(arg_index) = arg.index { - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); - ecx.expr_call_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]), - vec![ecx.expr_usize(sp, i)], - ) - } else { - DummyResult::raw_expr(sp, true) - } - } - None => ecx.expr_path(ecx.path_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]), - )), - } -} - -fn make_format_spec( - ecx: &ExtCtxt<'_>, - sp: Span, - placeholder: &FormatPlaceholder, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, -) -> P<ast::Expr> { - // Generate: - // ::core::fmt::rt::v1::Argument { - // position: 0usize, - // format: ::core::fmt::rt::v1::FormatSpec { - // fill: ' ', - // align: ::core::fmt::rt::v1::Alignment::Unknown, - // flags: 0u32, - // precision: ::core::fmt::rt::v1::Count::Implied, - // width: ::core::fmt::rt::v1::Count::Implied, - // }, - // } - let position = match placeholder.argument.index { - Ok(arg_index) => { - let (i, _) = - argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); - ecx.expr_usize(sp, i) - } - Err(_) => DummyResult::raw_expr(sp, true), - }; - let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' ')); - let align = ecx.expr_path(ecx.path_global( - sp, - ecx.std_path(&[ - sym::fmt, - sym::rt, - sym::v1, - sym::Alignment, - match placeholder.format_options.alignment { - Some(FormatAlignment::Left) => sym::Left, - Some(FormatAlignment::Right) => sym::Right, - Some(FormatAlignment::Center) => sym::Center, - None => sym::Unknown, - }, - ]), - )); - let flags = ecx.expr_u32(sp, placeholder.format_options.flags); - let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap); - let width = make_count(ecx, sp, &placeholder.format_options.width, argmap); - ecx.expr_struct( - sp, - ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])), - vec![ - ecx.field_imm(sp, Ident::new(sym::position, sp), position), - ecx.field_imm( - sp, - Ident::new(sym::format, sp), - ecx.expr_struct( - sp, - ecx.path_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]), - ), - vec![ - ecx.field_imm(sp, Ident::new(sym::fill, sp), fill), - ecx.field_imm(sp, Ident::new(sym::align, sp), align), - ecx.field_imm(sp, Ident::new(sym::flags, sp), flags), - ecx.field_imm(sp, Ident::new(sym::precision, sp), prec), - ecx.field_imm(sp, Ident::new(sym::width, sp), width), - ], - ), - ), - ], - ) -} - -pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> { - let macsp = ecx.with_def_site_ctxt(ecx.call_site()); - - let lit_pieces = ecx.expr_array_ref( - fmt.span, - fmt.template - .iter() - .enumerate() - .filter_map(|(i, piece)| match piece { - &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)), - &FormatArgsPiece::Placeholder(_) => { - // Inject empty string before placeholders when not already preceded by a literal piece. - if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { - Some(ecx.expr_str(fmt.span, kw::Empty)) - } else { - None - } - } - }) - .collect(), - ); - - // Whether we'll use the `Arguments::new_v1_formatted` form (true), - // or the `Arguments::new_v1` form (false). - let mut use_format_options = false; - - // Create a list of all _unique_ (argument, format trait) combinations. - // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] - let mut argmap = FxIndexSet::default(); - for piece in &fmt.template { - let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; - if placeholder.format_options != Default::default() { - // Can't use basic form if there's any formatting options. - use_format_options = true; - } - if let Ok(index) = placeholder.argument.index { - if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) { - // Duplicate (argument, format trait) combination, - // which we'll only put once in the args array. - use_format_options = true; - } - } - } - - let format_options = use_format_options.then(|| { - // Generate: - // &[format_spec_0, format_spec_1, format_spec_2] - ecx.expr_array_ref( - macsp, - fmt.template - .iter() - .filter_map(|piece| { - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; - Some(make_format_spec(ecx, macsp, placeholder, &mut argmap)) - }) - .collect(), - ) - }); - - let arguments = fmt.arguments.into_vec(); - - // If the args array contains exactly all the original arguments once, - // in order, we can use a simple array instead of a `match` construction. - // However, if there's a yield point in any argument except the first one, - // we don't do this, because an ArgumentV1 cannot be kept across yield points. - let use_simple_array = argmap.len() == arguments.len() - && argmap.iter().enumerate().all(|(i, &(j, _))| i == j) - && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); - - let args = if use_simple_array { - // Generate: - // &[ - // ::core::fmt::ArgumentV1::new_display(&arg0), - // ::core::fmt::ArgumentV1::new_lower_hex(&arg1), - // ::core::fmt::ArgumentV1::new_debug(&arg2), - // ] - ecx.expr_array_ref( - macsp, - arguments - .into_iter() - .zip(argmap) - .map(|(arg, (_, ty))| { - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); - make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty) - }) - .collect(), - ) - } else { - // Generate: - // match (&arg0, &arg1, &arg2) { - // args => &[ - // ::core::fmt::ArgumentV1::new_display(args.0), - // ::core::fmt::ArgumentV1::new_lower_hex(args.1), - // ::core::fmt::ArgumentV1::new_debug(args.0), - // ] - // } - let args_ident = Ident::new(sym::args, macsp); - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - if let Some(arg) = arguments.get(arg_index) { - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); - make_argument( - ecx, - sp, - ecx.expr_field( - sp, - ecx.expr_ident(macsp, args_ident), - Ident::new(sym::integer(arg_index), macsp), - ), - ty, - ) - } else { - DummyResult::raw_expr(macsp, true) - } - }) - .collect(); - ecx.expr_addr_of( - macsp, - ecx.expr_match( - macsp, - ecx.expr_tuple( - macsp, - arguments - .into_iter() - .map(|arg| { - ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr) - }) - .collect(), - ), - vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))], - ), - ) - }; - - if let Some(format_options) = format_options { - // Generate: - // ::core::fmt::Arguments::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // unsafe { ::core::fmt::UnsafeArg::new() } - // ) - ecx.expr_call_global( - macsp, - ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]), - vec![ - lit_pieces, - args, - format_options, - ecx.expr_block(P(ast::Block { - stmts: vec![ecx.stmt_expr(ecx.expr_call_global( - macsp, - ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]), - Vec::new(), - ))], - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), - span: macsp, - tokens: None, - could_be_bare_literal: false, - })), - ], - ) - } else { - // Generate: - // ::core::fmt::Arguments::new_v1( - // lit_pieces, - // args, - // ) - ecx.expr_call_global( - macsp, - ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]), - vec![lit_pieces, args], - ) - } -} - -fn may_contain_yield_point(e: &ast::Expr) -> bool { - struct MayContainYieldPoint(bool); - - impl Visitor<'_> for MayContainYieldPoint { - fn visit_expr(&mut self, e: &ast::Expr) { - if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { - self.0 = true; - } else { - visit::walk_expr(self, e); - } - } - - fn visit_mac_call(&mut self, _: &ast::MacCall) { - self.0 = true; - } - - fn visit_attribute(&mut self, _: &ast::Attribute) { - // Conservatively assume this may be a proc macro attribute in - // expression position. - self.0 = true; - } - - fn visit_item(&mut self, _: &ast::Item) { - // Do not recurse into nested items. - } - } - - let mut visitor = MayContainYieldPoint(false); - visitor.visit_expr(e); - visitor.0 -} diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml index d627c2ee09c..7886cae42a1 100644 --- a/compiler/rustc_codegen_cranelift/.cirrus.yml +++ b/compiler/rustc_codegen_cranelift/.cirrus.yml @@ -1,13 +1,11 @@ task: name: freebsd freebsd_instance: - image: freebsd-12-1-release-amd64 + image: freebsd-13-1-release-amd64 setup_rust_script: - pkg install -y curl git bash - curl https://sh.rustup.rs -sSf --output rustup.sh - sh rustup.sh --default-toolchain none -y --profile=minimal - cargo_bin_cache: - folder: ~/.cargo/bin target_cache: folder: target prepare_script: @@ -15,9 +13,4 @@ task: - ./y.rs prepare test_script: - . $HOME/.cargo/env - - # Enable backtraces for easier debugging - - export RUST_BACKTRACE=1 - - # Reduce amount of benchmark runs as they are slow - - export COMPILE_RUNS=2 - - export RUN_RUNS=2 - ./y.rs test diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index a6bb12a66a2..c0daf69e98e 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -25,6 +25,10 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 + defaults: + run: + shell: bash + strategy: fail-fast: false matrix: @@ -46,36 +50,31 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: s390x-unknown-linux-gnu + - os: windows-latest + env: + TARGET_TRIPLE: x86_64-pc-windows-msvc + - os: windows-latest + env: + TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - uses: actions/checkout@v3 - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-cargo-installed-crates - - - name: Cache cargo registry and index - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo target dir uses: actions/cache@v3 with: path: build/cg_clif - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + + - name: Set MinGW as the default toolchain + if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' + run: rustup set default-host x86_64-pc-windows-gnu - name: Install MinGW toolchain and wine if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: | sudo apt-get update sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable - rustup target add x86_64-pc-windows-gnu - name: Install AArch64 toolchain and qemu if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu' @@ -89,6 +88,13 @@ jobs: sudo apt-get update sudo apt-get install -y gcc-s390x-linux-gnu qemu-user + - name: Use sparse cargo registry + run: | + cat >> ~/.cargo/config.toml <<EOF + [unstable] + sparse-registry = true + EOF + - name: Prepare dependencies run: ./y.rs prepare @@ -104,49 +110,47 @@ jobs: - name: Test env: TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }} - run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 - - # Reduce amount of benchmark runs as they are slow - export COMPILE_RUNS=2 - export RUN_RUNS=2 - - # Enable extra checks - export CG_CLIF_ENABLE_VERIFIER=1 - - ./y.rs test + run: ./y.rs test - name: Package prebuilt cg_clif run: tar cvfJ cg_clif.tar.xz dist - name: Upload prebuilt cg_clif - if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v2 + if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' + uses: actions/upload-artifact@v3 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz - name: Upload prebuilt cg_clif (cross compile) - if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' + if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' uses: actions/upload-artifact@v3 with: name: cg_clif-${{ runner.os }}-cross-x86_64-mingw path: cg_clif.tar.xz - windows: + + abi_cafe: runs-on: ${{ matrix.os }} timeout-minutes: 60 + defaults: + run: + shell: bash + strategy: - fail-fast: false + fail-fast: true matrix: include: - # Native Windows build with MSVC + - os: ubuntu-latest + env: + TARGET_TRIPLE: x86_64-unknown-linux-gnu + - os: macos-latest + env: + TARGET_TRIPLE: x86_64-apple-darwin - os: windows-latest env: TARGET_TRIPLE: x86_64-pc-windows-msvc - # cross-compile from Windows to Windows MinGW - os: windows-latest env: TARGET_TRIPLE: x86_64-pc-windows-gnu @@ -154,20 +158,6 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates - - - name: Cache cargo registry and index - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo target dir uses: actions/cache@v3 with: @@ -178,50 +168,20 @@ jobs: if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Prepare dependencies + - name: Use sparse cargo registry run: | - git config --global core.autocrlf false - rustc y.rs -o y.exe -g - ./y.exe prepare + cat >> ~/.cargo/config.toml <<EOF + [unstable] + sparse-registry = true + EOF - - name: Build without unstable features - env: - TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }} - # This is the config rust-lang/rust uses for builds - run: ./y.rs build --no-unstable-features + - name: Prepare dependencies + run: ./y.rs prepare - name: Build run: ./y.rs build --sysroot none - - name: Test - run: | - # Enable backtraces for easier debugging - $Env:RUST_BACKTRACE=1 - - # Reduce amount of benchmark runs as they are slow - $Env:COMPILE_RUNS=2 - $Env:RUN_RUNS=2 - - # Enable extra checks - $Env:CG_CLIF_ENABLE_VERIFIER=1 - - # WIP Disable some tests - - # This fails due to some weird argument handling by hyperfine, not an actual regression - # more of a build system issue - (Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' | Out-File config.txt - - # This fails with a different output than expected - (Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' | Out-File config.txt - - ./y.exe test - - - name: Package prebuilt cg_clif - # don't use compression as xzip isn't supported by tar on windows and bzip2 hangs - run: tar cvf cg_clif.tar dist - - - name: Upload prebuilt cg_clif - uses: actions/upload-artifact@v3 - with: - name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} - path: cg_clif.tar + - name: Test abi-cafe + env: + TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }} + run: ./y.rs abi-cafe diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml deleted file mode 100644 index d0d58d2a7ea..00000000000 --- a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Test nightly Cranelift - -on: - push: - schedule: - - cron: '17 1 * * *' # At 01:17 UTC every day. - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 60 - - steps: - - uses: actions/checkout@v3 - - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ubuntu-latest-cargo-installed-crates - - - name: Prepare dependencies - run: | - git config --global user.email "user@example.com" - git config --global user.name "User" - ./y.rs prepare - - - name: Patch Cranelift - run: | - sed -i 's/cranelift-codegen = { version = "\w*.\w*.\w*", features = \["unwind", "all-arch"\] }/cranelift-codegen = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", features = ["unwind", "all-arch"] }/' Cargo.toml - sed -i 's/cranelift-frontend = "\w*.\w*.\w*"/cranelift-frontend = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml - sed -i 's/cranelift-module = "\w*.\w*.\w*"/cranelift-module = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml - sed -i 's/cranelift-native = "\w*.\w*.\w*"/cranelift-native = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml - sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml - sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml - - sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml - - cat Cargo.toml - - - name: Build without unstable features - # This is the config rust-lang/rust uses for builds - run: ./y.rs build --no-unstable-features - - - name: Build - run: ./y.rs build --sysroot none - - name: Test - run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 - - # Reduce amount of benchmark runs as they are slow - export COMPILE_RUNS=2 - export RUN_RUNS=2 - - # Enable extra checks - export CG_CLIF_ENABLE_VERIFIER=1 - - ./test.sh diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index bef806318ef..5faa8f05404 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -10,73 +10,45 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-cargo-installed-crates - - - name: Cache cargo registry and index - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo target dir uses: actions/cache@v3 with: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Prepare dependencies + - name: Use sparse cargo registry run: | - git config --global user.email "user@example.com" - git config --global user.name "User" - ./y.rs prepare + cat >> ~/.cargo/config.toml <<EOF + [unstable] + sparse-registry = true + EOF - - name: Test - run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 + - name: Prepare dependencies + run: ./y.rs prepare - ./scripts/test_bootstrap.sh + - name: Test + run: ./scripts/test_bootstrap.sh rustc_test_suite: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Cache cargo installed crates - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-cargo-installed-crates - - - name: Cache cargo registry and index - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo target dir uses: actions/cache@v3 with: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Prepare dependencies + - name: Use sparse cargo registry run: | - git config --global user.email "user@example.com" - git config --global user.name "User" - ./y.rs prepare + cat >> ~/.cargo/config.toml <<EOF + [unstable] + sparse-registry = true + EOF - - name: Test - run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 + - name: Prepare dependencies + run: ./y.rs prepare - ./scripts/test_rustc_tests.sh + - name: Test + run: ./scripts/test_rustc_tests.sh diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index b443fd58a1b..8012e93f6a9 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -1,4 +1,4 @@ -target +/target **/*.rs.bk *.rlib *.o @@ -11,9 +11,6 @@ perf.data.old /y.exe /y.pdb /build -/build_sysroot/sysroot_src -/build_sysroot/compiler-builtins -/build_sysroot/rustc_version /dist /rust /download diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index bc914e37d2b..7c8703cba50 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -1,4 +1,6 @@ { + "editor.formatOnSave": true, + // source for rustc_* is not included in the rust-src component; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], "rust-analyzer.imports.granularity.enforce": true, @@ -30,7 +32,7 @@ ] }, { - "sysroot_src": "./build_sysroot/sysroot_src/library", + "sysroot_src": "./download/sysroot/sysroot_src/library", "crates": [ { "root_module": "./example/std_example.rs", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index e4d3e9ca5ae..50249ea1bdb 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -57,28 +57,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad" +checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46" +checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61" dependencies = [ "arrayvec", "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", - "cranelift-egraph", "cranelift-entity", "cranelift-isle", "gimli", + "hashbrown", "log", "regalloc2", "smallvec", @@ -87,44 +87,30 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5" +checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43dfa417b884a9ab488d95fd6b93b25e959321fe7bfd7a0a960ba5d7fb7ab927" - -[[package]] -name = "cranelift-egraph" -version = "0.90.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a66b39785efd8513d2cca967ede56d6cc57c8d7986a595c7c47d0c78de8dce" -dependencies = [ - "cranelift-entity", - "fxhash", - "hashbrown", - "indexmap", - "log", - "smallvec", -] +checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d" [[package]] name = "cranelift-entity" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346" +checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13" [[package]] name = "cranelift-frontend" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56" +checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0" dependencies = [ "cranelift-codegen", "log", @@ -134,15 +120,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd" +checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0" [[package]] name = "cranelift-jit" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4" +checksum = "6557f8ce44d498777f2495aa58d9692a4a37d6f84aa445750d666cef770b6a5c" dependencies = [ "anyhow", "cranelift-codegen", @@ -159,9 +145,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f" +checksum = "88807e1c0c47ec02fe433333ccbe56b480425418b1470e333205e11650697d72" dependencies = [ "anyhow", "cranelift-codegen", @@ -169,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e" +checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120" dependencies = [ "cranelift-codegen", "libc", @@ -180,9 +166,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.90.1" +version = "0.92.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983" +checksum = "341375758d7c3fedc0b5315f552e6f0feac46baf87c450a15e9455ef47c2b261" dependencies = [ "anyhow", "cranelift-codegen", @@ -317,9 +303,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "regalloc2" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" dependencies = [ "fxhash", "log", @@ -347,7 +333,6 @@ dependencies = [ "cranelift-frontend", "cranelift-jit", "cranelift-module", - "cranelift-native", "cranelift-object", "gimli", "indexmap", @@ -396,9 +381,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasmtime-jit-icache-coherence" -version = "2.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66" +checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e" dependencies = [ "cfg-if", "libc", @@ -429,43 +414,57 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ + "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", + "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 2b216ca072f..34117c2886f 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -15,12 +15,14 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.90.1", features = ["unwind", "all-arch"] } -cranelift-frontend = "0.90.1" -cranelift-module = "0.90.1" -cranelift-native = "0.90.1" -cranelift-jit = { version = "0.90.1", optional = true } -cranelift-object = "0.90.1" +cranelift-codegen = { version = "0.92", features = ["unwind", "all-arch"] } +cranelift-frontend = { version = "0.92" } +cranelift-module = { version = "0.92" } +# NOTE vendored as src/cranelift_native.rs +# FIXME revert back to the external crate with Cranelift 0.93 +#cranelift-native = { version = "0.92" } +cranelift-jit = { version = "0.92", optional = true } +cranelift-object = { version = "0.92" } target-lexicon = "0.12.0" gimli = { version = "0.26.0", default-features = false, features = ["write"]} object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 0e9c77244d4..b87a9dc51e8 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -8,9 +8,9 @@ If not please open an issue. ## Building and testing ```bash -$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git +$ git clone https://github.com/bjorn3/rustc_codegen_cranelift $ cd rustc_codegen_cranelift -$ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking +$ ./y.rs prepare $ ./y.rs build ``` @@ -20,13 +20,12 @@ To run the test suite replace the last command with: $ ./test.sh ``` -This will implicitly build cg_clif too. Both `y.rs build` and `test.sh` accept a `--debug` argument to -build in debug mode. +For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`. -Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section +Alternatively you can download a pre built version from [Github Actions]. It is listed in the artifacts section of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it. -[GHA]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess +[Github Actions]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess ## Usage @@ -53,7 +52,8 @@ configuration options. * Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041)) * On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`. -* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work) +* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported) +* Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default) ## License diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index bba3210536e..24f15fc8521 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cfg-if" @@ -50,9 +50,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.85" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb" +checksum = "5dae98c88e576098d7ab13ebcb40cc43e5114b2beafe61a87cda9200649ff205" dependencies = [ "rustc-std-workspace-core", ] @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs index a081fdaa1c7..dbee9be04ee 100644 --- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs +++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs @@ -1,7 +1,6 @@ use std::path::Path; use super::build_sysroot; -use super::config; use super::path::Dirs; use super::prepare::GitRepo; use super::utils::{spawn_and_wait, CargoProject, Compiler}; @@ -10,41 +9,31 @@ use super::SysrootKind; pub(crate) static ABI_CAFE_REPO: GitRepo = GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe"); -static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe"); +pub(crate) static ABI_CAFE: CargoProject = + CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe"); pub(crate) fn run( channel: &str, sysroot_kind: SysrootKind, dirs: &Dirs, cg_clif_dylib: &Path, - host_triple: &str, - target_triple: &str, + bootstrap_host_compiler: &Compiler, ) { - if !config::get_bool("testsuite.abi-cafe") { - eprintln!("[SKIP] abi-cafe"); - return; - } - - if host_triple != target_triple { - eprintln!("[SKIP] abi-cafe (cross-compilation not supported)"); - return; - } - eprintln!("Building sysroot for abi-cafe"); build_sysroot::build_sysroot( dirs, channel, sysroot_kind, cg_clif_dylib, - host_triple, - target_triple, + bootstrap_host_compiler, + bootstrap_host_compiler.triple.clone(), ); eprintln!("Running abi-cafe"); let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; - let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs); + let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); cmd.arg("--"); cmd.arg("--pairs"); cmd.args(pairs); diff --git a/compiler/rustc_codegen_cranelift/build_system/bench.rs b/compiler/rustc_codegen_cranelift/build_system/bench.rs new file mode 100644 index 00000000000..01d44dafbdd --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build_system/bench.rs @@ -0,0 +1,97 @@ +use std::env; +use std::fs; +use std::path::Path; + +use super::path::{Dirs, RelPath}; +use super::prepare::GitRepo; +use super::rustc_info::get_file_name; +use super::utils::{hyperfine_command, is_ci, spawn_and_wait, CargoProject, Compiler}; + +pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github( + "ebobby", + "simple-raytracer", + "804a7a21b9e673a482797aa289a18ed480e4d813", + "<none>", +); + +// Use a separate target dir for the initial LLVM build to reduce unnecessary recompiles +pub(crate) static SIMPLE_RAYTRACER_LLVM: CargoProject = + CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer_llvm"); + +pub(crate) static SIMPLE_RAYTRACER: CargoProject = + CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer"); + +pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { + benchmark_simple_raytracer(dirs, bootstrap_host_compiler); +} + +fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { + if std::process::Command::new("hyperfine").output().is_err() { + eprintln!("Hyperfine not installed"); + eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine"); + std::process::exit(1); + } + + eprintln!("[LLVM BUILD] simple-raytracer"); + let build_cmd = SIMPLE_RAYTRACER_LLVM.build(bootstrap_host_compiler, dirs); + spawn_and_wait(build_cmd); + fs::copy( + SIMPLE_RAYTRACER_LLVM + .target_dir(dirs) + .join(&bootstrap_host_compiler.triple) + .join("debug") + .join(get_file_name("main", "bin")), + RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")), + ) + .unwrap(); + + let run_runs = env::var("RUN_RUNS") + .unwrap_or(if is_ci() { "2" } else { "10" }.to_string()) + .parse() + .unwrap(); + + eprintln!("[BENCH COMPILE] ebobby/simple-raytracer"); + let cargo_clif = + RelPath::DIST.to_path(dirs).join(get_file_name("cargo_clif", "bin").replace('_', "-")); + let manifest_path = SIMPLE_RAYTRACER.manifest_path(dirs); + let target_dir = SIMPLE_RAYTRACER.target_dir(dirs); + + let clean_cmd = format!( + "cargo clean --manifest-path {manifest_path} --target-dir {target_dir}", + manifest_path = manifest_path.display(), + target_dir = target_dir.display(), + ); + let llvm_build_cmd = format!( + "cargo build --manifest-path {manifest_path} --target-dir {target_dir}", + manifest_path = manifest_path.display(), + target_dir = target_dir.display(), + ); + let clif_build_cmd = format!( + "{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}", + cargo_clif = cargo_clif.display(), + manifest_path = manifest_path.display(), + target_dir = target_dir.display(), + ); + + let bench_compile = + hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd); + + spawn_and_wait(bench_compile); + + eprintln!("[BENCH RUN] ebobby/simple-raytracer"); + fs::copy( + target_dir.join("debug").join(get_file_name("main", "bin")), + RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_clif", "bin")), + ) + .unwrap(); + + let mut bench_run = hyperfine_command( + 0, + run_runs, + None, + Path::new(".").join(get_file_name("raytracer_cg_llvm", "bin")).to_str().unwrap(), + Path::new(".").join(get_file_name("raytracer_cg_clif", "bin")).to_str().unwrap(), + ); + bench_run.current_dir(RelPath::BUILD.to_path(dirs)); + spawn_and_wait(bench_run); +} diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index fde8ef424cc..514404305a3 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -5,15 +5,15 @@ use super::path::{Dirs, RelPath}; use super::rustc_info::get_file_name; use super::utils::{is_ci, CargoProject, Compiler}; -static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); +pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); pub(crate) fn build_backend( dirs: &Dirs, channel: &str, - host_triple: &str, + bootstrap_host_compiler: &Compiler, use_unstable_features: bool, ) -> PathBuf { - let mut cmd = CG_CLIF.build(&Compiler::host(), dirs); + let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode @@ -25,6 +25,8 @@ pub(crate) fn build_backend( // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway cmd.env("CARGO_BUILD_INCREMENTAL", "false"); + + cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); } if use_unstable_features { @@ -46,7 +48,7 @@ pub(crate) fn build_backend( CG_CLIF .target_dir(dirs) - .join(host_triple) + .join(&bootstrap_host_compiler.triple) .join(channel) .join(get_file_name("rustc_codegen_cranelift", "dylib")) } diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index cbbf09b9b97..bd04fdbe304 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -1,31 +1,32 @@ use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{self, Command}; use super::path::{Dirs, RelPath}; -use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name}; -use super::utils::{spawn_and_wait, try_hard_link, CargoProject, Compiler}; +use super::rustc_info::{get_file_name, get_rustc_version, get_toolchain_name}; +use super::utils::{remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler}; use super::SysrootKind; static DIST_DIR: RelPath = RelPath::DIST; static BIN_DIR: RelPath = RelPath::DIST.join("bin"); static LIB_DIR: RelPath = RelPath::DIST.join("lib"); -static RUSTLIB_DIR: RelPath = LIB_DIR.join("rustlib"); pub(crate) fn build_sysroot( dirs: &Dirs, channel: &str, sysroot_kind: SysrootKind, cg_clif_dylib_src: &Path, - host_triple: &str, - target_triple: &str, -) { + bootstrap_host_compiler: &Compiler, + target_triple: String, +) -> Compiler { eprintln!("[BUILD] sysroot {:?}", sysroot_kind); DIST_DIR.ensure_fresh(dirs); BIN_DIR.ensure_exists(dirs); LIB_DIR.ensure_exists(dirs); + let is_native = bootstrap_host_compiler.triple == target_triple; + // Copy the backend let cg_clif_dylib_path = if cfg!(windows) { // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the @@ -35,129 +36,169 @@ pub(crate) fn build_sysroot( LIB_DIR } .to_path(dirs) - .join(get_file_name("rustc_codegen_cranelift", "dylib")); + .join(cg_clif_dylib_src.file_name().unwrap()); try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path); // Build and copy rustc and cargo wrappers + let wrapper_base_name = get_file_name("____", "bin"); + let toolchain_name = get_toolchain_name(); for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] { - let wrapper_name = get_wrapper_file_name(wrapper, "bin"); + let wrapper_name = wrapper_base_name.replace("____", wrapper); - let mut build_cargo_wrapper_cmd = Command::new("rustc"); + let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc); build_cargo_wrapper_cmd + .env("TOOLCHAIN_NAME", toolchain_name.clone()) .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs"))) .arg("-o") .arg(DIST_DIR.to_path(dirs).join(wrapper_name)) - .arg("-g"); + .arg("-Cstrip=debuginfo"); spawn_and_wait(build_cargo_wrapper_cmd); } - let default_sysroot = super::rustc_info::get_default_sysroot(); + let host = build_sysroot_for_triple( + dirs, + channel, + bootstrap_host_compiler.clone(), + &cg_clif_dylib_path, + sysroot_kind, + ); + host.install_into_sysroot(&DIST_DIR.to_path(dirs)); - let host_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(host_triple).join("lib"); - let target_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(target_triple).join("lib"); - fs::create_dir_all(&host_rustlib_lib).unwrap(); - fs::create_dir_all(&target_rustlib_lib).unwrap(); + if !is_native { + build_sysroot_for_triple( + dirs, + channel, + { + let mut bootstrap_target_compiler = bootstrap_host_compiler.clone(); + bootstrap_target_compiler.triple = target_triple.clone(); + bootstrap_target_compiler.set_cross_linker_and_runner(); + bootstrap_target_compiler + }, + &cg_clif_dylib_path, + sysroot_kind, + ) + .install_into_sysroot(&DIST_DIR.to_path(dirs)); + } - if target_triple == "x86_64-pc-windows-gnu" { - if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() { - eprintln!( - "The x86_64-pc-windows-gnu target needs to be installed first before it is possible \ - to compile a sysroot for it.", - ); - process::exit(1); + // Copy std for the host to the lib dir. This is necessary for the jit mode to find + // libstd. + for lib in host.libs { + let filename = lib.file_name().unwrap().to_str().unwrap(); + if filename.contains("std-") && !filename.contains(".rlib") { + try_hard_link(&lib, LIB_DIR.to_path(dirs).join(lib.file_name().unwrap())); } - for file in fs::read_dir( - default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"), - ) - .unwrap() - { - let file = file.unwrap().path(); - if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") { - continue; // only copy object files - } - try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap())); + } + + let mut target_compiler = { + let dirs: &Dirs = &dirs; + let rustc_clif = + RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustc-clif")); + let rustdoc_clif = + RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustdoc-clif")); + + Compiler { + cargo: bootstrap_host_compiler.cargo.clone(), + rustc: rustc_clif.clone(), + rustdoc: rustdoc_clif.clone(), + rustflags: String::new(), + rustdocflags: String::new(), + triple: target_triple, + runner: vec![], } + }; + if !is_native { + target_compiler.set_cross_linker_and_runner(); } + target_compiler +} - match sysroot_kind { - SysrootKind::None => {} // Nothing to do - SysrootKind::Llvm => { - for file in fs::read_dir( - default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"), - ) - .unwrap() - { - let file = file.unwrap().path(); - let file_name_str = file.file_name().unwrap().to_str().unwrap(); - if (file_name_str.contains("rustc_") - && !file_name_str.contains("rustc_std_workspace_") - && !file_name_str.contains("rustc_demangle")) - || file_name_str.contains("chalk") - || file_name_str.contains("tracing") - || file_name_str.contains("regex") - { - // These are large crates that are part of the rustc-dev component and are not - // necessary to run regular programs. - continue; - } - try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap())); - } +struct SysrootTarget { + triple: String, + libs: Vec<PathBuf>, +} - if target_triple != host_triple { - for file in fs::read_dir( - default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"), - ) - .unwrap() - { - let file = file.unwrap().path(); - try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap())); - } - } +impl SysrootTarget { + fn install_into_sysroot(&self, sysroot: &Path) { + if self.libs.is_empty() { + return; } - SysrootKind::Clif => { - build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None); - - if host_triple != target_triple { - // When cross-compiling it is often necessary to manually pick the right linker - let linker = match target_triple { - "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu-gcc"), - "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu-gcc"), - _ => None, - }; - build_clif_sysroot_for_triple( - dirs, - channel, - target_triple, - &cg_clif_dylib_path, - linker, - ); - } - // Copy std for the host to the lib dir. This is necessary for the jit mode to find - // libstd. - for file in fs::read_dir(host_rustlib_lib).unwrap() { - let file = file.unwrap().path(); - let filename = file.file_name().unwrap().to_str().unwrap(); - if filename.contains("std-") && !filename.contains(".rlib") { - try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.file_name().unwrap())); - } - } + let target_rustlib_lib = sysroot.join("lib").join("rustlib").join(&self.triple).join("lib"); + fs::create_dir_all(&target_rustlib_lib).unwrap(); + + for lib in &self.libs { + try_hard_link(lib, target_rustlib_lib.join(lib.file_name().unwrap())); } } } -// FIXME move to download/ or dist/ -pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = RelPath::BUILD_SYSROOT.join("rustc_version"); -pub(crate) static SYSROOT_SRC: RelPath = RelPath::BUILD_SYSROOT.join("sysroot_src"); -static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::BUILD_SYSROOT, "build_sysroot"); +pub(crate) static ORIG_BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot"); +pub(crate) static BUILD_SYSROOT: RelPath = RelPath::DOWNLOAD.join("sysroot"); +pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = BUILD_SYSROOT.join("rustc_version"); +pub(crate) static SYSROOT_SRC: RelPath = BUILD_SYSROOT.join("sysroot_src"); +pub(crate) static STANDARD_LIBRARY: CargoProject = + CargoProject::new(&BUILD_SYSROOT, "build_sysroot"); +pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup"); +#[must_use] +fn build_sysroot_for_triple( + dirs: &Dirs, + channel: &str, + compiler: Compiler, + cg_clif_dylib_path: &Path, + sysroot_kind: SysrootKind, +) -> SysrootTarget { + match sysroot_kind { + SysrootKind::None => build_rtstartup(dirs, &compiler) + .unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }), + SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler), + SysrootKind::Clif => { + build_clif_sysroot_for_triple(dirs, channel, compiler, &cg_clif_dylib_path) + } + } +} + +#[must_use] +fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { + let default_sysroot = super::rustc_info::get_default_sysroot(&compiler.rustc); + + let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] }; + + for entry in fs::read_dir( + default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"), + ) + .unwrap() + { + let entry = entry.unwrap(); + if entry.file_type().unwrap().is_dir() { + continue; + } + let file = entry.path(); + let file_name_str = file.file_name().unwrap().to_str().unwrap(); + if (file_name_str.contains("rustc_") + && !file_name_str.contains("rustc_std_workspace_") + && !file_name_str.contains("rustc_demangle")) + || file_name_str.contains("chalk") + || file_name_str.contains("tracing") + || file_name_str.contains("regex") + { + // These are large crates that are part of the rustc-dev component and are not + // necessary to run regular programs. + continue; + } + target_libs.libs.push(file); + } + + target_libs +} + +#[must_use] fn build_clif_sysroot_for_triple( dirs: &Dirs, channel: &str, - triple: &str, + mut compiler: Compiler, cg_clif_dylib_path: &Path, - linker: Option<&str>, -) { +) -> SysrootTarget { match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) { Err(e) => { eprintln!("Failed to get rustc version for patched sysroot source: {}", e); @@ -165,7 +206,7 @@ fn build_clif_sysroot_for_triple( process::exit(1); } Ok(source_version) => { - let rustc_version = get_rustc_version(); + let rustc_version = get_rustc_version(&compiler.rustc); if source_version != rustc_version { eprintln!("The patched sysroot source is outdated"); eprintln!("Source version: {}", source_version.trim()); @@ -176,29 +217,32 @@ fn build_clif_sysroot_for_triple( } } - let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel); + let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] }; + + if let Some(rtstartup_target_libs) = build_rtstartup(dirs, &compiler) { + rtstartup_target_libs.install_into_sysroot(&RTSTARTUP_SYSROOT.to_path(dirs)); + + target_libs.libs.extend(rtstartup_target_libs.libs); + } + + let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel); if !super::config::get_bool("keep_sysroot") { // Cleanup the deps dir, but keep build scripts and the incremental cache for faster // recompilation as they are not affected by changes in cg_clif. - if build_dir.join("deps").exists() { - fs::remove_dir_all(build_dir.join("deps")).unwrap(); - } + remove_dir_if_exists(&build_dir.join("deps")); } // Build sysroot - let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string(); + let mut rustflags = " -Zforce-unstable-if-unmarked -Cpanic=abort".to_string(); rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap())); - rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap())); + // Necessary for MinGW to find rsbegin.o and rsend.o + rustflags + .push_str(&format!(" --sysroot={}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap())); if channel == "release" { rustflags.push_str(" -Zmir-opt-level=3"); } - if let Some(linker) = linker { - use std::fmt::Write; - write!(rustflags, " -Clinker={}", linker).unwrap(); - } - let mut compiler = Compiler::with_triple(triple.to_owned()); - compiler.rustflags = rustflags; + compiler.rustflags += &rustflags; let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); if channel == "release" { build_cmd.arg("--release"); @@ -206,7 +250,6 @@ fn build_clif_sysroot_for_triple( build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); spawn_and_wait(build_cmd); - // Copy all relevant files to the sysroot for entry in fs::read_dir(build_dir.join("deps")).unwrap() { let entry = entry.unwrap(); if let Some(ext) = entry.path().extension() { @@ -216,9 +259,35 @@ fn build_clif_sysroot_for_triple( } else { continue; }; - try_hard_link( - entry.path(), - RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()), - ); + target_libs.libs.push(entry.path()); + } + + target_libs +} + +fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> { + if !compiler.triple.ends_with("windows-gnu") { + return None; } + + RTSTARTUP_SYSROOT.ensure_fresh(dirs); + + let rtstartup_src = SYSROOT_SRC.to_path(dirs).join("library").join("rtstartup"); + let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] }; + + for file in ["rsbegin", "rsend"] { + let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o")); + let mut build_rtstartup_cmd = Command::new(&compiler.rustc); + build_rtstartup_cmd + .arg("--target") + .arg(&compiler.triple) + .arg("--emit=obj") + .arg("-o") + .arg(&obj) + .arg(rtstartup_src.join(format!("{file}.rs"))); + spawn_and_wait(build_rtstartup_cmd); + target_libs.libs.push(obj.clone()); + } + + Some(target_libs) } diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs index 1afc9a55c73..8dcbe8de189 100644 --- a/compiler/rustc_codegen_cranelift/build_system/mod.rs +++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs @@ -2,9 +2,10 @@ use std::env; use std::path::PathBuf; use std::process; -use self::utils::is_ci; +use self::utils::{is_ci, Compiler}; mod abi_cafe; +mod bench; mod build_backend; mod build_sysroot; mod config; @@ -14,31 +15,8 @@ mod rustc_info; mod tests; mod utils; -const USAGE: &str = r#"The build system of cg_clif. - -USAGE: - ./y.rs prepare [--out-dir DIR] - ./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features] - ./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features] - -OPTIONS: - --sysroot none|clif|llvm - Which sysroot libraries to use: - `none` will not include any standard library in the sysroot. - `clif` will build the standard library using Cranelift. - `llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM. - - --out-dir DIR - Specify the directory in which the download, build and dist directories are stored. - By default this is the working directory. - - --no-unstable-features - fSome features are not yet ready for production usage. This option will disable these - features. This includes the JIT mode and inline assembly support. -"#; - fn usage() { - eprintln!("{USAGE}"); + eprintln!("{}", include_str!("usage.txt")); } macro_rules! arg_error { @@ -54,6 +32,8 @@ enum Command { Prepare, Build, Test, + AbiCafe, + Bench, } #[derive(Copy, Clone, Debug)] @@ -64,12 +44,17 @@ pub(crate) enum SysrootKind { } pub fn main() { - env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1"); + if env::var("RUST_BACKTRACE").is_err() { + env::set_var("RUST_BACKTRACE", "1"); + } env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1"); if is_ci() { // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway env::set_var("CARGO_BUILD_INCREMENTAL", "false"); + + // Enable the Cranelift verifier + env::set_var("CG_CLIF_ENABLE_VERIFIER", "1"); } let mut args = env::args().skip(1); @@ -77,6 +62,8 @@ pub fn main() { Some("prepare") => Command::Prepare, Some("build") => Command::Build, Some("test") => Command::Test, + Some("abi-cafe") => Command::AbiCafe, + Some("bench") => Command::Bench, Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag), Some(command) => arg_error!("Unknown command {}", command), None => { @@ -112,24 +99,16 @@ pub fn main() { } } - let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") { - host_triple - } else if let Some(host_triple) = config::get_value("host") { - host_triple - } else { - rustc_info::get_host_triple() - }; - let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") { - if target_triple != "" { - target_triple - } else { - host_triple.clone() // Empty target triple can happen on GHA - } - } else if let Some(target_triple) = config::get_value("target") { - target_triple - } else { - host_triple.clone() - }; + let bootstrap_host_compiler = Compiler::bootstrap_with_triple( + std::env::var("HOST_TRIPLE") + .ok() + .or_else(|| config::get_value("host")) + .unwrap_or_else(|| rustc_info::get_host_triple()), + ); + let target_triple = std::env::var("TARGET_TRIPLE") + .ok() + .or_else(|| config::get_value("target")) + .unwrap_or_else(|| bootstrap_host_compiler.triple.clone()); // FIXME allow changing the location of these dirs using cli arguments let current_dir = std::env::current_dir().unwrap(); @@ -157,8 +136,15 @@ pub fn main() { process::exit(0); } - let cg_clif_dylib = - build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features); + env::set_var("RUSTC", "rustc_should_be_set_explicitly"); + env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly"); + + let cg_clif_dylib = build_backend::build_backend( + &dirs, + channel, + &bootstrap_host_compiler, + use_unstable_features, + ); match command { Command::Prepare => { // Handled above @@ -169,28 +155,37 @@ pub fn main() { channel, sysroot_kind, &cg_clif_dylib, - &host_triple, - &target_triple, + &bootstrap_host_compiler, + target_triple.clone(), ); - - abi_cafe::run( + } + Command::AbiCafe => { + if bootstrap_host_compiler.triple != target_triple { + eprintln!("Abi-cafe doesn't support cross-compilation"); + process::exit(1); + } + abi_cafe::run(channel, sysroot_kind, &dirs, &cg_clif_dylib, &bootstrap_host_compiler); + } + Command::Build => { + build_sysroot::build_sysroot( + &dirs, channel, sysroot_kind, - &dirs, &cg_clif_dylib, - &host_triple, - &target_triple, + &bootstrap_host_compiler, + target_triple, ); } - Command::Build => { + Command::Bench => { build_sysroot::build_sysroot( &dirs, channel, sysroot_kind, &cg_clif_dylib, - &host_triple, - &target_triple, + &bootstrap_host_compiler, + target_triple, ); + bench::benchmark(&dirs, &bootstrap_host_compiler); } } } diff --git a/compiler/rustc_codegen_cranelift/build_system/path.rs b/compiler/rustc_codegen_cranelift/build_system/path.rs index e93981f1d64..3290723005d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/path.rs +++ b/compiler/rustc_codegen_cranelift/build_system/path.rs @@ -1,6 +1,8 @@ use std::fs; use std::path::PathBuf; +use super::utils::remove_dir_if_exists; + #[derive(Debug, Clone)] pub(crate) struct Dirs { pub(crate) source_dir: PathBuf, @@ -42,7 +44,6 @@ impl RelPath { pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist); pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts"); - pub(crate) const BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot"); pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches"); pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath { @@ -62,9 +63,7 @@ impl RelPath { pub(crate) fn ensure_fresh(&self, dirs: &Dirs) { let path = self.to_path(dirs); - if path.exists() { - fs::remove_dir_all(&path).unwrap(); - } + remove_dir_if_exists(&path); fs::create_dir_all(path).unwrap(); } } diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index 8ac67e8f942..f25a81dc234 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -3,73 +3,55 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC}; +use super::build_sysroot::{BUILD_SYSROOT, ORIG_BUILD_SYSROOT, SYSROOT_RUSTC_VERSION, SYSROOT_SRC}; use super::path::{Dirs, RelPath}; -use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version}; -use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler}; +use super::rustc_info::{get_default_sysroot, get_rustc_version}; +use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait}; pub(crate) fn prepare(dirs: &Dirs) { - if RelPath::DOWNLOAD.to_path(dirs).exists() { - std::fs::remove_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap(); - } - std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap(); + RelPath::DOWNLOAD.ensure_fresh(dirs); - prepare_sysroot(dirs); + spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", dirs)); - // FIXME maybe install this only locally? - eprintln!("[INSTALL] hyperfine"); - Command::new("cargo") - .arg("install") - .arg("hyperfine") - .env_remove("CARGO_TARGET_DIR") - .spawn() - .unwrap() - .wait() - .unwrap(); + prepare_sysroot(dirs); + spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", dirs)); + spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", dirs)); super::abi_cafe::ABI_CAFE_REPO.fetch(dirs); + spawn_and_wait(super::abi_cafe::ABI_CAFE.fetch("cargo", dirs)); super::tests::RAND_REPO.fetch(dirs); + spawn_and_wait(super::tests::RAND.fetch("cargo", dirs)); super::tests::REGEX_REPO.fetch(dirs); + spawn_and_wait(super::tests::REGEX.fetch("cargo", dirs)); super::tests::PORTABLE_SIMD_REPO.fetch(dirs); - super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs); - - eprintln!("[LLVM BUILD] simple-raytracer"); - let host_compiler = Compiler::host(); - let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs); - spawn_and_wait(build_cmd); - fs::copy( - super::tests::SIMPLE_RAYTRACER - .target_dir(dirs) - .join(&host_compiler.triple) - .join("debug") - .join(get_file_name("main", "bin")), - RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")), - ) - .unwrap(); + spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", dirs)); + super::bench::SIMPLE_RAYTRACER_REPO.fetch(dirs); + spawn_and_wait(super::bench::SIMPLE_RAYTRACER.fetch("cargo", dirs)); } fn prepare_sysroot(dirs: &Dirs) { - let rustc_path = get_rustc_path(); - let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust"); - let sysroot_src = SYSROOT_SRC; - + let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust"); assert!(sysroot_src_orig.exists()); - sysroot_src.ensure_fresh(dirs); - fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap(); eprintln!("[COPY] sysroot src"); + + // FIXME ensure builds error out or update the copy if any of the files copied here change + BUILD_SYSROOT.ensure_fresh(dirs); + copy_dir_recursively(&ORIG_BUILD_SYSROOT.to_path(dirs), &BUILD_SYSROOT.to_path(dirs)); + + fs::create_dir_all(SYSROOT_SRC.to_path(dirs).join("library")).unwrap(); copy_dir_recursively( &sysroot_src_orig.join("library"), - &sysroot_src.to_path(dirs).join("library"), + &SYSROOT_SRC.to_path(dirs).join("library"), ); - let rustc_version = get_rustc_version(); + let rustc_version = get_rustc_version(Path::new("rustc")); fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap(); eprintln!("[GIT] init"); - init_git_repo(&sysroot_src.to_path(dirs)); + init_git_repo(&SYSROOT_SRC.to_path(dirs)); - apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs)); + apply_patches(dirs, "sysroot", &SYSROOT_SRC.to_path(dirs)); } pub(crate) struct GitRepo { @@ -118,14 +100,14 @@ impl GitRepo { fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { eprintln!("[CLONE] {}", repo); // Ignore exit code as the repo may already have been checked out - Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap(); + git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap(); - let mut clean_cmd = Command::new("git"); - clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir); + let mut clean_cmd = git_command(download_dir, "checkout"); + clean_cmd.arg("--").arg("."); spawn_and_wait(clean_cmd); - let mut checkout_cmd = Command::new("git"); - checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir); + let mut checkout_cmd = git_command(download_dir, "checkout"); + checkout_cmd.arg("-q").arg(rev); spawn_and_wait(checkout_cmd); } @@ -149,8 +131,22 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: // Download zip archive let mut download_cmd = Command::new("curl"); - download_cmd.arg("--location").arg("--output").arg(&archive_file).arg(archive_url); - spawn_and_wait(download_cmd); + download_cmd + .arg("--max-time") + .arg("600") + .arg("-y") + .arg("30") + .arg("-Y") + .arg("10") + .arg("--connect-timeout") + .arg("30") + .arg("--continue-at") + .arg("-") + .arg("--location") + .arg("--output") + .arg(&archive_file) + .arg(archive_url); + retry_spawn_and_wait(5, download_cmd); // Unpack tar archive let mut unpack_cmd = Command::new("tar"); @@ -167,25 +163,16 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: } fn init_git_repo(repo_dir: &Path) { - let mut git_init_cmd = Command::new("git"); - git_init_cmd.arg("init").arg("-q").current_dir(repo_dir); + let mut git_init_cmd = git_command(repo_dir, "init"); + git_init_cmd.arg("-q"); spawn_and_wait(git_init_cmd); - let mut git_add_cmd = Command::new("git"); - git_add_cmd.arg("add").arg(".").current_dir(repo_dir); + let mut git_add_cmd = git_command(repo_dir, "add"); + git_add_cmd.arg("."); spawn_and_wait(git_add_cmd); - let mut git_commit_cmd = Command::new("git"); - git_commit_cmd - .arg("-c") - .arg("user.name=Dummy") - .arg("-c") - .arg("user.email=dummy@example.com") - .arg("commit") - .arg("-m") - .arg("Initial commit") - .arg("-q") - .current_dir(repo_dir); + let mut git_commit_cmd = git_command(repo_dir, "commit"); + git_commit_cmd.arg("-m").arg("Initial commit").arg("-q"); spawn_and_wait(git_commit_cmd); } @@ -220,16 +207,8 @@ fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) { target_dir.file_name().unwrap(), patch.file_name().unwrap() ); - let mut apply_patch_cmd = Command::new("git"); - apply_patch_cmd - .arg("-c") - .arg("user.name=Dummy") - .arg("-c") - .arg("user.email=dummy@example.com") - .arg("am") - .arg(patch) - .arg("-q") - .current_dir(target_dir); + let mut apply_patch_cmd = git_command(target_dir, "am"); + apply_patch_cmd.arg(patch).arg("-q"); spawn_and_wait(apply_patch_cmd); } } diff --git a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs index 8e5ab688e13..a70453b4422 100644 --- a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs +++ b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs @@ -1,9 +1,9 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -pub(crate) fn get_rustc_version() -> String { +pub(crate) fn get_rustc_version(rustc: &Path) -> String { let version_info = - Command::new("rustc").stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout; + Command::new(rustc).stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout; String::from_utf8(version_info).unwrap() } @@ -23,6 +23,16 @@ pub(crate) fn get_host_triple() -> String { .to_owned() } +pub(crate) fn get_toolchain_name() -> String { + let active_toolchain = Command::new("rustup") + .stderr(Stdio::inherit()) + .args(&["show", "active-toolchain"]) + .output() + .unwrap() + .stdout; + String::from_utf8(active_toolchain).unwrap().trim().split_once(' ').unwrap().0.to_owned() +} + pub(crate) fn get_cargo_path() -> PathBuf { let cargo_path = Command::new("rustup") .stderr(Stdio::inherit()) @@ -53,8 +63,8 @@ pub(crate) fn get_rustdoc_path() -> PathBuf { Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned() } -pub(crate) fn get_default_sysroot() -> PathBuf { - let default_sysroot = Command::new("rustc") +pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf { + let default_sysroot = Command::new(rustc) .stderr(Stdio::inherit()) .args(&["--print", "sysroot"]) .output() @@ -83,12 +93,3 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String { assert!(file_name.contains(crate_name)); file_name } - -/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to -/// underscores (`_`). This is specially made for the rustc and cargo wrappers -/// which have a dash in the name, and that is not allowed in a crate name. -pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String { - let crate_name = crate_name.replace('-', "_"); - let wrapper_name = get_file_name(&crate_name, crate_type); - wrapper_name.replace('_', "-") -} diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 1c372736ed6..dcfadd73756 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -1,11 +1,10 @@ -use super::build_sysroot; +use super::bench::SIMPLE_RAYTRACER; +use super::build_sysroot::{self, SYSROOT_SRC}; use super::config; use super::path::{Dirs, RelPath}; use super::prepare::GitRepo; -use super::rustc_info::{get_cargo_path, get_wrapper_file_name}; -use super::utils::{ - hyperfine_command, spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler, -}; +use super::rustc_info::get_host_triple; +use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler}; use super::SysrootKind; use std::env; use std::ffi::OsStr; @@ -17,256 +16,111 @@ static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); struct TestCase { config: &'static str, - func: &'static dyn Fn(&TestRunner), + cmd: TestCaseCmd, +} + +enum TestCaseCmd { + Custom { func: &'static dyn Fn(&TestRunner) }, + BuildLib { source: &'static str, crate_types: &'static str }, + BuildBinAndRun { source: &'static str, args: &'static [&'static str] }, + JitBin { source: &'static str, args: &'static str }, } impl TestCase { - const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self { - Self { config, func } + // FIXME reduce usage of custom test case commands + const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self { + Self { config, cmd: TestCaseCmd::Custom { func } } + } + + const fn build_lib( + config: &'static str, + source: &'static str, + crate_types: &'static str, + ) -> Self { + Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } } + } + + const fn build_bin_and_run( + config: &'static str, + source: &'static str, + args: &'static [&'static str], + ) -> Self { + Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } } + } + + const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self { + Self { config, cmd: TestCaseCmd::JitBin { source, args } } } } const NO_SYSROOT_SUITE: &[TestCase] = &[ - TestCase::new("build.mini_core", &|runner| { - runner.run_rustc([ - "example/mini_core.rs", - "--crate-name", - "mini_core", - "--crate-type", - "lib,dylib", - "--target", - &runner.target_compiler.triple, - ]); - }), - TestCase::new("build.example", &|runner| { - runner.run_rustc([ - "example/example.rs", - "--crate-type", - "lib", - "--target", - &runner.target_compiler.triple, - ]); - }), - TestCase::new("jit.mini_core_hello_world", &|runner| { - let mut jit_cmd = runner.rustc_command([ - "-Zunstable-options", - "-Cllvm-args=mode=jit", - "-Cprefer-dynamic", - "example/mini_core_hello_world.rs", - "--cfg", - "jit", - "--target", - &runner.target_compiler.triple, - ]); - jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd"); - spawn_and_wait(jit_cmd); - - eprintln!("[JIT-lazy] mini_core_hello_world"); - let mut jit_cmd = runner.rustc_command([ - "-Zunstable-options", - "-Cllvm-args=mode=jit-lazy", - "-Cprefer-dynamic", - "example/mini_core_hello_world.rs", - "--cfg", - "jit", - "--target", - &runner.target_compiler.triple, - ]); - jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd"); - spawn_and_wait(jit_cmd); - }), - TestCase::new("aot.mini_core_hello_world", &|runner| { - runner.run_rustc([ - "example/mini_core_hello_world.rs", - "--crate-name", - "mini_core_hello_world", - "--crate-type", - "bin", - "-g", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]); - }), + TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"), + TestCase::build_lib("build.example", "example/example.rs", "lib"), + TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"), + TestCase::build_bin_and_run( + "aot.mini_core_hello_world", + "example/mini_core_hello_world.rs", + &["abc", "bcd"], + ), ]; const BASE_SYSROOT_SUITE: &[TestCase] = &[ - TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| { - runner.run_rustc([ - "example/arbitrary_self_types_pointers_and_wrappers.rs", - "--crate-name", - "arbitrary_self_types_pointers_and_wrappers", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []); - }), - TestCase::new("aot.issue_91827_extern_types", &|runner| { - runner.run_rustc([ - "example/issue-91827-extern-types.rs", - "--crate-name", - "issue_91827_extern_types", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("issue_91827_extern_types", []); - }), - TestCase::new("build.alloc_system", &|runner| { - runner.run_rustc([ - "example/alloc_system.rs", - "--crate-type", - "lib", - "--target", - &runner.target_compiler.triple, - ]); - }), - TestCase::new("aot.alloc_example", &|runner| { - runner.run_rustc([ - "example/alloc_example.rs", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("alloc_example", []); - }), - TestCase::new("jit.std_example", &|runner| { - runner.run_rustc([ - "-Zunstable-options", - "-Cllvm-args=mode=jit", - "-Cprefer-dynamic", - "example/std_example.rs", - "--target", - &runner.target_compiler.triple, - ]); - - eprintln!("[JIT-lazy] std_example"); - runner.run_rustc([ - "-Zunstable-options", - "-Cllvm-args=mode=jit-lazy", - "-Cprefer-dynamic", - "example/std_example.rs", - "--target", - &runner.target_compiler.triple, - ]); - }), - TestCase::new("aot.std_example", &|runner| { - runner.run_rustc([ - "example/std_example.rs", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("std_example", ["arg"]); - }), - TestCase::new("aot.dst_field_align", &|runner| { - runner.run_rustc([ - "example/dst-field-align.rs", - "--crate-name", - "dst_field_align", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("dst_field_align", []); - }), - TestCase::new("aot.subslice-patterns-const-eval", &|runner| { - runner.run_rustc([ - "example/subslice-patterns-const-eval.rs", - "--crate-type", - "bin", - "-Cpanic=abort", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("subslice-patterns-const-eval", []); - }), - TestCase::new("aot.track-caller-attribute", &|runner| { - runner.run_rustc([ - "example/track-caller-attribute.rs", - "--crate-type", - "bin", - "-Cpanic=abort", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("track-caller-attribute", []); - }), - TestCase::new("aot.float-minmax-pass", &|runner| { - runner.run_rustc([ - "example/float-minmax-pass.rs", - "--crate-type", - "bin", - "-Cpanic=abort", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("float-minmax-pass", []); - }), - TestCase::new("aot.mod_bench", &|runner| { - runner.run_rustc([ - "example/mod_bench.rs", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("mod_bench", []); - }), - TestCase::new("aot.issue-72793", &|runner| { - runner.run_rustc([ - "example/issue-72793.rs", - "--crate-type", - "bin", - "--target", - &runner.target_compiler.triple, - ]); - runner.run_out_command("issue-72793", []); - }), + TestCase::build_bin_and_run( + "aot.arbitrary_self_types_pointers_and_wrappers", + "example/arbitrary_self_types_pointers_and_wrappers.rs", + &[], + ), + TestCase::build_bin_and_run( + "aot.issue_91827_extern_types", + "example/issue-91827-extern-types.rs", + &[], + ), + TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"), + TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]), + TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""), + TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]), + TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]), + TestCase::build_bin_and_run( + "aot.subslice-patterns-const-eval", + "example/subslice-patterns-const-eval.rs", + &[], + ), + TestCase::build_bin_and_run( + "aot.track-caller-attribute", + "example/track-caller-attribute.rs", + &[], + ), + TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]), + TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]), + TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]), ]; pub(crate) static RAND_REPO: GitRepo = GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand"); -static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand"); +pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand"); pub(crate) static REGEX_REPO: GitRepo = GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex"); -static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex"); +pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex"); pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( "rust-lang", "portable-simd", - "d5cd4a8112d958bd3a252327e0d069a6363249bd", + "582239ac3b32007613df04d7ffa78dc30f4c5645", "portable-simd", ); -static PORTABLE_SIMD: CargoProject = +pub(crate) static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd"); -pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github( - "ebobby", - "simple-raytracer", - "804a7a21b9e673a482797aa289a18ed480e4d813", - "<none>", -); - -pub(crate) static SIMPLE_RAYTRACER: CargoProject = - CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer"); - -static LIBCORE_TESTS: CargoProject = - CargoProject::new(&RelPath::BUILD_SYSROOT.join("sysroot_src/library/core/tests"), "core_tests"); +pub(crate) static LIBCORE_TESTS: CargoProject = + CargoProject::new(&SYSROOT_SRC.join("library/core/tests"), "core_tests"); const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ - TestCase::new("test.rust-random/rand", &|runner| { - spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs)); + TestCase::custom("test.rust-random/rand", &|runner| { + RAND.clean(&runner.dirs); if runner.is_native { eprintln!("[TEST] rust-random/rand"); @@ -280,60 +134,12 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::new("bench.simple-raytracer", &|runner| { - let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap(); - - if runner.is_native { - eprintln!("[BENCH COMPILE] ebobby/simple-raytracer"); - let cargo_clif = RelPath::DIST - .to_path(&runner.dirs) - .join(get_wrapper_file_name("cargo-clif", "bin")); - let manifest_path = SIMPLE_RAYTRACER.manifest_path(&runner.dirs); - let target_dir = SIMPLE_RAYTRACER.target_dir(&runner.dirs); - - let clean_cmd = format!( - "cargo clean --manifest-path {manifest_path} --target-dir {target_dir}", - manifest_path = manifest_path.display(), - target_dir = target_dir.display(), - ); - let llvm_build_cmd = format!( - "cargo build --manifest-path {manifest_path} --target-dir {target_dir}", - manifest_path = manifest_path.display(), - target_dir = target_dir.display(), - ); - let clif_build_cmd = format!( - "{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}", - cargo_clif = cargo_clif.display(), - manifest_path = manifest_path.display(), - target_dir = target_dir.display(), - ); - - let bench_compile = - hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd); - - spawn_and_wait(bench_compile); - - eprintln!("[BENCH RUN] ebobby/simple-raytracer"); - fs::copy( - target_dir.join("debug").join("main"), - RelPath::BUILD.to_path(&runner.dirs).join("raytracer_cg_clif"), - ) - .unwrap(); - - let mut bench_run = - hyperfine_command(0, run_runs, None, "./raytracer_cg_llvm", "./raytracer_cg_clif"); - bench_run.current_dir(RelPath::BUILD.to_path(&runner.dirs)); - spawn_and_wait(bench_run); - } else { - spawn_and_wait(SIMPLE_RAYTRACER.clean(&runner.target_compiler.cargo, &runner.dirs)); - eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)"); - eprintln!("[COMPILE] ebobby/simple-raytracer"); - spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs)); - eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)"); - } + TestCase::custom("test.simple-raytracer", &|runner| { + SIMPLE_RAYTRACER.clean(&runner.dirs); + spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs)); }), - TestCase::new("test.libcore", &|runner| { - spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs)); + TestCase::custom("test.libcore", &|runner| { + LIBCORE_TESTS.clean(&runner.dirs); if runner.is_native { spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs)); @@ -344,8 +150,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::new("test.regex-shootout-regex-dna", &|runner| { - spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs)); + TestCase::custom("test.regex-shootout-regex-dna", &|runner| { + REGEX.clean(&runner.dirs); // newer aho_corasick versions throw a deprecation warning let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags); @@ -364,9 +170,10 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"), ) .unwrap(); - let expected_path = - REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"); - let expected = fs::read_to_string(&expected_path).unwrap(); + let expected = fs::read_to_string( + REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"), + ) + .unwrap(); let output = spawn_and_wait_with_input(run_cmd, input); // Make sure `[codegen mono items] start` doesn't poison the diff @@ -379,27 +186,16 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ let output_matches = expected.lines().eq(output.lines()); if !output_matches { - let res_path = REGEX.source_dir(&runner.dirs).join("res.txt"); - fs::write(&res_path, &output).unwrap(); - - if cfg!(windows) { - println!("Output files don't match!"); - println!("Expected Output:\n{}", expected); - println!("Actual Output:\n{}", output); - } else { - let mut diff = Command::new("diff"); - diff.arg("-u"); - diff.arg(res_path); - diff.arg(expected_path); - spawn_and_wait(diff); - } + println!("Output files don't match!"); + println!("Expected Output:\n{}", expected); + println!("Actual Output:\n{}", output); std::process::exit(1); } } }), - TestCase::new("test.regex", &|runner| { - spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs)); + TestCase::custom("test.regex", &|runner| { + REGEX.clean(&runner.dirs); // newer aho_corasick versions throw a deprecation warning let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags); @@ -425,8 +221,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ spawn_and_wait(build_cmd); } }), - TestCase::new("test.portable-simd", &|runner| { - spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs)); + TestCase::custom("test.portable-simd", &|runner| { + PORTABLE_SIMD.clean(&runner.dirs); let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs); build_cmd.arg("--all-targets"); @@ -445,21 +241,22 @@ pub(crate) fn run_tests( channel: &str, sysroot_kind: SysrootKind, cg_clif_dylib: &Path, - host_triple: &str, - target_triple: &str, + bootstrap_host_compiler: &Compiler, + target_triple: String, ) { - let runner = TestRunner::new(dirs.clone(), host_triple.to_string(), target_triple.to_string()); - if config::get_bool("testsuite.no_sysroot") { - build_sysroot::build_sysroot( + let target_compiler = build_sysroot::build_sysroot( dirs, channel, SysrootKind::None, cg_clif_dylib, - &host_triple, - &target_triple, + bootstrap_host_compiler, + target_triple.clone(), ); + let runner = + TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple); + BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs); runner.run_testsuite(NO_SYSROOT_SUITE); } else { @@ -470,26 +267,29 @@ pub(crate) fn run_tests( let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot"); if run_base_sysroot || run_extended_sysroot { - build_sysroot::build_sysroot( + let target_compiler = build_sysroot::build_sysroot( dirs, channel, sysroot_kind, cg_clif_dylib, - &host_triple, - &target_triple, + bootstrap_host_compiler, + target_triple.clone(), ); - } - if run_base_sysroot { - runner.run_testsuite(BASE_SYSROOT_SUITE); - } else { - eprintln!("[SKIP] base_sysroot tests"); - } + let runner = + TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple); - if run_extended_sysroot { - runner.run_testsuite(EXTENDED_SYSROOT_SUITE); - } else { - eprintln!("[SKIP] extended_sysroot tests"); + if run_base_sysroot { + runner.run_testsuite(BASE_SYSROOT_SUITE); + } else { + eprintln!("[SKIP] base_sysroot tests"); + } + + if run_extended_sysroot { + runner.run_testsuite(EXTENDED_SYSROOT_SUITE); + } else { + eprintln!("[SKIP] extended_sysroot tests"); + } } } @@ -497,84 +297,34 @@ struct TestRunner { is_native: bool, jit_supported: bool, dirs: Dirs, - host_compiler: Compiler, target_compiler: Compiler, } impl TestRunner { - pub fn new(dirs: Dirs, host_triple: String, target_triple: String) -> Self { - let is_native = host_triple == target_triple; - let jit_supported = - target_triple.contains("x86_64") && is_native && !host_triple.contains("windows"); - - let rustc_clif = - RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustc-clif", "bin")); - let rustdoc_clif = - RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustdoc-clif", "bin")); - - let mut rustflags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string()); - let mut runner = vec![]; - - if !is_native { - match target_triple.as_str() { - "aarch64-unknown-linux-gnu" => { - // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - rustflags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rustflags); - runner = vec![ - "qemu-aarch64".to_owned(), - "-L".to_owned(), - "/usr/aarch64-linux-gnu".to_owned(), - ]; - } - "s390x-unknown-linux-gnu" => { - // We are cross-compiling for s390x. Use the correct linker and run tests in qemu. - rustflags = format!("-Clinker=s390x-linux-gnu-gcc{}", rustflags); - runner = vec![ - "qemu-s390x".to_owned(), - "-L".to_owned(), - "/usr/s390x-linux-gnu".to_owned(), - ]; - } - "x86_64-pc-windows-gnu" => { - // We are cross-compiling for Windows. Run tests in wine. - runner = vec!["wine".to_owned()]; - } - _ => { - println!("Unknown non-native platform"); - } - } + pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self { + if let Ok(rustflags) = env::var("RUSTFLAGS") { + target_compiler.rustflags.push(' '); + target_compiler.rustflags.push_str(&rustflags); + } + if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") { + target_compiler.rustdocflags.push(' '); + target_compiler.rustdocflags.push_str(&rustdocflags); } // FIXME fix `#[linkage = "extern_weak"]` without this - if target_triple.contains("darwin") { - rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags); + if target_compiler.triple.contains("darwin") { + target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup"); } - let host_compiler = Compiler { - cargo: get_cargo_path(), - rustc: rustc_clif.clone(), - rustdoc: rustdoc_clif.clone(), - rustflags: String::new(), - rustdocflags: String::new(), - triple: host_triple, - runner: vec![], - }; - - let target_compiler = Compiler { - cargo: get_cargo_path(), - rustc: rustc_clif, - rustdoc: rustdoc_clif, - rustflags: rustflags.clone(), - rustdocflags: rustflags, - triple: target_triple, - runner, - }; - - Self { is_native, jit_supported, dirs, host_compiler, target_compiler } + let jit_supported = is_native + && target_compiler.triple.contains("x86_64") + && !target_compiler.triple.contains("windows"); + + Self { is_native, jit_supported, dirs, target_compiler } } pub fn run_testsuite(&self, tests: &[TestCase]) { - for &TestCase { config, func } in tests { + for TestCase { config, cmd } in tests { let (tag, testname) = config.split_once('.').unwrap(); let tag = tag.to_uppercase(); let is_jit_test = tag == "JIT"; @@ -586,7 +336,47 @@ impl TestRunner { eprintln!("[{tag}] {testname}"); } - func(self); + match *cmd { + TestCaseCmd::Custom { func } => func(self), + TestCaseCmd::BuildLib { source, crate_types } => { + self.run_rustc([source, "--crate-type", crate_types]); + } + TestCaseCmd::BuildBinAndRun { source, args } => { + self.run_rustc([source]); + self.run_out_command( + source.split('/').last().unwrap().split('.').next().unwrap(), + args, + ); + } + TestCaseCmd::JitBin { source, args } => { + let mut jit_cmd = self.rustc_command([ + "-Zunstable-options", + "-Cllvm-args=mode=jit", + "-Cprefer-dynamic", + source, + "--cfg", + "jit", + ]); + if !args.is_empty() { + jit_cmd.env("CG_CLIF_JIT_ARGS", args); + } + spawn_and_wait(jit_cmd); + + eprintln!("[JIT-lazy] {testname}"); + let mut jit_cmd = self.rustc_command([ + "-Zunstable-options", + "-Cllvm-args=mode=jit-lazy", + "-Cprefer-dynamic", + source, + "--cfg", + "jit", + ]); + if !args.is_empty() { + jit_cmd.env("CG_CLIF_JIT_ARGS", args); + } + spawn_and_wait(jit_cmd); + } + } } } @@ -603,6 +393,9 @@ impl TestRunner { cmd.arg("--out-dir"); cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display())); cmd.arg("-Cdebuginfo=2"); + cmd.arg("--target"); + cmd.arg(&self.target_compiler.triple); + cmd.arg("-Cpanic=abort"); cmd.args(args); cmd } @@ -615,10 +408,7 @@ impl TestRunner { spawn_and_wait(self.rustc_command(args)); } - fn run_out_command<'a, I>(&self, name: &str, args: I) - where - I: IntoIterator<Item = &'a str>, - { + fn run_out_command<'a>(&self, name: &str, args: &[&str]) { let mut full_cmd = vec![]; // Prepend the RUN_WRAPPER's @@ -630,7 +420,7 @@ impl TestRunner { BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(), ); - for arg in args.into_iter() { + for arg in args { full_cmd.push(arg.to_string()); } diff --git a/compiler/rustc_codegen_cranelift/build_system/usage.txt b/compiler/rustc_codegen_cranelift/build_system/usage.txt new file mode 100644 index 00000000000..ab98ccc35a5 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build_system/usage.txt @@ -0,0 +1,35 @@ +The build system of cg_clif. + +USAGE: + ./y.rs prepare [--out-dir DIR] + ./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features] + ./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features] + ./y.rs abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features] + ./y.rs bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features] + +OPTIONS: + --debug + Build cg_clif and the standard library in debug mode rather than release mode. + Warning: An unoptimized cg_clif is very slow. + + --sysroot none|clif|llvm + Which sysroot libraries to use: + `none` will not include any standard library in the sysroot. + `clif` will build the standard library using Cranelift. + `llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM. + + --out-dir DIR + Specify the directory in which the download, build and dist directories are stored. + By default this is the working directory. + + --no-unstable-features + Some features are not yet ready for production usage. This option will disable these + features. This includes the JIT mode and inline assembly support. + +REQUIREMENTS: + * Rustup: The build system has a hard coded dependency on rustup to install the right nightly + version and make sure it is used where necessary. + * Git: `./y.rs prepare` uses git for applying patches and on Windows for downloading test repos. + * Curl and tar (non-Windows only): Used by `./y.rs prepare` to download a single commit for + repos. Git will be used to clone the whole repo when using Windows. + * [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.rs bench`. diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index 2be70e8e421..da2a94a0a4f 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -1,12 +1,13 @@ use std::env; use std::fs; -use std::io::Write; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use super::path::{Dirs, RelPath}; -use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path}; +use super::rustc_info::{get_cargo_path, get_rustc_path, get_rustdoc_path}; +#[derive(Clone, Debug)] pub(crate) struct Compiler { pub(crate) cargo: PathBuf, pub(crate) rustc: PathBuf, @@ -18,27 +19,47 @@ pub(crate) struct Compiler { } impl Compiler { - pub(crate) fn host() -> Compiler { + pub(crate) fn bootstrap_with_triple(triple: String) -> Compiler { Compiler { cargo: get_cargo_path(), rustc: get_rustc_path(), rustdoc: get_rustdoc_path(), rustflags: String::new(), rustdocflags: String::new(), - triple: get_host_triple(), + triple, runner: vec![], } } - pub(crate) fn with_triple(triple: String) -> Compiler { - Compiler { - cargo: get_cargo_path(), - rustc: get_rustc_path(), - rustdoc: get_rustdoc_path(), - rustflags: String::new(), - rustdocflags: String::new(), - triple, - runner: vec![], + pub(crate) fn set_cross_linker_and_runner(&mut self) { + match self.triple.as_str() { + "aarch64-unknown-linux-gnu" => { + // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + self.rustflags += " -Clinker=aarch64-linux-gnu-gcc"; + self.rustdocflags += " -Clinker=aarch64-linux-gnu-gcc"; + self.runner = vec![ + "qemu-aarch64".to_owned(), + "-L".to_owned(), + "/usr/aarch64-linux-gnu".to_owned(), + ]; + } + "s390x-unknown-linux-gnu" => { + // We are cross-compiling for s390x. Use the correct linker and run tests in qemu. + self.rustflags += " -Clinker=s390x-linux-gnu-gcc"; + self.rustdocflags += " -Clinker=s390x-linux-gnu-gcc"; + self.runner = vec![ + "qemu-s390x".to_owned(), + "-L".to_owned(), + "/usr/s390x-linux-gnu".to_owned(), + ]; + } + "x86_64-pc-windows-gnu" => { + // We are cross-compiling for Windows. Run tests in wine. + self.runner = vec!["wine".to_owned()]; + } + _ => { + println!("Unknown non-native platform"); + } } } } @@ -65,6 +86,7 @@ impl CargoProject { RelPath::BUILD.join(self.target).to_path(dirs) } + #[must_use] fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command { let mut cmd = Command::new(cargo); @@ -72,11 +94,13 @@ impl CargoProject { .arg("--manifest-path") .arg(self.manifest_path(dirs)) .arg("--target-dir") - .arg(self.target_dir(dirs)); + .arg(self.target_dir(dirs)) + .arg("--frozen"); cmd } + #[must_use] fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command { let mut cmd = self.base_cmd(command, &compiler.cargo, dirs); @@ -105,9 +129,8 @@ impl CargoProject { cmd } - #[must_use] - pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command { - self.base_cmd("clean", cargo, dirs) + pub(crate) fn clean(&self, dirs: &Dirs) { + let _ = fs::remove_dir_all(self.target_dir(dirs)); } #[must_use] @@ -153,6 +176,23 @@ pub(crate) fn hyperfine_command( bench } +#[must_use] +pub(crate) fn git_command<'a>(repo_dir: impl Into<Option<&'a Path>>, cmd: &str) -> Command { + let mut git_cmd = Command::new("git"); + git_cmd + .arg("-c") + .arg("user.name=Dummy") + .arg("-c") + .arg("user.email=dummy@example.com") + .arg("-c") + .arg("core.autocrlf=false") + .arg(cmd); + if let Some(repo_dir) = repo_dir.into() { + git_cmd.current_dir(repo_dir); + } + git_cmd +} + #[track_caller] pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) { let src = src.as_ref(); @@ -169,6 +209,22 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) { } } +// Based on the retry function in rust's src/ci/shared.sh +#[track_caller] +pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) { + for i in 1..tries + 1 { + if i != 1 { + println!("Command failed. Attempt {i}/{tries}:"); + } + if cmd.spawn().unwrap().wait().unwrap().success() { + return; + } + std::thread::sleep(std::time::Duration::from_secs(i * 5)); + } + println!("The command has failed after {tries} attempts."); + process::exit(1); +} + #[track_caller] pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String { let mut child = cmd @@ -190,6 +246,14 @@ pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> Stri String::from_utf8(output.stdout).unwrap() } +pub(crate) fn remove_dir_if_exists(path: &Path) { + match fs::remove_dir_all(&path) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()), + } +} + pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { for entry in fs::read_dir(from).unwrap() { let entry = entry.unwrap(); diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 1760e5836ec..cdfc2e143e6 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -1,10 +1,9 @@ #!/usr/bin/env bash set -e -rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} -rm -rf target/ build/ dist/ perf.data{,.old} y.bin -rm -rf download/ +rm -rf target/ download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb # Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh # FIXME remove at some point in the future rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/ +rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt index 258b67e9314..d49cc90791a 100644 --- a/compiler/rustc_codegen_cranelift/config.txt +++ b/compiler/rustc_codegen_cranelift/config.txt @@ -44,10 +44,8 @@ aot.issue-72793 testsuite.extended_sysroot test.rust-random/rand -bench.simple-raytracer +test.simple-raytracer test.libcore test.regex-shootout-regex-dna test.regex test.portable-simd - -testsuite.abi-cafe diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch deleted file mode 100644 index 89e2b61c1fc..00000000000 --- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch +++ /dev/null @@ -1,35 +0,0 @@ -From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001 -From: bjorn3 <bjorn3@users.noreply.github.com> -Date: Thu, 18 Nov 2021 19:28:40 +0100 -Subject: [PATCH] Disable unsupported tests - ---- - crates/core_simd/src/elements/int.rs | 8 ++++++++ - crates/core_simd/src/elements/uint.rs | 4 ++++ - crates/core_simd/src/masks/full_masks.rs | 6 ++++++ - crates/core_simd/src/vector.rs | 2 ++ - crates/core_simd/tests/masks.rs | 3 --- - 5 files changed, 20 insertions(+), 3 deletions(-) - -diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs -index e8e8f68..7173c24 100644 ---- a/crates/core_simd/src/vector.rs -+++ b/crates/core_simd/src/vector.rs -@@ -250,6 +250,7 @@ where - unsafe { intrinsics::simd_cast(self) } - } - -+ /* - /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector. - /// If an index is out-of-bounds, the lane is instead selected from the `or` vector. - /// -@@ -473,6 +474,7 @@ where - // Cleared ☢️ *mut T Zone - } - } -+ */ - } - - impl<T, const LANES: usize> Copy for Simd<T, LANES> --- -2.25.1 diff --git a/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch index 8d9ee3f25c4..865aa833a5e 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch @@ -18,7 +18,7 @@ new file mode 100644 index 0000000..46fd999 --- /dev/null +++ b/library/core/tests/Cargo.toml -@@ -0,0 +1,11 @@ +@@ -0,0 +1,12 @@ +[package] +name = "core" +version = "0.0.0" @@ -29,6 +29,7 @@ index 0000000..46fd999 +path = "lib.rs" + +[dependencies] -+rand = "0.7" ++rand = { version = "0.8.5", default-features = false } ++rand_xorshift = { version = "0.3.0", default-features = false } -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index d8f28dbcc15..77345b9a17c 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-12-13" +channel = "nightly-2023-01-20" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs index 9362b47fa6d..c993430b830 100644 --- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs @@ -26,7 +26,7 @@ fn main() { env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags); // Ensure that the right toolchain is used - env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN")); + env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME")); let args: Vec<_> = match env::args().nth(1).as_deref() { Some("jit") => { diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs index 3abfcd8ddc8..c187f54a60e 100644 --- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs @@ -24,7 +24,7 @@ fn main() { } // Ensure that the right toolchain is used - env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN")); + env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME")); #[cfg(unix)] Command::new("rustc").args(args).exec(); diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs index a19d72acfa8..a6528ac41ae 100644 --- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs @@ -24,7 +24,7 @@ fn main() { } // Ensure that the right toolchain is used - env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN")); + env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME")); #[cfg(unix)] Command::new("rustdoc").args(args).exec(); diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh index bc4c06ed7d2..34e3981b538 100755 --- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh +++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh @@ -17,10 +17,10 @@ case $1 in done ./clean_all.sh - ./y.rs prepare - (cd build_sysroot && cargo update) + ./y.rs prepare + (cd download/sysroot && cargo update && cargo fetch && cp Cargo.lock ../../build_sysroot/) ;; "commit") git add rust-toolchain build_sysroot/Cargo.lock diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 6c64b7de7da..a08e80dd19a 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -10,7 +10,7 @@ git fetch git checkout -- . git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" -git am ../patches/*-sysroot-*.patch +git -c user.name=Dummy -c user.email=dummy@example.com am ../patches/*-sysroot-*.patch git apply - <<EOF diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml @@ -25,8 +25,8 @@ index d95b5b7f17f..00b6f0e3635 100644 +compiler_builtins = { version = "0.1.66", features = ['rustc-dep-of-std', 'no-asm'] } [dev-dependencies] - rand = "0.7" - rand_xorshift = "0.2" + rand = { version = "0.8.5", default-features = false, features = ["alloc"] } + rand_xorshift = "0.3.0" EOF cat > config.toml <<EOF @@ -51,7 +51,7 @@ popd # FIXME remove once inline asm is fully supported export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc" -export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build_sysroot/sysroot_src; pwd)" +export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd download/sysroot/sysroot_src; pwd)" # Allow the testsuite to use llvm tools host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 12ecb8cf4e1..07c9ae6ee9f 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -11,7 +11,7 @@ pushd rust command -v rg >/dev/null 2>&1 || cargo install ripgrep rm -r tests/ui/{extern/,unsized-locals/,lto/,linkage*} || true -for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{ui,incremental}); do +for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{codegen-units,ui,incremental}); do rm $test done @@ -32,20 +32,13 @@ rm tests/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort # requires compiling with -Cpanic=unwind rm -r tests/ui/macros/rfc-2011-nicer-assert-messages/ rm -r tests/run-make/test-benches +rm tests/ui/test-attrs/test-type.rs # vendor intrinsics rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected rm tests/ui/intrinsics/const-eval-select-x86_64.rs # requires x86_64 vendor intrinsics rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant" -rm tests/ui/simd/intrinsic/generic-bitmask-pass.rs # simd_bitmask unimplemented -rm tests/ui/simd/intrinsic/generic-as.rs # simd_as unimplemented -rm tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs # simd_saturating_add unimplemented rm tests/ui/simd/intrinsic/float-math-pass.rs # simd_fcos unimplemented -rm tests/ui/simd/intrinsic/generic-gather-pass.rs # simd_gather unimplemented -rm tests/ui/simd/intrinsic/generic-select-pass.rs # simd_select_bitmask unimplemented -rm tests/ui/simd/issue-85915-simd-ptrs.rs # simd_gather unimplemented -rm tests/ui/simd/issue-89193.rs # simd_gather unimplemented -rm tests/ui/simd/simd-bitmask.rs # simd_bitmask unimplemented # exotic linkages rm tests/ui/issues/issue-33992.rs # unsupported linkages @@ -64,10 +57,7 @@ rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and near rm tests/ui/target-feature/missing-plusminus.rs # error not implemented rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment rm -r tests/run-make/emit-named-files # requires full --emit support -rm tests/ui/abi/stack-probes.rs # stack probes not yet implemented -rm tests/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented rm -r tests/run-make/repr128-dwarf # debuginfo test -rm tests/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!() # optimization tests # ================== @@ -88,6 +78,20 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/layout/valid_range_oob.rs # different ICE message +rm tests/ui/consts/issue-miri-1910.rs # different error message +rm tests/ui/consts/offset_ub.rs # same +rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same +rm tests/ui/lint/lint-const-item-mutation.rs # same +rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same +rm tests/ui/suggestions/derive-trait-for-method-call.rs # same +rm tests/ui/typeck/issue-46112.rs # same + +rm tests/ui/proc-macro/crt-static.rs # extra warning about -Cpanic=abort for proc macros +rm tests/ui/proc-macro/proc-macro-deprecated-attr.rs # same +rm tests/ui/proc-macro/quote-debug.rs # same +rm tests/ui/proc-macro/no-missing-docs.rs # same +rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs # same + # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended # ============================================================ @@ -102,23 +106,20 @@ rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to b # ============ rm tests/incremental/spike-neg1.rs # errors out for some reason rm tests/incremental/spike-neg2.rs # same -rm tests/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs -rm tests/ui/mir/ssa-analysis-regression-50041.rs # produces ICE -rm tests/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors -rm tests/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301) +rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type filed (#1318) +rm tests/ui/simd/simd-bitmask.rs # crash + +rm tests/ui/dyn-star/dyn-star-to-dyn.rs +rm tests/ui/dyn-star/dispatch-on-pin-mut.rs # bugs in the test suite # ====================== rm tests/ui/backtrace.rs # TODO warning rm tests/ui/simple_global_asm.rs # TODO add needs-asm-support -rm tests/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout -# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason -rm -r tests/run-make/native-link-modifier-bundle rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue -rm tests/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 65cc6b43767..3c34585d419 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -7,6 +7,7 @@ mod returning; use cranelift_module::ModuleError; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::FnAbiOf; +use rustc_session::Session; use rustc_target::abi::call::{Conv, FnAbi}; use rustc_target::spec::abi::Abi; @@ -22,7 +23,7 @@ fn clif_sig_from_fn_abi<'tcx>( default_call_conv: CallConv, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> Signature { - let call_conv = conv_to_call_conv(fn_abi.conv, default_call_conv); + let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv); let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten(); @@ -33,24 +34,32 @@ fn clif_sig_from_fn_abi<'tcx>( Signature { params, returns, call_conv } } -pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallConv { +pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { match c { Conv::Rust | Conv::C => default_call_conv, Conv::RustCold => CallConv::Cold, Conv::X86_64SysV => CallConv::SystemV, Conv::X86_64Win64 => CallConv::WindowsFastcall, - Conv::ArmAapcs - | Conv::CCmseNonSecureCall - | Conv::Msp430Intr + + // Should already get a back compat warning + Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => { + default_call_conv + } + + Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"), + + Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"), + Conv::CCmseNonSecureCall => { + sess.fatal("C-cmse-nonsecure-call call conv is not yet implemented"); + } + + Conv::Msp430Intr | Conv::PtxKernel - | Conv::X86Fastcall - | Conv::X86Intr - | Conv::X86Stdcall - | Conv::X86ThisCall - | Conv::X86VectorCall | Conv::AmdGpuKernel | Conv::AvrInterrupt - | Conv::AvrNonBlockingInterrupt => todo!("{:?}", c), + | Conv::AvrNonBlockingInterrupt => { + unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); + } } } @@ -161,6 +170,12 @@ fn make_local_place<'tcx>( layout: TyAndLayout<'tcx>, is_ssa: bool, ) -> CPlace<'tcx> { + if layout.is_unsized() { + fx.tcx.sess.span_fatal( + fx.mir.local_decls[local].source_info.span, + "unsized locals are not yet supported", + ); + } let place = if is_ssa { if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi { CPlace::new_var_pair(fx, local, layout) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 89d955e8bf2..dffb2ed8f4f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -113,6 +113,8 @@ pub(crate) fn codegen_fn<'tcx>( }; tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block)); + fx.bcx.seal_all_blocks(); + fx.bcx.finalize(); // Recover all necessary data from fx, before accessing func will prevent future access to it. let symbol_name = fx.symbol_name; @@ -303,6 +305,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { let source_info = bb_data.terminator().source_info; fx.set_debug_loc(source_info); + let _print_guard = + crate::PrintOnPanic(|| format!("terminator {:?}", bb_data.terminator().kind)); + match &bb_data.terminator().kind { TerminatorKind::Goto { target } => { if let TerminatorKind::Return = fx.mir[*target].terminator().kind { @@ -464,7 +469,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { *destination, ); } - TerminatorKind::Resume | TerminatorKind::Abort => { + TerminatorKind::Abort => { + codegen_panic_cannot_unwind(fx, source_info); + } + TerminatorKind::Resume => { // FIXME implement unwinding fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } @@ -487,9 +495,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { } }; } - - fx.bcx.seal_all_blocks(); - fx.bcx.finalize(); } fn codegen_stmt<'tcx>( @@ -789,6 +794,7 @@ fn codegen_stmt<'tcx>( StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Deinit(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop | StatementKind::FakeRead(..) | StatementKind::Retag { .. } @@ -932,7 +938,28 @@ pub(crate) fn codegen_panic<'tcx>( codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span); } -pub(crate) fn codegen_panic_inner<'tcx>( +pub(crate) fn codegen_panic_nounwind<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + msg_str: &str, + source_info: mir::SourceInfo, +) { + let msg_ptr = fx.anonymous_str(msg_str); + let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); + let args = [msg_ptr, msg_len]; + + codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span); +} + +pub(crate) fn codegen_panic_cannot_unwind<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + source_info: mir::SourceInfo, +) { + let args = []; + + codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span); +} + +fn codegen_panic_inner<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, lang_item: rustc_hir::LangItem, args: &[Value], @@ -949,11 +976,7 @@ pub(crate) fn codegen_panic_inner<'tcx>( fx.lib_call( &*symbol_name, - vec![ - AbiParam::new(fx.pointer_type), - AbiParam::new(fx.pointer_type), - AbiParam::new(fx.pointer_type), - ], + args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(), vec![], args, ); diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 2dcd42fbd8f..f41af3a9e63 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -35,7 +35,8 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { }, Primitive::F32 => types::F32, Primitive::F64 => types::F64, - Primitive::Pointer => pointer_ty(tcx), + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Primitive::Pointer(_) => pointer_ty(tcx), } } @@ -167,6 +168,15 @@ pub(crate) fn codegen_icmp_imm( } } +pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value { + let mut flags = MemFlags::new(); + flags.set_endianness(match fx.tcx.data_layout.endian { + rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big, + rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little, + }); + fx.bcx.ins().bitcast(dst_ty, flags, val) +} + pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value { if ty == types::I128 { let zero = bcx.ins().iconst(types::I64, 0); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 51450897bfc..49c4f1aaaef 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -530,6 +530,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | StatementKind::Retag(_, _) | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} } } diff --git a/compiler/rustc_codegen_cranelift/src/cranelift_native.rs b/compiler/rustc_codegen_cranelift/src/cranelift_native.rs new file mode 100644 index 00000000000..6c4efca4424 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/cranelift_native.rs @@ -0,0 +1,248 @@ +// Vendored from https://github.com/bytecodealliance/wasmtime/blob/b58a197d33f044193c3d608010f5e6ec394ac07e/cranelift/native/src/lib.rs +// which is licensed as +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// unlike rustc_codegen_cranelift itself. Also applies a small change to remove #![cfg_attr] that +// rust's CI complains about and to fix formatting to match rustc. +// FIXME revert back to the external crate with Cranelift 0.93 +#![allow(warnings)] + +//! Performs autodetection of the host for the purposes of running +//! Cranelift to generate code to run on the same machine. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates, unstable_features)] +#![warn(unused_import_braces)] + +use cranelift_codegen::isa; +use target_lexicon::Triple; + +/// Return an `isa` builder configured for the current host +/// machine, or `Err(())` if the host machine is not supported +/// in the current configuration. +pub fn builder() -> Result<isa::Builder, &'static str> { + builder_with_options(true) +} + +/// Return an `isa` builder configured for the current host +/// machine, or `Err(())` if the host machine is not supported +/// in the current configuration. +/// +/// Selects the given backend variant specifically; this is +/// useful when more than oen backend exists for a given target +/// (e.g., on x86-64). +pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> { + let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err { + isa::LookupError::SupportDisabled => "support for architecture disabled at compile time", + isa::LookupError::Unsupported => "unsupported architecture", + })?; + + #[cfg(target_arch = "x86_64")] + { + use cranelift_codegen::settings::Configurable; + + if !std::is_x86_feature_detected!("sse2") { + return Err("x86 support requires SSE2"); + } + + if !infer_native_flags { + return Ok(isa_builder); + } + + // These are temporarily enabled by default (see #3810 for + // more) so that a default-constructed `Flags` can work with + // default Wasmtime features. Otherwise, the user must + // explicitly use native flags or turn these on when on x86-64 + // platforms to avoid a configuration panic. In order for the + // "enable if detected" logic below to work, we must turn them + // *off* (differing from the default) and then re-enable below + // if present. + isa_builder.set("has_sse3", "false").unwrap(); + isa_builder.set("has_ssse3", "false").unwrap(); + isa_builder.set("has_sse41", "false").unwrap(); + isa_builder.set("has_sse42", "false").unwrap(); + + if std::is_x86_feature_detected!("sse3") { + isa_builder.enable("has_sse3").unwrap(); + } + if std::is_x86_feature_detected!("ssse3") { + isa_builder.enable("has_ssse3").unwrap(); + } + if std::is_x86_feature_detected!("sse4.1") { + isa_builder.enable("has_sse41").unwrap(); + } + if std::is_x86_feature_detected!("sse4.2") { + isa_builder.enable("has_sse42").unwrap(); + } + if std::is_x86_feature_detected!("popcnt") { + isa_builder.enable("has_popcnt").unwrap(); + } + if std::is_x86_feature_detected!("avx") { + isa_builder.enable("has_avx").unwrap(); + } + if std::is_x86_feature_detected!("avx2") { + isa_builder.enable("has_avx2").unwrap(); + } + if std::is_x86_feature_detected!("fma") { + isa_builder.enable("has_fma").unwrap(); + } + if std::is_x86_feature_detected!("bmi1") { + isa_builder.enable("has_bmi1").unwrap(); + } + if std::is_x86_feature_detected!("bmi2") { + isa_builder.enable("has_bmi2").unwrap(); + } + if std::is_x86_feature_detected!("avx512bitalg") { + isa_builder.enable("has_avx512bitalg").unwrap(); + } + if std::is_x86_feature_detected!("avx512dq") { + isa_builder.enable("has_avx512dq").unwrap(); + } + if std::is_x86_feature_detected!("avx512f") { + isa_builder.enable("has_avx512f").unwrap(); + } + if std::is_x86_feature_detected!("avx512vl") { + isa_builder.enable("has_avx512vl").unwrap(); + } + if std::is_x86_feature_detected!("avx512vbmi") { + isa_builder.enable("has_avx512vbmi").unwrap(); + } + if std::is_x86_feature_detected!("lzcnt") { + isa_builder.enable("has_lzcnt").unwrap(); + } + } + + #[cfg(target_arch = "aarch64")] + { + use cranelift_codegen::settings::Configurable; + + if !infer_native_flags { + return Ok(isa_builder); + } + + if std::arch::is_aarch64_feature_detected!("lse") { + isa_builder.enable("has_lse").unwrap(); + } + + if std::arch::is_aarch64_feature_detected!("paca") { + isa_builder.enable("has_pauth").unwrap(); + } + + if cfg!(target_os = "macos") { + // Pointer authentication is always available on Apple Silicon. + isa_builder.enable("sign_return_address").unwrap(); + // macOS enforces the use of the B key for return addresses. + isa_builder.enable("sign_return_address_with_bkey").unwrap(); + } + } + + // There is no is_s390x_feature_detected macro yet, so for now + // we use getauxval from the libc crate directly. + #[cfg(all(target_arch = "s390x", target_os = "linux"))] + { + use cranelift_codegen::settings::Configurable; + + if !infer_native_flags { + return Ok(isa_builder); + } + + let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; + const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768; + if (v & HWCAP_S390X_VXRS_EXT2) != 0 { + isa_builder.enable("has_vxrs_ext2").unwrap(); + // There is no separate HWCAP bit for mie2, so assume + // that any machine with vxrs_ext2 also has mie2. + isa_builder.enable("has_mie2").unwrap(); + } + } + + // `is_riscv_feature_detected` is nightly only for now, use + // getauxval from the libc crate directly as a temporary measure. + #[cfg(all(target_arch = "riscv64", target_os = "linux"))] + { + use cranelift_codegen::settings::Configurable; + + if !infer_native_flags { + return Ok(isa_builder); + } + + let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; + + const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a'); + const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a'); + const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a'); + const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a'); + const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a'); + const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a'); + + if (v & HWCAP_RISCV_EXT_A) != 0 { + isa_builder.enable("has_a").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_C) != 0 { + isa_builder.enable("has_c").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_D) != 0 { + isa_builder.enable("has_d").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_F) != 0 { + isa_builder.enable("has_f").unwrap(); + + // TODO: There doesn't seem to be a bit associated with this extension + // rust enables it with the `f` extension: + // https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43 + isa_builder.enable("has_zicsr").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_M) != 0 { + isa_builder.enable("has_m").unwrap(); + } + + if (v & HWCAP_RISCV_EXT_V) != 0 { + isa_builder.enable("has_v").unwrap(); + } + + // TODO: ZiFencei does not have a bit associated with it + // TODO: Zbkb does not have a bit associated with it + } + + // squelch warnings about unused mut/variables on some platforms. + drop(&mut isa_builder); + drop(infer_native_flags); + + Ok(isa_builder) +} + +#[cfg(test)] +mod tests { + use super::builder; + use cranelift_codegen::isa::CallConv; + use cranelift_codegen::settings; + + #[test] + fn test() { + if let Ok(isa_builder) = builder() { + let flag_builder = settings::builder(); + let isa = isa_builder.finish(settings::Flags::new(flag_builder)).unwrap(); + + if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64); + } else if cfg!(any(unix, target_os = "nebulet")) { + assert_eq!(isa.default_call_conv(), CallConv::SystemV); + } else if cfg!(windows) { + assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall); + } + + if cfg!(target_pointer_width = "64") { + assert_eq!(isa.pointer_bits(), 64); + } else if cfg!(target_pointer_width = "32") { + assert_eq!(isa.pointer_bits(), 32); + } else if cfg!(target_pointer_width = "16") { + assert_eq!(isa.pointer_bits(), 16); + } + } + } +} + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 28fbcb15b2b..3a7421d8b30 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -20,6 +20,14 @@ use indexmap::IndexSet; pub(crate) use emit::{DebugReloc, DebugRelocName}; pub(crate) use unwind::UnwindContext; +pub(crate) fn producer() -> String { + format!( + "cg_clif (rustc {}, cranelift {})", + rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), + cranelift_codegen::VERSION, + ) +} + pub(crate) struct DebugContext { endian: RunTimeEndian, @@ -57,11 +65,7 @@ impl DebugContext { let mut dwarf = DwarfUnit::new(encoding); - let producer = format!( - "cg_clif (rustc {}, cranelift {})", - rustc_interface::util::rustc_version_str().unwrap_or("unknown version"), - cranelift_codegen::VERSION, - ); + let producer = producer(); let comp_dir = tcx .sess .opts diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index f873561c171..d4494a9e45d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -108,6 +108,8 @@ impl OngoingCodegen { self.concurrency_limiter.finished(); + sess.abort_if_errors(); + ( CodegenResults { modules, @@ -169,10 +171,22 @@ fn emit_cgu( fn emit_module( output_filenames: &OutputFilenames, prof: &SelfProfilerRef, - object: cranelift_object::object::write::Object<'_>, + mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, name: String, ) -> Result<CompiledModule, String> { + if object.format() == cranelift_object::object::BinaryFormat::Elf { + let comment_section = object.add_section( + Vec::new(), + b".comment".to_vec(), + cranelift_object::object::SectionKind::OtherString, + ); + let mut producer = vec![0]; + producer.extend(crate::debuginfo::producer().as_bytes()); + producer.push(0); + object.set_section_data(comment_section, producer, 1); + } + let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name)); let mut file = match File::create(&tmp_file) { Ok(file) => file, @@ -399,8 +413,6 @@ pub(crate) fn run_aot( .collect::<Vec<_>>() }); - tcx.sess.abort_if_errors(); - let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string()); let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true); let created_alloc_shim = diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 7bc161fbe55..d2ae6978ca2 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -33,8 +33,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // cast float to int let a_lane = match lane_ty { - types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane), - types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane), + types::F32 => codegen_bitcast(fx, types::I32, a_lane), + types::F64 => codegen_bitcast(fx, types::I64, a_lane), _ => a_lane, }; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index e4ac89a7bec..d561cf139b6 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -21,6 +21,7 @@ mod simd; pub(crate) use cpuid::codegen_cpuid_call; pub(crate) use llvm::codegen_llvm_intrinsic_call; +use rustc_middle::ty::layout::HasParamEnv; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::SubstsRef; use rustc_span::symbol::{kw, sym, Symbol}; @@ -200,7 +201,7 @@ fn bool_to_zero_or_max_uint<'tcx>( let mut res = fx.bcx.ins().bmask(int_ty, val); if ty.is_float() { - res = fx.bcx.ins().bitcast(ty, res); + res = codegen_bitcast(fx, ty, res); } res @@ -240,10 +241,9 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( substs, args, destination, + target, source_info.span, ); - let ret_block = fx.get_block(target); - fx.bcx.ins().jump(ret_block, &[]); } else if codegen_float_intrinsic_call(fx, intrinsic, args, destination) { let ret_block = fx.get_block(target); fx.bcx.ins().jump(ret_block, &[]); @@ -650,7 +650,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(substs.type_at(0)); if layout.abi.is_uninhabited() { with_no_trimmed_paths!({ - crate::base::codegen_panic( + crate::base::codegen_panic_nounwind( fx, &format!("attempted to instantiate uninhabited type `{}`", layout.ty), source_info, @@ -659,9 +659,11 @@ fn codegen_regular_intrinsic_call<'tcx>( return; } - if intrinsic == sym::assert_zero_valid && !fx.tcx.permits_zero_init(layout) { + if intrinsic == sym::assert_zero_valid + && !fx.tcx.permits_zero_init(fx.param_env().and(layout)) + { with_no_trimmed_paths!({ - crate::base::codegen_panic( + crate::base::codegen_panic_nounwind( fx, &format!( "attempted to zero-initialize type `{}`, which is invalid", @@ -674,10 +676,10 @@ fn codegen_regular_intrinsic_call<'tcx>( } if intrinsic == sym::assert_mem_uninitialized_valid - && !fx.tcx.permits_uninit_init(layout) + && !fx.tcx.permits_uninit_init(fx.param_env().and(layout)) { with_no_trimmed_paths!({ - crate::base::codegen_panic( + crate::base::codegen_panic_nounwind( fx, &format!( "attempted to leave type `{}` uninitialized, which is invalid", diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 14f5e918739..b33eb29754a 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -24,6 +24,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( _substs: SubstsRef<'tcx>, args: &[mir::Operand<'tcx>], ret: CPlace<'tcx>, + target: BasicBlock, span: Span, ) { match intrinsic { @@ -277,16 +278,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } else { fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant"); let trap_block = fx.bcx.create_block(); - let dummy_block = fx.bcx.create_block(); let true_ = fx.bcx.ins().iconst(types::I8, 1); fx.bcx.ins().brnz(true_, trap_block, &[]); - fx.bcx.ins().jump(dummy_block, &[]); + let ret_block = fx.get_block(target); + fx.bcx.ins().jump(ret_block, &[]); fx.bcx.switch_to_block(trap_block); crate::trap::trap_unimplemented( fx, "Index argument for `simd_extract` is not a constant", ); - fx.bcx.switch_to_block(dummy_block); return; }; @@ -770,11 +770,119 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - // simd_arith_offset - // simd_scatter - // simd_gather + sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => { + intrinsic_args!(fx, args => (arg); intrinsic); + ret.write_cvalue_transmute(fx, arg); + } + + sym::simd_arith_offset => { + intrinsic_args!(fx, args => (ptr, offset); intrinsic); + + let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); + let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty; + let pointee_size = fx.layout_of(pointee_ty).size.bytes(); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + assert_eq!(lane_count, ret_lane_count); + + for lane_idx in 0..lane_count { + let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx); + let offset_lane = offset.value_lane(fx, lane_idx).load_scalar(fx); + + let ptr_diff = if pointee_size != 1 { + fx.bcx.ins().imul_imm(offset_lane, pointee_size as i64) + } else { + offset_lane + }; + let res_lane = fx.bcx.ins().iadd(ptr_lane, ptr_diff); + let res_lane = CValue::by_val(res_lane, ret_lane_layout); + + ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane); + } + } + + sym::simd_gather => { + intrinsic_args!(fx, args => (val, ptr, mask); intrinsic); + + let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx); + let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); + let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(val_lane_count, ptr_lane_count); + assert_eq!(val_lane_count, mask_lane_count); + assert_eq!(val_lane_count, ret_lane_count); + + let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap(); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + + for lane_idx in 0..ptr_lane_count { + let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx); + let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx); + let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx); + + let if_enabled = fx.bcx.create_block(); + let if_disabled = fx.bcx.create_block(); + let next = fx.bcx.create_block(); + let res_lane = fx.bcx.append_block_param(next, lane_clif_ty); + + fx.bcx.ins().brnz(mask_lane, if_enabled, &[]); + fx.bcx.ins().jump(if_disabled, &[]); + fx.bcx.seal_block(if_enabled); + fx.bcx.seal_block(if_disabled); + + fx.bcx.switch_to_block(if_enabled); + let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0); + fx.bcx.ins().jump(next, &[res]); + + fx.bcx.switch_to_block(if_disabled); + fx.bcx.ins().jump(next, &[val_lane]); + + fx.bcx.seal_block(next); + fx.bcx.switch_to_block(next); + + fx.bcx.ins().nop(); + + ret.place_lane(fx, lane_idx) + .write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout)); + } + } + + sym::simd_scatter => { + intrinsic_args!(fx, args => (val, ptr, mask); intrinsic); + + let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx); + let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); + let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(val_lane_count, ptr_lane_count); + assert_eq!(val_lane_count, mask_lane_count); + + for lane_idx in 0..ptr_lane_count { + let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx); + let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx); + let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx); + + let if_enabled = fx.bcx.create_block(); + let next = fx.bcx.create_block(); + + fx.bcx.ins().brnz(mask_lane, if_enabled, &[]); + fx.bcx.ins().jump(next, &[]); + fx.bcx.seal_block(if_enabled); + + fx.bcx.switch_to_block(if_enabled); + fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_lane, 0); + fx.bcx.ins().jump(next, &[]); + + fx.bcx.seal_block(next); + fx.bcx.switch_to_block(next); + } + } + _ => { - fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic)); + fx.tcx.sess.span_err(span, &format!("Unknown SIMD intrinsic {}", intrinsic)); + // Prevent verifier error + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); } } + let ret_block = fx.get_block(target); + fx.bcx.ins().jump(ret_block, &[]); } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 629d79d5012..d3868730557 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -57,6 +57,8 @@ mod compiler_builtins; mod concurrency_limiter; mod config; mod constant; +// FIXME revert back to the external crate with Cranelift 0.93 +mod cranelift_native; mod debuginfo; mod discriminant; mod driver; @@ -278,12 +280,14 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar } } - if target_triple.architecture == target_lexicon::Architecture::X86_64 { + if let target_lexicon::Architecture::Aarch64(_) | target_lexicon::Architecture::X86_64 = + target_triple.architecture + { // Windows depends on stack probes to grow the committed part of the stack flags_builder.enable("enable_probestack").unwrap(); flags_builder.set("probestack_strategy", "inline").unwrap(); } else { - // __cranelift_probestack is not provided and inline stack probes are only supported on x86_64 + // __cranelift_probestack is not provided and inline stack probes are only supported on AArch64 and x86_64 flags_builder.set("enable_probestack", "false").unwrap(); } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index c10054e7f0d..3e3b6857134 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -46,7 +46,7 @@ pub(crate) fn maybe_create_entry_wrapper( is_main_fn: bool, sigpipe: u8, ) { - let main_ret_ty = tcx.fn_sig(rust_main_def_id).output(); + let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output(); // Given that `main()` has no arguments, // then its return type cannot have // late-bound regions, since late-bound @@ -64,13 +64,20 @@ pub(crate) fn maybe_create_entry_wrapper( ], returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)], call_conv: crate::conv_to_call_conv( + tcx.sess, tcx.sess.target.options.entry_abi, m.target_config().default_call_conv, ), }; let entry_name = tcx.sess.target.options.entry_name.as_ref(); - let cmain_func_id = m.declare_function(entry_name, Linkage::Export, &cmain_sig).unwrap(); + let cmain_func_id = match m.declare_function(entry_name, Linkage::Export, &cmain_sig) { + Ok(func_id) => func_id, + Err(err) => { + tcx.sess + .fatal(&format!("entry symbol `{entry_name}` declared multiple times: {err}")); + } + }; let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx); @@ -162,7 +169,11 @@ pub(crate) fn maybe_create_entry_wrapper( bcx.seal_all_blocks(); bcx.finalize(); } - m.define_function(cmain_func_id, &mut ctx).unwrap(); + + if let Err(err) = m.define_function(cmain_func_id, &mut ctx) { + tcx.sess.fatal(&format!("entry symbol `{entry_name}` defined multiple times: {err}")); + } + unwind_context.add_function(cmain_func_id, &ctx, m.isa()); } } diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs index 7f45bbd8f28..26327dca299 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs @@ -7,7 +7,7 @@ use cranelift_frontend::FunctionBuilder; /// otherwise return the given value and false. pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) { if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { - match bcx.func.dfg[arg_inst] { + match bcx.func.dfg.insts[arg_inst] { // This is the lowering of `Rvalue::Not` InstructionData::IntCompareImm { opcode: Opcode::IcmpImm, @@ -34,7 +34,7 @@ pub(crate) fn maybe_known_branch_taken( return None; }; - match bcx.func.dfg[arg_inst] { + match bcx.func.dfg.insts[arg_inst] { InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => { if test_zero { Some(imm.bits() == 0) diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index fe8af21ac6d..fa06d6c3ba7 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -514,8 +514,8 @@ impl<'tcx> CPlace<'tcx> { (types::I32, types::F32) | (types::F32, types::I32) | (types::I64, types::F64) - | (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data), - _ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(dst_ty, data), + | (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data), + _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data), _ if src_ty.is_vector() || dst_ty.is_vector() => { // FIXME do something more efficient for transmutes between vectors and integers. let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { diff --git a/compiler/rustc_codegen_cranelift/y.rs b/compiler/rustc_codegen_cranelift/y.rs index 02e1e21ade1..fd825d02e35 100755 --- a/compiler/rustc_codegen_cranelift/y.rs +++ b/compiler/rustc_codegen_cranelift/y.rs @@ -3,7 +3,7 @@ # This block is ignored by rustc set -e echo "[BUILD] y.rs" 1>&2 -rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 +rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 -Cpanic=abort exec ${0/.rs/.bin} $@ */ diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a92242b2615..e88c12716ec 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -709,7 +709,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { bx.range_metadata(load, vr); } } - abi::Pointer if vr.start < vr.end && !vr.contains(0) => { + abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => { bx.nonnull_metadata(load); } _ => {} diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 0afc56b4494..c939da9cec3 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -211,7 +211,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let base_addr = self.const_bitcast(base_addr, self.usize_type); let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); let ptr = self.const_bitcast(base_addr + offset, ptr_type); - if layout.primitive() != Pointer { + if !matches!(layout.primitive(), Pointer(_)) { self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) } else { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index ea8ab761146..dc41cb761b5 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -322,13 +322,16 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl ) .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; + + let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx); + llvals.push(cx.scalar_to_backend( InterpScalar::from_pointer( interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), &cx.tcx, ), - abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) }, - cx.type_i8p(), + abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) }, + cx.type_i8p_ext(address_space), )); next_offset = offset + pointer_size; } diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 524d10fb5e2..1326af670cd 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -253,7 +253,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { Int(i, false) => cx.type_from_unsigned_integer(i), F32 => cx.type_f32(), F64 => cx.type_f64(), - Pointer => { + Pointer(address_space) => { // If we know the alignment, pick something better than i8. let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { @@ -262,7 +262,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { else { cx.type_i8() }; - cx.type_ptr_to(pointee) + cx.type_ptr_to_ext(pointee, address_space) } } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 52c8b51796c..d9f8170a3cf 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -849,6 +849,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' /// Helper function to get the LLVM type for a Scalar. Pointers are returned as /// the equivalent integer type. fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type { + let dl = &cx.tcx.data_layout; match scalar.primitive() { Primitive::Int(Integer::I8, _) => cx.type_i8(), Primitive::Int(Integer::I16, _) => cx.type_i16(), @@ -856,7 +857,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty Primitive::Int(Integer::I64, _) => cx.type_i64(), Primitive::F32 => cx.type_f32(), Primitive::F64 => cx.type_f64(), - Primitive::Pointer => cx.type_isize(), + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()), _ => unreachable!(), } } @@ -868,6 +870,7 @@ fn llvm_fixup_input<'ll, 'tcx>( reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, ) -> &'ll Value { + let dl = &bx.tcx.data_layout; match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { @@ -881,8 +884,10 @@ fn llvm_fixup_input<'ll, 'tcx>( let elem_ty = llvm_asm_scalar_type(bx.cx, s); let count = 16 / layout.size.bytes(); let vec_ty = bx.cx.type_vector(elem_ty, count); - if let Primitive::Pointer = s.primitive() { - value = bx.ptrtoint(value, bx.cx.type_isize()); + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + if let Primitive::Pointer(_) = s.primitive() { + let t = bx.type_from_integer(dl.ptr_sized_integer()); + value = bx.ptrtoint(value, t); } bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) } @@ -958,7 +963,7 @@ fn llvm_fixup_output<'ll, 'tcx>( } (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => { value = bx.extract_element(value, bx.const_i32(0)); - if let Primitive::Pointer = s.primitive() { + if let Primitive::Pointer(_) = s.primitive() { value = bx.inttoptr(value, layout.llvm_type(bx.cx)); } value diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 95baa95b021..54ac7a46cf2 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -441,7 +441,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // the WebAssembly specification, which has this feature. This won't be // needed when LLVM enables this `multivalue` feature by default. if !cx.tcx.is_closure(instance.def_id()) { - let abi = cx.tcx.fn_sig(instance.def_id()).abi(); + let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi(); if abi == Abi::Wasm { function_features.push("+multivalue".to_string()); } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 426f57c0608..58ca87524de 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -15,8 +15,8 @@ use crate::errors::{ use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, - ArchiveBuilderBuilder, UnknownArchiveKind, + get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder, + ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind, }; use rustc_session::cstore::DllImport; @@ -66,7 +66,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { archive: &Path, skip: Box<dyn FnMut(&str) -> bool + 'static>, ) -> io::Result<()> { - let archive_ro = match ArchiveRO::open(archive) { + let mut archive = archive.to_path_buf(); + if self.sess.target.llvm_target.contains("-apple-macosx") { + if let Some(new_archive) = try_extract_macho_fat_archive(&self.sess, &archive)? { + archive = new_archive + } + } + let archive_ro = match ArchiveRO::open(&archive) { Ok(ar) => ar, Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), }; @@ -74,7 +80,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { return Ok(()); } self.additions.push(Addition::Archive { - path: archive.to_path_buf(), + path: archive, archive: archive_ro, skip: Box::new(skip), }); @@ -102,7 +108,9 @@ pub struct LlvmArchiveBuilderBuilder; impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> { - if sess.target.arch == "wasm32" || sess.target.arch == "wasm64" { + // FIXME use ArArchiveBuilder on most targets again once reading thin archives is + // implemented + if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" { Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) } else { Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols)) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5e98deae48a..0f33b985489 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -511,7 +511,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { bx.range_metadata(load, scalar.valid_range(bx)); } } - abi::Pointer => { + abi::Pointer(_) => { if !scalar.valid_range(bx).contains(0) { bx.nonnull_metadata(load); } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index acee9134fb9..edb1c160626 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -236,7 +236,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { Scalar::Int(int) => { let data = int.assert_bits(layout.size(self)); let llval = self.const_uint_big(self.type_ix(bitsize), data); - if layout.primitive() == Pointer { + if matches!(layout.primitive(), Pointer(_)) { unsafe { llvm::LLVMConstIntToPtr(llval, llty) } } else { self.const_bitcast(llval, llty) @@ -284,7 +284,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { 1, ) }; - if layout.primitive() != Pointer { + if !matches!(layout.primitive(), Pointer(_)) { unsafe { llvm::LLVMConstPtrToInt(llval, llty) } } else { self.const_bitcast(llval, llty) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 16467b614fe..cad3c5d87b7 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer, + read_target_uint, Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar, }; use rustc_middle::mir::mono::MonoItem; @@ -21,9 +21,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::Lto; -use rustc_target::abi::{ - AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange, -}; +use rustc_target::abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; use std::ops::Range; pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value { @@ -98,12 +96,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; - let address_space = match cx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, - GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { - AddressSpace::DATA - } - }; + let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx); llvals.push(cx.scalar_to_backend( InterpScalar::from_pointer( @@ -111,7 +104,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< &cx.tcx, ), Scalar::Initialized { - value: Primitive::Pointer, + value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size), }, cx.type_i8p_ext(address_space), diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d9ccba07a34..32cd3a4efa2 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>( // // FIXME(#34960) let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = cfg_llvm_root.trim() != ""; + let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); if !custom_llvm_used && target_data_layout != llvm_data_layout { bug!( diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 22c61248b7d..240a9d2f371 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,6 +1,5 @@ use crate::common::CodegenCx; use crate::coverageinfo; -use crate::errors::InstrumentCoverageRequiresLLVM12; use crate::llvm; use llvm::coverageinfo::CounterMappingRegion; @@ -19,8 +18,8 @@ use std::ffi::CString; /// Generates and exports the Coverage Map. /// -/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions -/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at +/// Rust Coverage Map generation supports LLVM Coverage Mapping Format version +/// 6 (zero-based encoded as 5), as defined at /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). /// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) /// bundled with Rust's fork of LLVM. @@ -33,13 +32,10 @@ use std::ffi::CString; pub fn finalize(cx: &CodegenCx<'_, '_>) { let tcx = cx.tcx; - // Ensure the installed version of LLVM supports at least Coverage Map - // Version 5 (encoded as a zero-based value: 4), which was introduced with - // LLVM 12. + // Ensure the installed version of LLVM supports Coverage Map Version 6 + // (encoded as a zero-based value: 5), which was introduced with LLVM 13. let version = coverageinfo::mapping_version(); - if version < 4 { - tcx.sess.emit_fatal(InstrumentCoverageRequiresLLVM12); - } + assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync"); debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); @@ -61,7 +57,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { return; } - let mut mapgen = CoverageMapGenerator::new(tcx, version); + let mut mapgen = CoverageMapGenerator::new(tcx); // Encode coverage mappings and generate function records let mut function_data = Vec::new(); @@ -124,25 +120,18 @@ struct CoverageMapGenerator { } impl CoverageMapGenerator { - fn new(tcx: TyCtxt<'_>, version: u32) -> Self { + fn new(tcx: TyCtxt<'_>) -> Self { let mut filenames = FxIndexSet::default(); - if version >= 5 { - // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) - // requires setting the first filename to the compilation directory. - // Since rustc generates coverage maps with relative paths, the - // compilation directory can be combined with the relative paths - // to get absolute paths, if needed. - let working_dir = tcx - .sess - .opts - .working_dir - .remapped_path_if_available() - .to_string_lossy() - .to_string(); - let c_filename = - CString::new(working_dir).expect("null error converting filename to C string"); - filenames.insert(c_filename); - } + // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) + // requires setting the first filename to the compilation directory. + // Since rustc generates coverage maps with relative paths, the + // compilation directory can be combined with the relative paths + // to get absolute paths, if needed. + let working_dir = + tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string(); + let c_filename = + CString::new(working_dir).expect("null error converting filename to C string"); + filenames.insert(c_filename); Self { filenames } } @@ -306,9 +295,8 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator ) { return None; - } else if ignore_unused_generics - && tcx.generics_of(def_id).requires_monomorphization(tcx) - { + } + if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) { return None; } Some(local_def_id.to_def_id()) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index b6eb5ee183f..f73bbf3d22b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1499,6 +1499,11 @@ pub fn create_vtable_di_node<'ll, 'tcx>( return; } + // When full debuginfo is enabled, we want to try and prevent vtables from being + // merged. Otherwise debuggers will have a hard time mapping from dyn pointer + // to concrete type. + llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 564ab351bd4..54e850f2599 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -122,7 +122,8 @@ fn tag_base_type<'ll, 'tcx>( Primitive::Int(t, _) => t, Primitive::F32 => Integer::I32, Primitive::F64 => Integer::I64, - Primitive::Pointer => { + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Primitive::Pointer(_) => { // If the niche is the NULL value of a reference, then `discr_enum_ty` will be // a RawPtr. CodeView doesn't know what to do with enums whose base type is a // pointer so we fix this up to just be `usize`. diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index b4620997242..001d1ce93d8 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -40,10 +40,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { } #[derive(Diagnostic)] -#[diag(codegen_llvm_instrument_coverage_requires_llvm_12)] -pub(crate) struct InstrumentCoverageRequiresLLVM12; - -#[derive(Diagnostic)] #[diag(codegen_llvm_symbol_already_defined)] pub(crate) struct SymbolAlreadyDefined<'a> { #[primary_span] diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index a6a75eff9a3..dd89c4c59c1 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -149,7 +149,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { emit_va_arg(self, args[0], ret_ty) } } - Primitive::F64 | Primitive::Pointer => { + Primitive::F64 | Primitive::Pointer(_) => { emit_va_arg(self, args[0], ret_ty) } // `va_arg` should never be used with the return type f32. diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 75cd5df9723..c73d233b767 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -7,7 +7,7 @@ use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty, TypeVisitable}; -use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; +use rustc_target::abi::{Abi, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; use smallvec::{smallvec, SmallVec}; @@ -312,14 +312,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { Int(i, _) => cx.type_from_integer(i), F32 => cx.type_f32(), F64 => cx.type_f64(), - Pointer => { + Pointer(address_space) => { // If we know the alignment, pick something better than i8. - let (pointee, address_space) = - if let Some(pointee) = self.pointee_info_at(cx, offset) { - (cx.type_pointee_for_align(pointee.align), pointee.address_space) - } else { - (cx.type_i8(), AddressSpace::DATA) - }; + let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { + cx.type_pointee_for_align(pointee.align) + } else { + cx.type_i8() + }; cx.type_ptr_to_ext(pointee, address_space) } } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 6eb120157da..d3cd085cfb6 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -14,7 +14,7 @@ use tempfile::Builder as TempFileBuilder; use std::error::Error; use std::fs::File; -use std::io; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; // Re-exporting for rustc_codegen_llvm::back::archive @@ -116,11 +116,12 @@ impl<'a> ArArchiveBuilder<'a> { } } -fn try_filter_fat_archs<'a>( +fn try_filter_fat_archs( archs: object::read::Result<&[impl FatArch]>, target_arch: object::Architecture, - archive_map_data: &'a [u8], -) -> io::Result<Option<(&'a [u8], u64)>> { + archive_path: &Path, + archive_map_data: &[u8], +) -> io::Result<Option<PathBuf>> { let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; let desired = match archs.iter().find(|a| a.architecture() == target_arch) { @@ -128,30 +129,38 @@ fn try_filter_fat_archs<'a>( None => return Ok(None), }; - Ok(Some(( + let (mut new_f, extracted_path) = tempfile::Builder::new() + .suffix(archive_path.file_name().unwrap()) + .tempfile()? + .keep() + .unwrap(); + + new_f.write_all( desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?, - desired.offset().into(), - ))) + )?; + + Ok(Some(extracted_path)) } -pub fn try_extract_macho_fat_archive<'a>( +pub fn try_extract_macho_fat_archive( sess: &Session, - archive_bytes: &'a [u8], -) -> io::Result<Option<(&'a [u8], u64)>> { + archive_path: &Path, +) -> io::Result<Option<PathBuf>> { + let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; let target_arch = match sess.target.arch.as_ref() { "aarch64" => object::Architecture::Aarch64, "x86_64" => object::Architecture::X86_64, _ => return Ok(None), }; - match object::macho::FatHeader::parse(archive_bytes) { + match object::macho::FatHeader::parse(&*archive_map) { Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => { - let archs = object::macho::FatHeader::parse_arch32(archive_bytes); - try_filter_fat_archs(archs, target_arch, archive_bytes) + let archs = object::macho::FatHeader::parse_arch32(&*archive_map); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) } Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => { - let archs = object::macho::FatHeader::parse_arch64(archive_bytes); - try_filter_fat_archs(archs, target_arch, archive_bytes) + let archs = object::macho::FatHeader::parse_arch64(&*archive_map); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) } // Not a FatHeader at all, just return None. _ => Ok(None), @@ -164,24 +173,21 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { archive_path: &Path, mut skip: Box<dyn FnMut(&str) -> bool + 'static>, ) -> io::Result<()> { - let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; + let mut archive_path = archive_path.to_path_buf(); + if self.sess.target.llvm_target.contains("-apple-macosx") { + if let Some(new_archive_path) = + try_extract_macho_fat_archive(&self.sess, &archive_path)? + { + archive_path = new_archive_path + } + } + if self.src_archives.iter().any(|archive| archive.0 == archive_path) { return Ok(()); } - let (archive_bytes, offset) = if self.sess.target.llvm_target.contains("-apple-macosx") { - if let Some((sub_archive, archive_offset)) = - try_extract_macho_fat_archive(&self.sess, &*archive_map)? - { - (sub_archive, Some(archive_offset)) - } else { - (&*archive_map, None) - } - } else { - (&*archive_map, None) - }; - - let archive = ArchiveFile::parse(&*archive_bytes) + let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; + let archive = ArchiveFile::parse(&*archive_map) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; let archive_index = self.src_archives.len(); @@ -190,13 +196,9 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { let file_name = String::from_utf8(entry.name().to_vec()) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; if !skip(&file_name) { - let mut range = entry.file_range(); - if let Some(offset) = offset { - range.0 += offset; - } self.entries.push(( file_name.into_bytes(), - ArchiveEntry::FromArchive { archive_index, file_range: range }, + ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, )); } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b148e4185a6..4ac7bea03eb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -599,7 +599,8 @@ fn link_dwarf_object<'a>( cg_results: &CodegenResults, executable_out_filename: &Path, ) { - let dwp_out_filename = executable_out_filename.with_extension("dwp"); + let mut dwp_out_filename = executable_out_filename.to_path_buf().into_os_string(); + dwp_out_filename.push(".dwp"); debug!(?dwp_out_filename, ?executable_out_filename); #[derive(Default)] @@ -1300,12 +1301,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) { return (false, false); } - // If we're only producing artifacts that are archives, no need to preserve - // the objects as they're losslessly contained inside the archives. - if sess.crate_types().iter().all(|&x| x.is_archive()) { - return (false, false); - } - match (sess.split_debuginfo(), sess.opts.unstable_opts.split_dwarf_kind) { // If there is no split debuginfo then do not preserve objects. (SplitDebuginfo::Off, _) => (false, false), diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 32d3cfe6fc6..02b502d948c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -436,7 +436,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx.type_func(&[], cx.type_int()) }; - let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).output(); + let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).no_bound_vars().unwrap().output(); // Given that `main()` has no arguments, // then its return type cannot have // late-bound regions, since late-bound diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8808ad2dcd1..87b819ebc98 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -214,7 +214,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } else if attr.has_name(sym::cmse_nonsecure_entry) { if validate_fn_only_attr(attr.span) - && !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) + && !matches!(tcx.fn_sig(did).skip_binder().abi(), abi::Abi::C { .. }) { struct_span_err!( tcx.sess, @@ -234,7 +234,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } else if attr.has_name(sym::track_caller) { if !tcx.is_closure(did.to_def_id()) && validate_fn_only_attr(attr.span) - && tcx.fn_sig(did).abi() != abi::Abi::Rust + && tcx.fn_sig(did).skip_binder().abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); @@ -266,7 +266,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } } else if attr.has_name(sym::target_feature) { if !tcx.is_closure(did.to_def_id()) - && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal + && tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { // The `#[target_feature]` attribute is allowed on diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1599ccbb259..b0e007ce009 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -414,6 +414,7 @@ fn push_debuginfo_type_name<'tcx>( | ty::Placeholder(..) | ty::Alias(..) | ty::Bound(..) + | ty::GeneratorWitnessMIR(..) | ty::GeneratorWitness(..) => { bug!( "debuginfo: Trying to create type name for \ diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index dd1ac2c74ae..95aad10fdb0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Arguments get assigned to by means of the function being called for arg in mir.args_iter() { - analyzer.assign(arg, mir::START_BLOCK.start_location()); + analyzer.assign(arg, DefLocation::Argument); } // If there exists a local definition that dominates all uses of that local, @@ -64,7 +64,22 @@ enum LocalKind { /// A scalar or a scalar pair local that is neither defined nor used. Unused, /// A scalar or a scalar pair local with a single definition that dominates all uses. - SSA(mir::Location), + SSA(DefLocation), +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum DefLocation { + Argument, + Body(Location), +} + +impl DefLocation { + fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool { + match self { + DefLocation::Argument => true, + DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators), + } + } } struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { @@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { } impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { - fn assign(&mut self, local: mir::Local, location: Location) { + fn assign(&mut self, local: mir::Local, location: DefLocation) { let kind = &mut self.locals[local]; match *kind { LocalKind::ZST => {} LocalKind::Memory => {} - LocalKind::Unused => { - *kind = LocalKind::SSA(location); - } - LocalKind::SSA(_) => { - *kind = LocalKind::Memory; - } + LocalKind::Unused => *kind = LocalKind::SSA(location), + LocalKind::SSA(_) => *kind = LocalKind::Memory, } } @@ -166,7 +177,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); if let Some(local) = place.as_local() { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); if self.locals[local] != LocalKind::Memory { let decl_span = self.fx.mir.local_decls[local].source_info.span; if !self.fx.rvalue_creates_operand(rvalue, decl_span) { @@ -189,7 +200,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> match context { PlaceContext::MutatingUse(MutatingUseContext::Call) | PlaceContext::MutatingUse(MutatingUseContext::Yield) => { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); } PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 978aff511bf..2623a650e07 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -39,7 +39,6 @@ enum MergingSucc { struct TerminatorCodegenHelper<'tcx> { bb: mir::BasicBlock, terminator: &'tcx mir::Terminator<'tcx>, - funclet_bb: Option<mir::BasicBlock>, } impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { @@ -49,28 +48,24 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { &self, fx: &'b mut FunctionCx<'a, 'tcx, Bx>, ) -> Option<&'b Bx::Funclet> { - let funclet_bb = self.funclet_bb?; - if base::wants_msvc_seh(fx.cx.tcx().sess) { - // If `landing_pad_for` hasn't been called yet to create the `Funclet`, - // it has to be now. This may not seem necessary, as RPO should lead - // to all the unwind edges being visited (and so to `landing_pad_for` - // getting called for them), before building any of the blocks inside - // the funclet itself - however, if MIR contains edges that end up not - // being needed in the LLVM IR after monomorphization, the funclet may - // be unreachable, and we don't have yet a way to skip building it in - // such an eventuality (which may be a better solution than this). - if fx.funclets[funclet_bb].is_none() { - fx.landing_pad_for(funclet_bb); - } - - Some( - fx.funclets[funclet_bb] - .as_ref() - .expect("landing_pad_for didn't also create funclets entry"), - ) - } else { - None + let cleanup_kinds = (&fx.cleanup_kinds).as_ref()?; + let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb)?; + // If `landing_pad_for` hasn't been called yet to create the `Funclet`, + // it has to be now. This may not seem necessary, as RPO should lead + // to all the unwind edges being visited (and so to `landing_pad_for` + // getting called for them), before building any of the blocks inside + // the funclet itself - however, if MIR contains edges that end up not + // being needed in the LLVM IR after monomorphization, the funclet may + // be unreachable, and we don't have yet a way to skip building it in + // such an eventuality (which may be a better solution than this). + if fx.funclets[funclet_bb].is_none() { + fx.landing_pad_for(funclet_bb); } + Some( + fx.funclets[funclet_bb] + .as_ref() + .expect("landing_pad_for didn't also create funclets entry"), + ) } /// Get a basic block (creating it if necessary), possibly with cleanup @@ -104,23 +99,24 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { fx: &mut FunctionCx<'a, 'tcx, Bx>, target: mir::BasicBlock, ) -> (bool, bool) { - let target_funclet = fx.cleanup_kinds[target].funclet_bb(target); - let (needs_landing_pad, is_cleanupret) = match (self.funclet_bb, target_funclet) { - (None, None) => (false, false), - (None, Some(_)) => (true, false), - (Some(_), None) => { - let span = self.terminator.source_info.span; - span_bug!(span, "{:?} - jump out of cleanup?", self.terminator); - } - (Some(f), Some(t_f)) => { - if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) { - (false, false) - } else { - (true, true) + if let Some(ref cleanup_kinds) = fx.cleanup_kinds { + let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb); + let target_funclet = cleanup_kinds[target].funclet_bb(target); + let (needs_landing_pad, is_cleanupret) = match (funclet_bb, target_funclet) { + (None, None) => (false, false), + (None, Some(_)) => (true, false), + (Some(f), Some(t_f)) => (f != t_f, f != t_f), + (Some(_), None) => { + let span = self.terminator.source_info.span; + span_bug!(span, "{:?} - jump out of cleanup?", self.terminator); } - } - }; - (needs_landing_pad, is_cleanupret) + }; + (needs_landing_pad, is_cleanupret) + } else { + let needs_landing_pad = !fx.mir[self.bb].is_cleanup && fx.mir[target].is_cleanup; + let is_cleanupret = false; + (needs_landing_pad, is_cleanupret) + } } fn funclet_br<Bx: BuilderMethods<'a, 'tcx>>( @@ -678,8 +674,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); let do_panic = match intrinsic { Inhabited => layout.abi.is_uninhabited(), - ZeroValid => !bx.tcx().permits_zero_init(layout), - MemUninitializedValid => !bx.tcx().permits_uninit_init(layout), + ZeroValid => !bx.tcx().permits_zero_init(bx.param_env().and(layout)), + MemUninitializedValid => !bx.tcx().permits_uninit_init(bx.param_env().and(layout)), }; Some(if do_panic { let msg_str = with_no_visible_paths!({ @@ -1253,9 +1249,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> MergingSucc { debug!("codegen_terminator: {:?}", terminator); - // Create the cleanup bundle, if needed. - let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb); - let helper = TerminatorCodegenHelper { bb, terminator, funclet_bb }; + let helper = TerminatorCodegenHelper { bb, terminator }; let mergeable_succ = || { // Note: any call to `switch_to_block` will invalidate a `true` value @@ -1801,8 +1795,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match (src.layout.abi, dst.layout.abi) { (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. - let src_is_ptr = src_scalar.primitive() == abi::Pointer; - let dst_is_ptr = dst_scalar.primitive() == abi::Pointer; + let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_)); + let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_)); if src_is_ptr == dst_is_ptr { assert_eq!(src.layout.size, dst.layout.size); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 79c66a955e7..bb265b8289e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -1,3 +1,4 @@ +use crate::base; use crate::traits::*; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; @@ -58,7 +59,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>>, /// The funclet status of each basic block - cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>, + cleanup_kinds: Option<IndexVec<mir::BasicBlock, analyze::CleanupKind>>, /// When targeting MSVC, this stores the cleanup info for each funclet BB. /// This is initialized at the same time as the `landing_pads` entry for the @@ -166,7 +167,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( start_bx.set_personality_fn(cx.eh_personality()); } - let cleanup_kinds = analyze::cleanup_kinds(&mir); + let cleanup_kinds = + if base::wants_msvc_seh(cx.tcx().sess) { Some(analyze::cleanup_kinds(&mir)) } else { None }; + let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> = mir.basic_blocks .indices() diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index fbe30154a7c..cf02f59f67b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -9,7 +9,7 @@ use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding}; +use rustc_target::abi::{Abi, Align, FieldsShape, Int, Pointer, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; #[derive(Copy, Clone, Debug)] @@ -209,6 +209,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, cast_to: Ty<'tcx>, ) -> V { + let dl = &bx.tcx().data_layout; let cast_to_layout = bx.cx().layout_of(cast_to); let cast_to_size = cast_to_layout.layout.size(); let cast_to = bx.cx().immediate_backend_type(cast_to_layout); @@ -250,12 +251,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { // Cast to an integer so we don't have to treat a pointer as a // special case. - let (tag, tag_llty) = if tag_scalar.primitive().is_ptr() { - let t = bx.type_isize(); - let tag = bx.ptrtoint(tag_imm, t); - (tag, t) - } else { - (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)) + let (tag, tag_llty) = match tag_scalar.primitive() { + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Pointer(_) => { + let t = bx.type_from_integer(dl.ptr_sized_integer()); + let tag = bx.ptrtoint(tag_imm, t); + (tag, t) + } + _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), }; let tag_size = tag_scalar.size(bx.cx()); diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 19452c8cdc8..60fbceb344d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -91,6 +91,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } | mir::StatementKind::AscribeUserType(..) + | mir::StatementKind::ConstEvalCounter | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 351c701305a..f92277b1113 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -66,7 +66,7 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { if cfg!(debug_assertions) && stab.promotable { let sig = tcx.fn_sig(def_id); assert_eq!( - sig.unsafety(), + sig.skip_binder().unsafety(), hir::Unsafety::Normal, "don't mark const unsafe fns as promotable", // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4709514c82e..a5bc121485d 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -561,8 +561,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time"); } - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - // The step limit has already been hit in a previous call to `before_terminator`. + fn increment_const_eval_counter(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // The step limit has already been hit in a previous call to `increment_const_eval_counter`. if ecx.machine.steps_remaining == 0 { return Ok(()); } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 498c0087387..c52886b77e6 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -151,7 +151,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( // FIXME(oli-obk): we can probably encode closures just like structs | ty::Closure(..) | ty::Generator(..) - | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType), + | ty::GeneratorWitness(..) |ty::GeneratorWitnessMIR(..)=> Err(ValTreeCreationError::NonSupportedType), } } @@ -314,6 +314,7 @@ pub fn valtree_to_const_value<'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::FnPtr(_) | ty::RawPtr(_) | ty::Str diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index cc7b6c91b60..907f014dfb5 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -101,6 +101,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(_, _) | ty::Never | ty::Tuple(_) | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx), @@ -447,7 +448,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } if intrinsic_name == sym::assert_zero_valid { - let should_panic = !self.tcx.permits_zero_init(layout); + let should_panic = !self.tcx.permits_zero_init(self.param_env.and(layout)); if should_panic { M::abort( @@ -461,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } if intrinsic_name == sym::assert_mem_uninitialized_valid { - let should_panic = !self.tcx.permits_uninit_init(layout); + let should_panic = !self.tcx.permits_uninit_init(self.param_env.and(layout)); if should_panic { M::abort( diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 248953de867..76ed7b80f8d 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -244,12 +244,18 @@ pub trait Machine<'mir, 'tcx>: Sized { } /// Called before a basic block terminator is executed. - /// You can use this to detect endlessly running programs. #[inline] fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { Ok(()) } + /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction. + /// You can use this to detect long or endlessly running programs. + #[inline] + fn increment_const_eval_counter(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + /// Called before a global allocation is accessed. /// `def_id` is `Some` if this is the "lazy" allocation of a static. #[inline] diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index befc0928f3d..a1b3985dce4 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -319,7 +319,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); let scalar = alloc.read_scalar( alloc_range(Size::ZERO, size), - /*read_provenance*/ s.is_ptr(), + /*read_provenance*/ matches!(s, abi::Pointer(_)), )?; Some(ImmTy { imm: scalar.into(), layout: mplace.layout }) } @@ -335,11 +335,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields let a_val = alloc.read_scalar( alloc_range(Size::ZERO, a_size), - /*read_provenance*/ a.is_ptr(), + /*read_provenance*/ matches!(a, abi::Pointer(_)), )?; let b_val = alloc.read_scalar( alloc_range(b_offset, b_size), - /*read_provenance*/ b.is_ptr(), + /*read_provenance*/ matches!(b, abi::Pointer(_)), )?; Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index fad4cb06cd6..d101937fd74 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -129,6 +129,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME(#73156): Handle source code coverage in const eval Coverage(..) => {} + ConstEvalCounter => { + M::increment_const_eval_counter(self)?; + } + // Defined to do nothing. These are added by optimization passes, to avoid changing the // size of MIR constantly. Nop => {} diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 19e359986a1..aa539516d5e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -602,6 +602,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Bound(..) | ty::Param(..) | ty::Alias(..) + | ty::GeneratorWitnessMIR(..) | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 57b91df2d07..51624a0c6c8 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -58,7 +58,12 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::deref_mir_constant(tcx, param_env, value) }; - providers.permits_uninit_init = - |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill); - providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero); + providers.permits_uninit_init = |tcx, param_env_and_ty| { + let (param_env, ty) = param_env_and_ty.into_parts(); + util::might_permit_raw_init(tcx, param_env, ty, InitKind::UninitMitigated0x01Fill) + }; + providers.permits_zero_init = |tcx, param_env_and_ty| { + let (param_env, ty) = param_env_and_ty.into_parts(); + util::might_permit_raw_init(tcx, param_env, ty, InitKind::Zero) + }; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 79f1737e32b..f47e3e86ebe 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -693,6 +693,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} } } @@ -754,12 +755,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let ocx = ObligationCtxt::new(&infcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, substs); - let hir_id = tcx - .hir() - .local_def_id_to_hir_id(self.body.source.def_id().expect_local()); let cause = ObligationCause::new( terminator.source_info.span, - hir_id, + self.body.source.def_id().expect_local(), ObligationCauseCode::ItemObligation(callee), ); let normalized_predicates = ocx.normalize(&cause, param_env, predicates); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 54868e418c4..e841500bf3e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") }; substs.as_closure().sig() } else { - self.tcx.fn_sig(did) + self.tcx.fn_sig(did).subst_identity() } } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index dd168a9ac3c..a2f2457487a 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::{ ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, }; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; @@ -230,11 +230,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Equal types, all is good. return true; } - // Normalization reveals opaque types, but we may be validating MIR while computing - // said opaque types, causing cycles. - if (src, dest).has_opaque_types() { - return true; - } crate::util::is_subtype(self.tcx, self.param_env, src, dest) } @@ -377,12 +372,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; - let Some(&f_ty) = layout.field_tys.get(local) else { + let Some(f_ty) = layout.field_tys.get(local) else { self.fail(location, format!("Out of bounds local {:?} for {:?}", local, parent_ty)); return; }; - f_ty + f_ty.ty } else { let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { fail_out_of_bounds(self, location); @@ -766,6 +761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Coverage(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} } diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index 38d9b044981..995363c0edd 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -40,6 +40,7 @@ pub enum CallKind<'tcx> { self_arg: Option<Ident>, desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>, method_did: DefId, + method_substs: SubstsRef<'tcx>, }, /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)` FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> }, @@ -131,6 +132,6 @@ pub fn call_kind<'tcx>( } else { None }; - CallKind::Normal { self_arg, desugaring, method_did } + CallKind::Normal { self_arg, desugaring, method_did, method_substs } }) } diff --git a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs index 4ce107ea68d..48961b7aac6 100644 --- a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs +++ b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs @@ -20,13 +20,14 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy}; /// to the full uninit check). pub fn might_permit_raw_init<'tcx>( tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, ty: TyAndLayout<'tcx>, kind: InitKind, ) -> bool { if tcx.sess.opts.unstable_opts.strict_init_checks { might_permit_raw_init_strict(ty, tcx, kind) } else { - let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() }; + let layout_cx = LayoutCx { tcx, param_env }; might_permit_raw_init_lax(ty, &layout_cx, kind) } } diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index c4122f66498..4e80a285186 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -64,6 +64,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { ty::Foreign(def_id) => self.print_def_path(def_id, &[]), ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), + ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"), } } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 471457f61b2..0a21a4249c8 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -135,7 +135,47 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { // This loop computes the semi[w] for w. semi[w] = w; for v in graph.predecessors(pre_order_to_real[w]) { - // Reachable vertices may have unreachable predecessors, so ignore any of them + // TL;DR: Reachable vertices may have unreachable predecessors, so ignore any of them. + // + // Ignore blocks which are not connected to the entry block. + // + // The algorithm that was used to traverse the graph and build the + // `pre_order_to_real` and `real_to_pre_order` vectors does so by + // starting from the entry block and following the successors. + // Therefore, any blocks not reachable from the entry block will be + // set to `None` in the `pre_order_to_real` vector. + // + // For example, in this graph, A and B should be skipped: + // + // ┌─────┐ + // │ │ + // └──┬──┘ + // │ + // ┌──▼──┐ ┌─────┐ + // │ │ │ A │ + // └──┬──┘ └──┬──┘ + // │ │ + // ┌───────┴───────┐ │ + // │ │ │ + // ┌──▼──┐ ┌──▼──┐ ┌──▼──┐ + // │ │ │ │ │ B │ + // └──┬──┘ └──┬──┘ └──┬──┘ + // │ └──────┬─────┘ + // ┌──▼──┐ │ + // │ │ │ + // └──┬──┘ ┌──▼──┐ + // │ │ │ + // │ └─────┘ + // ┌──▼──┐ + // │ │ + // └──┬──┘ + // │ + // ┌──▼──┐ + // │ │ + // └─────┘ + // + // ...this may be the case if a MirPass modifies the CFG to remove + // or rearrange certain blocks/edges. let Some(v) = real_to_pre_order[v] else { continue }; @@ -264,13 +304,18 @@ fn compress( } } +/// Tracks the list of dominators for each node. #[derive(Clone, Debug)] pub struct Dominators<N: Idx> { post_order_rank: IndexVec<N, usize>, + // Even though we track only the immediate dominator of each node, it's + // possible to get its full list of dominators by looking up the dominator + // of each dominator. (See the `impl Iterator for Iter` definition). immediate_dominators: IndexVec<N, Option<N>>, } impl<Node: Idx> Dominators<Node> { + /// Whether the given Node has an immediate dominator. pub fn is_reachable(&self, node: Node) -> bool { self.immediate_dominators[node].is_some() } @@ -280,12 +325,14 @@ impl<Node: Idx> Dominators<Node> { self.immediate_dominators[node].unwrap() } + /// Provides an iterator over each dominator up the CFG, for the given Node. + /// See the `impl Iterator for Iter` definition to understand how this works. pub fn dominators(&self, node: Node) -> Iter<'_, Node> { assert!(self.is_reachable(node), "node {node:?} is not reachable"); Iter { dominators: self, node: Some(node) } } - pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool { + pub fn dominates(&self, dom: Node, node: Node) -> bool { // FIXME -- could be optimized by using post-order-rank self.dominators(node).any(|n| n == dom) } diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 10e673cd929..dda422c6dd0 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -139,8 +139,7 @@ pub enum ProcessResult<O, E> { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] struct ObligationTreeId(usize); -type ObligationTreeIdGenerator = - std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>; +type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>; pub struct ObligationForest<O: ForestObligation> { /// The list of obligations. In between calls to [Self::process_obligations], diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index f50ad0137b8..ccefd6adaf1 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -296,9 +296,8 @@ fn run_compiler( if let Some(ppm) = &sess.opts.pretty { if ppm.needs_ast_map() { - let expanded_crate = queries.expansion()?.borrow().0.clone(); queries.global_ctxt()?.enter(|tcx| { - pretty::print_after_hir_lowering(tcx, &*expanded_crate, *ppm); + pretty::print_after_hir_lowering(tcx, *ppm); Ok(()) })?; } else { @@ -328,11 +327,15 @@ fn run_compiler( } } - queries.global_ctxt()?; + let mut gctxt = queries.global_ctxt()?; if callbacks.after_expansion(compiler, queries) == Compilation::Stop { return early_exit(); } + // Make sure the `output_filenames` query is run for its side + // effects of writing the dep-info and reporting errors. + gctxt.enter(|tcx| tcx.output_filenames(())); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 { @@ -343,7 +346,7 @@ fn run_compiler( return early_exit(); } - queries.global_ctxt()?.enter(|tcx| { + gctxt.enter(|tcx| { let result = tcx.analysis(()); if sess.opts.unstable_opts.save_analysis { let crate_name = tcx.crate_name(LOCAL_CRATE); @@ -360,6 +363,8 @@ fn run_compiler( result })?; + drop(gctxt); + if callbacks.after_analysis(compiler, queries) == Compilation::Stop { return early_exit(); } diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index ae3ac8625b1..446c6832cb7 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -403,7 +403,7 @@ pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { write_or_print(&out, sess); } -pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm: PpMode) { +pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { if ppm.needs_analysis() { abort_on_err(print_with_analysis(tcx, ppm), tcx.sess); return; @@ -420,7 +420,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm let parse = &sess.parse_sess; pprust::print_crate( sess.source_map(), - krate, + &tcx.resolver_for_lowering(()).borrow().1, src_name, src, annotation.pp_ann(), @@ -433,7 +433,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm AstTree(PpAstTreeMode::Expanded) => { debug!("pretty-printing expanded AST"); - format!("{krate:#?}") + format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1) } Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| { @@ -498,6 +498,21 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante out } + ThirFlat => { + let mut out = String::new(); + abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + debug!("pretty printing THIR flat"); + for did in tcx.hir().body_owners() { + let _ = writeln!( + out, + "{:?}:\n{}\n", + did, + tcx.thir_flat(ty::WithOptConstParam::unknown(did)) + ); + } + out + } + _ => unreachable!(), }; diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 9d5f4ad7520..4ae372bb904 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -506,6 +506,7 @@ E0785: include_str!("./error_codes/E0785.md"), E0786: include_str!("./error_codes/E0786.md"), E0787: include_str!("./error_codes/E0787.md"), E0788: include_str!("./error_codes/E0788.md"), +E0789: include_str!("./error_codes/E0789.md"), E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), E0792: include_str!("./error_codes/E0792.md"), @@ -645,5 +646,4 @@ E0792: include_str!("./error_codes/E0792.md"), // E0721, // `await` keyword // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0789, // rustc_allowed_through_unstable_modules without stability attribute } diff --git a/compiler/rustc_error_codes/src/error_codes/E0587.md b/compiler/rustc_error_codes/src/error_codes/E0587.md index ee9031dc379..d7998af85b9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0587.md +++ b/compiler/rustc_error_codes/src/error_codes/E0587.md @@ -11,6 +11,6 @@ You cannot use `packed` and `align` hints on a same type. If you want to pack a type to a given size, you should provide a size to packed: ``` -#[repr(packed)] // ok! +#[repr(packed(8))] // ok! struct Umbrella(i32); ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0789.md b/compiler/rustc_error_codes/src/error_codes/E0789.md new file mode 100644 index 00000000000..89b7cd422fe --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0789.md @@ -0,0 +1,30 @@ +#### This error code is internal to the compiler and will not be emitted with normal Rust code. + +The internal `rustc_allowed_through_unstable_modules` attribute must be used +on an item with a `stable` attribute. + +Erroneous code example: + +```compile_fail,E0789 +// NOTE: both of these attributes are perma-unstable and should *never* be +// used outside of the compiler and standard library. +#![feature(rustc_attrs)] +#![feature(staged_api)] + +#![unstable(feature = "foo_module", reason = "...", issue = "123")] + +#[rustc_allowed_through_unstable_modules] +// #[stable(feature = "foo", since = "1.0")] +struct Foo; +// ^^^ error: `rustc_allowed_through_unstable_modules` attribute must be +// paired with a `stable` attribute +``` + +Typically when an item is marked with a `stable` attribute, the modules that +enclose the item must also be marked with `stable` attributes, otherwise the +item becomes *de facto* unstable. `#[rustc_allowed_through_unstable_modules]` +is a workaround which allows an item to "escape" its unstable parent modules. +This error occurs when an item is marked with +`#[rustc_allowed_through_unstable_modules]` but no supplementary `stable` +attribute exists. See [#99288](https://github.com/rust-lang/rust/pull/99288) +for an example of `#[rustc_allowed_through_unstable_modules]` in use. diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl index 9e4332c4283..0021638c102 100644 --- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -123,4 +123,7 @@ borrowck_cannot_move_when_borrowed = borrowck_opaque_type_non_generic_param = expected generic {$kind} parameter, found `{$ty}` - .label = this generic parameter must be used with a generic {$kind} parameter + .label = {STREQ($ty, "'static") -> + [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type + *[other] this generic parameter must be used with a generic {$kind} parameter + } diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl index 08ce5172574..6101b28ab0c 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl @@ -23,7 +23,7 @@ codegen_gcc_invalid_monomorphization_unsupported_element = invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` codegen_gcc_invalid_monomorphization_invalid_bitmask = - invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` + invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` codegen_gcc_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl index 860212b051f..b82c903290b 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl @@ -11,9 +11,6 @@ codegen_llvm_unknown_ctarget_feature_prefix = codegen_llvm_error_creating_import_library = Error creating import library for {$lib_name}: {$error} -codegen_llvm_instrument_coverage_requires_llvm_12 = - rustc option `-C instrument-coverage` requires LLVM 12 or higher. - codegen_llvm_symbol_already_defined = symbol `{$symbol_name}` is already defined diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl index c8c7afb5f91..4924105128d 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl @@ -179,9 +179,9 @@ codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$ codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` -codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error} +codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error} -codegen_ssa_read_file = failed to read file: {message} +codegen_ssa_read_file = failed to read file: {$message} codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 164d6d26d23..bcc1d9002df 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -147,8 +147,6 @@ infer_region_explanation = {$pref_kind -> }{$desc_kind -> *[should_not_happen] [{$desc_kind}] [restatic] the static lifetime - [reempty] the empty lifetime - [reemptyuni] the empty lifetime in universe {$desc_arg} [revar] lifetime {$desc_arg} [as_defined] the lifetime `{$desc_arg}` as defined here diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index d63ff77d8e2..dca678dff7a 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -100,6 +100,8 @@ lint_cstring_ptr = getting the inner pointer of a temporary `CString` .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see https://doc.rust-lang.org/reference/destructors.html +lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits + lint_identifier_non_ascii_char = identifier contains non-ASCII characters lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 224855fff8b..f9bda721df3 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -299,10 +299,18 @@ mir_build_borrow_of_moved_value = borrow of moved value .suggestion = borrow this binding in the pattern to avoid moving the value mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time - .label = first mutable borrow, by `{$name}`, occurs here - .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here - .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here - .moved = also moved into `{$name_moved}` here + +mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable + +mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable + +mir_build_moved_while_borrowed = cannot move out of value because it is borrowed + +mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here + +mir_build_borrow = value is borrowed by `{$name}` here + +mir_build_moved = value is moved into `{$name}` here mir_build_union_pattern = cannot use unions in constant patterns diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index 8f063f5082c..1728ef70cba 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces } with a body .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression +parse_inclusive_range_extra_equals = unexpected `=` after inclusive range + .suggestion_remove_eq = use `..=` instead + .note = inclusive ranges end with a single equals sign (`..=`) + +parse_inclusive_range_match_arrow = unexpected `=>` after open range + .suggestion_add_space = add a space between the pattern and `=>` + +parse_inclusive_range_no_end = inclusive range with no end + .suggestion_open_range = use `..` instead + .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + parse_struct_literal_not_allowed_here = struct literals are not allowed here .suggestion = surround the struct literal with parentheses @@ -238,6 +249,7 @@ parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed +parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable .suggestion = initialize the variable diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 91857dd227d..0c2ab3d08f9 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -710,3 +710,24 @@ passes_ignored_derived_impls = [one] trait {$trait_list}, but this is *[other] traits {$trait_list}, but these are } intentionally ignored during dead code analysis + +passes_proc_macro_typeerror = mismatched {$kind} signature + .label = found {$found}, expected type `proc_macro::TokenStream` + .note = {$kind}s must have a signature of `{$expected_signature}` + +passes_proc_macro_diff_arg_count = mismatched {$kind} signature + .label = found unexpected {$count -> + [one] argument + *[other] arguments + } + .note = {$kind}s must have a signature of `{$expected_signature}` + +passes_proc_macro_missing_args = mismatched {$kind} signature + .label = {$kind} must have {$expected_input_count -> + [one] one argument + *[other] two arguments + } of type `proc_macro::TokenStream` + +passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"` + +passes_proc_macro_unsafe = proc macro functions may not be `unsafe` diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 37a51980a08..f053bdc3809 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -182,6 +182,9 @@ pub fn fluent_bundle( trace!(?locale); let mut bundle = new_bundle(vec![locale]); + // Add convenience functions available to ftl authors. + register_functions(&mut bundle); + // Fluent diagnostics can insert directionality isolation markers around interpolated variables // indicating that there may be a shift from right-to-left to left-to-right text (or // vice-versa). These are disabled because they are sometimes visible in the error output, but @@ -244,6 +247,15 @@ pub fn fluent_bundle( Ok(Some(bundle)) } +fn register_functions(bundle: &mut FluentBundle) { + bundle + .add_function("STREQ", |positional, _named| match positional { + [FluentValue::String(a), FluentValue::String(b)] => format!("{}", (a == b)).into(), + _ => FluentValue::Error, + }) + .expect("Failed to add a function to the bundle."); +} + /// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily /// evaluated fluent bundle. pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBundle>>; @@ -256,6 +268,9 @@ pub fn fallback_fluent_bundle( ) -> LazyFallbackBundle { Lrc::new(Lazy::new(move || { let mut fallback_bundle = new_bundle(vec![langid!("en-US")]); + + register_functions(&mut fallback_bundle); + // See comment in `fluent_bundle`. fallback_bundle.set_use_isolating(with_directionality_markers); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 51b2ff6a003..4ad24c1400d 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -629,19 +629,27 @@ impl Diagnostic { applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { - assert!(!suggestion.is_empty()); - debug_assert!( - !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())), - "Span must not be empty and have no suggestion" + let mut parts = suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect::<Vec<_>>(); + + parts.sort_unstable_by_key(|part| part.span); + + assert!(!parts.is_empty()); + debug_assert_eq!( + parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()), + None, + "Span must not be empty and have no suggestion", + ); + debug_assert_eq!( + parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), + None, + "suggestion must not have overlapping parts", ); self.push_suggestion(CodeSuggestion { - substitutions: vec![Substitution { - parts: suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }], + substitutions: vec![Substitution { parts }], msg: self.subdiagnostic_message_to_diagnostic_message(msg), style, applicability, @@ -802,25 +810,34 @@ impl Diagnostic { suggestions: impl IntoIterator<Item = Vec<(Span, String)>>, applicability: Applicability, ) -> &mut Self { - let suggestions: Vec<_> = suggestions.into_iter().collect(); - debug_assert!( - !(suggestions - .iter() - .flatten() - .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())), - "Span must not be empty and have no suggestion" - ); + let substitutions = suggestions + .into_iter() + .map(|sugg| { + let mut parts = sugg + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect::<Vec<_>>(); + + parts.sort_unstable_by_key(|part| part.span); + + assert!(!parts.is_empty()); + debug_assert_eq!( + parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()), + None, + "Span must not be empty and have no suggestion", + ); + debug_assert_eq!( + parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), + None, + "suggestion must not have overlapping parts", + ); + + Substitution { parts } + }) + .collect(); self.push_suggestion(CodeSuggestion { - substitutions: suggestions - .into_iter() - .map(|sugg| Substitution { - parts: sugg - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }) - .collect(), + substitutions, msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::ShowCode, applicability, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 535812fb0e2..d076fc08b0e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,6 +3,7 @@ //! This module contains the code for creating and emitting diagnostics. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] #![feature(drain_filter)] #![feature(if_let_guard)] #![feature(is_terminal)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 4ebd75f0185..cd431f57019 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -10,7 +10,7 @@ use crate::mbe::transcribe::transcribe; use rustc_ast as ast; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; @@ -212,7 +212,6 @@ fn expand_macro<'cx>( }; let arm_span = rhses[i].span(); - let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::<Vec<_>>(); // rhs has holes ( `$id` and `$(...)` that need filled) let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) { Ok(tts) => tts, @@ -224,12 +223,25 @@ fn expand_macro<'cx>( // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. - if rhs_spans.len() == tts.len() { + if tts.len() == rhs.tts.len() { tts = tts.map_enumerated(|i, tt| { let mut tt = tt.clone(); - let mut sp = rhs_spans[i]; - sp = sp.with_ctxt(tt.span().ctxt()); - tt.set_span(sp); + let rhs_tt = &rhs.tts[i]; + let ctxt = tt.span().ctxt(); + match (&mut tt, rhs_tt) { + // preserve the delim spans if able + ( + TokenTree::Delimited(target_sp, ..), + mbe::TokenTree::Delimited(source_sp, ..), + ) => { + target_sp.open = source_sp.open.with_ctxt(ctxt); + target_sp.close = source_sp.close.with_ctxt(ctxt); + } + _ => { + let sp = rhs_tt.span().with_ctxt(ctxt); + tt.set_span(sp); + } + } tt }); } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 196c31302a0..af9c40a3ba5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -160,6 +160,8 @@ declare_features! ( (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), + /// Allows the `multiple_supertrait_upcastable` lint. + (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), /// Allows using `#[prelude_import]` on glob `use` items. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 8e2a13a6c0a..93d16716346 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -83,7 +83,8 @@ impl UnstableFeatures { /// Otherwise, only `RUSTC_BOOTSTRAP=1` will work. pub fn from_environment(krate: Option<&str>) -> Self { // `true` if this is a feature-staged build, i.e., on the beta or stable channel. - let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + let disable_unstable_features = + option_env!("CFG_DISABLE_UNSTABLE_FEATURES").map(|s| s != "0").unwrap_or(false); // Returns whether `krate` should be counted as unstable let is_unstable_crate = |var: &str| { krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name)) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d6566860f81..a063307af0c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -831,8 +831,6 @@ pub struct OwnerNodes<'tcx> { pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, /// Content of local bodies. pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>, - /// Non-owning definitions contained in this owner. - pub local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, } impl<'tcx> OwnerNodes<'tcx> { @@ -862,7 +860,6 @@ impl fmt::Debug for OwnerNodes<'_> { .collect::<Vec<_>>(), ) .field("bodies", &self.bodies) - .field("local_id_to_def_id", &self.local_id_to_def_id) .field("hash_without_bodies", &self.hash_without_bodies) .field("hash_including_bodies", &self.hash_including_bodies) .finish() @@ -2106,8 +2103,8 @@ pub enum LocalSource { } /// Hints at the original code for a `match _ { .. }`. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)] -#[derive(HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum MatchSource { /// A `match _ { .. }`. Normal, @@ -2117,6 +2114,8 @@ pub enum MatchSource { TryDesugar, /// A desugared `<expr>.await`. AwaitDesugar, + /// A desugared `format_args!()`. + FormatArgs, } impl MatchSource { @@ -2128,6 +2127,7 @@ impl MatchSource { ForLoopDesugar => "for", TryDesugar => "?", AwaitDesugar => ".await", + FormatArgs => "format_args!()", } } } @@ -2263,7 +2263,7 @@ pub struct TraitItem<'hir> { pub defaultness: Defaultness, } -impl TraitItem<'_> { +impl<'hir> TraitItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2273,6 +2273,32 @@ impl TraitItem<'_> { pub fn trait_item_id(&self) -> TraitItemId { TraitItemId { owner_id: self.owner_id } } + + /// Expect an [`TraitItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option<BodyId>) { + let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + + /// Expect an [`TraitItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { + let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") }; + (ty, trfn) + } + + /// Expect an [`TraitItemKind::Type`] or panic. + #[track_caller] + pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { + let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") }; + (bounds, ty) + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents a trait method's body (or just argument names). @@ -2325,7 +2351,7 @@ pub struct ImplItem<'hir> { pub vis_span: Span, } -impl ImplItem<'_> { +impl<'hir> ImplItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2335,6 +2361,32 @@ impl ImplItem<'_> { pub fn impl_item_id(&self) -> ImplItemId { ImplItemId { owner_id: self.owner_id } } + + /// Expect an [`ImplItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + + /// Expect an [`ImplItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { + let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") }; + (ty, *body) + } + + /// Expect an [`ImplItemKind::Type`] or panic. + #[track_caller] + pub fn expect_type(&self) -> &'hir Ty<'hir> { + let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") }; + ty + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents various kinds of content within an `impl`. @@ -2995,7 +3047,7 @@ pub struct Item<'hir> { pub vis_span: Span, } -impl Item<'_> { +impl<'hir> Item<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -3005,6 +3057,132 @@ impl Item<'_> { pub fn item_id(&self) -> ItemId { ItemId { owner_id: self.owner_id } } + + /// Expect an [`ItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_extern_crate(&self) -> Option<Symbol> { + let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") }; + s + } + + /// Expect an [`ItemKind::Use`] or panic. + #[track_caller] + pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { + let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") }; + (p, uk) + } + + /// Expect an [`ItemKind::Static`] or panic. + #[track_caller] + pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { + let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") }; + (ty, mutbl, body) + } + /// Expect an [`ItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + /// Expect an [`ItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") }; + (sig, gen, *body) + } + + /// Expect an [`ItemKind::Macro`] or panic. + #[track_caller] + pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { + let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") }; + (def, *mk) + } + + /// Expect an [`ItemKind::Mod`] or panic. + #[track_caller] + pub fn expect_mod(&self) -> &'hir Mod<'hir> { + let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") }; + m + } + + /// Expect an [`ItemKind::ForeignMod`] or panic. + #[track_caller] + pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { + let ItemKind::ForeignMod { abi, items } = self.kind else { self.expect_failed("a foreign module") }; + (abi, items) + } + + /// Expect an [`ItemKind::GlobalAsm`] or panic. + #[track_caller] + pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { + let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") }; + asm + } + + /// Expect an [`ItemKind::TyAlias`] or panic. + #[track_caller] + pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { + let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") }; + (ty, gen) + } + + /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. + /// Expect an [`ItemKind::OpaqueTy`] or panic. + #[track_caller] + pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { + let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") }; + ty + } + + /// Expect an [`ItemKind::Enum`] or panic. + #[track_caller] + pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { + let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") }; + (def, gen) + } + + /// Expect an [`ItemKind::Struct`] or panic. + #[track_caller] + pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") }; + (data, gen) + } + + /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`. + /// Expect an [`ItemKind::Union`] or panic. + #[track_caller] + pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") }; + (data, gen) + } + + /// Expect an [`ItemKind::Trait`] or panic. + #[track_caller] + pub fn expect_trait( + self, + ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { self.expect_failed("a trait") }; + (is_auto, unsafety, gen, bounds, items) + } + + /// Expect an [`ItemKind::TraitAlias`] or panic. + #[track_caller] + pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { + let ItemKind::TraitAlias(gen, bounds) = self.kind else { self.expect_failed("a trait alias") }; + (gen, bounds) + } + + /// Expect an [`ItemKind::Impl`] or panic. + #[track_caller] + pub fn expect_impl(&self) -> &'hir Impl<'hir> { + let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") }; + imp + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3524,6 +3702,13 @@ impl<'hir> Node<'hir> { } } + pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> { + match self { + Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty), + _ => None, + } + } + pub fn body_id(&self) -> Option<BodyId> { match self { Node::TraitItem(TraitItem { @@ -3590,6 +3775,185 @@ impl<'hir> Node<'hir> { pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> { if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None } } + + /// Expect a [`Node::Param`] or panic. + #[track_caller] + pub fn expect_param(self) -> &'hir Param<'hir> { + let Node::Param(this) = self else { self.expect_failed("a parameter") }; + this + } + + /// Expect a [`Node::Item`] or panic. + #[track_caller] + pub fn expect_item(self) -> &'hir Item<'hir> { + let Node::Item(this) = self else { self.expect_failed("a item") }; + this + } + + /// Expect a [`Node::ForeignItem`] or panic. + #[track_caller] + pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { + let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") }; + this + } + + /// Expect a [`Node::TraitItem`] or panic. + #[track_caller] + pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { + let Node::TraitItem(this) = self else { self.expect_failed("a trait item") }; + this + } + + /// Expect a [`Node::ImplItem`] or panic. + #[track_caller] + pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { + let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") }; + this + } + + /// Expect a [`Node::Variant`] or panic. + #[track_caller] + pub fn expect_variant(self) -> &'hir Variant<'hir> { + let Node::Variant(this) = self else { self.expect_failed("a variant") }; + this + } + + /// Expect a [`Node::Field`] or panic. + #[track_caller] + pub fn expect_field(self) -> &'hir FieldDef<'hir> { + let Node::Field(this) = self else { self.expect_failed("a field definition") }; + this + } + + /// Expect a [`Node::AnonConst`] or panic. + #[track_caller] + pub fn expect_anon_const(self) -> &'hir AnonConst { + let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") }; + this + } + + /// Expect a [`Node::Expr`] or panic. + #[track_caller] + pub fn expect_expr(self) -> &'hir Expr<'hir> { + let Node::Expr(this) = self else { self.expect_failed("an expression") }; + this + } + /// Expect a [`Node::ExprField`] or panic. + #[track_caller] + pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { + let Node::ExprField(this) = self else { self.expect_failed("an expression field") }; + this + } + + /// Expect a [`Node::Stmt`] or panic. + #[track_caller] + pub fn expect_stmt(self) -> &'hir Stmt<'hir> { + let Node::Stmt(this) = self else { self.expect_failed("a statement") }; + this + } + + /// Expect a [`Node::PathSegment`] or panic. + #[track_caller] + pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { + let Node::PathSegment(this) = self else { self.expect_failed("a path segment") }; + this + } + + /// Expect a [`Node::Ty`] or panic. + #[track_caller] + pub fn expect_ty(self) -> &'hir Ty<'hir> { + let Node::Ty(this) = self else { self.expect_failed("a type") }; + this + } + + /// Expect a [`Node::TypeBinding`] or panic. + #[track_caller] + pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { + let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") }; + this + } + + /// Expect a [`Node::TraitRef`] or panic. + #[track_caller] + pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { + let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") }; + this + } + + /// Expect a [`Node::Pat`] or panic. + #[track_caller] + pub fn expect_pat(self) -> &'hir Pat<'hir> { + let Node::Pat(this) = self else { self.expect_failed("a pattern") }; + this + } + + /// Expect a [`Node::PatField`] or panic. + #[track_caller] + pub fn expect_pat_field(self) -> &'hir PatField<'hir> { + let Node::PatField(this) = self else { self.expect_failed("a pattern field") }; + this + } + + /// Expect a [`Node::Arm`] or panic. + #[track_caller] + pub fn expect_arm(self) -> &'hir Arm<'hir> { + let Node::Arm(this) = self else { self.expect_failed("an arm") }; + this + } + + /// Expect a [`Node::Block`] or panic. + #[track_caller] + pub fn expect_block(self) -> &'hir Block<'hir> { + let Node::Block(this) = self else { self.expect_failed("a block") }; + this + } + + /// Expect a [`Node::Local`] or panic. + #[track_caller] + pub fn expect_local(self) -> &'hir Local<'hir> { + let Node::Local(this) = self else { self.expect_failed("a local") }; + this + } + + /// Expect a [`Node::Ctor`] or panic. + #[track_caller] + pub fn expect_ctor(self) -> &'hir VariantData<'hir> { + let Node::Ctor(this) = self else { self.expect_failed("a constructor") }; + this + } + + /// Expect a [`Node::Lifetime`] or panic. + #[track_caller] + pub fn expect_lifetime(self) -> &'hir Lifetime { + let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") }; + this + } + + /// Expect a [`Node::GenericParam`] or panic. + #[track_caller] + pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { + let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") }; + this + } + + /// Expect a [`Node::Crate`] or panic. + #[track_caller] + pub fn expect_crate(self) -> &'hir Mod<'hir> { + let Node::Crate(this) = self else { self.expect_failed("a crate") }; + this + } + + /// Expect a [`Node::Infer`] or panic. + #[track_caller] + pub fn expect_infer(self) -> &'hir InferArg { + let Node::Infer(this) = self else { self.expect_failed("an infer") }; + this + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} node, found {self:?}") + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 02641b7cf8f..f632babab0b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -67,6 +67,7 @@ use crate::hir::*; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -364,7 +365,7 @@ pub trait Visitor<'v>: Sized { fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) { walk_fn_decl(self, fd) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: HirId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: LocalDefId) { walk_fn(self, fk, fd, b, id) } fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) { @@ -468,13 +469,16 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { visitor.visit_ty(typ); visitor.visit_nested_body(body); } - ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn( - FnKind::ItemFn(item.ident, generics, sig.header), - sig.decl, - body_id, - item.span, - item.hir_id(), - ), + ItemKind::Fn(ref sig, ref generics, body_id) => { + visitor.visit_id(item.hir_id()); + visitor.visit_fn( + FnKind::ItemFn(item.ident, generics, sig.header), + sig.decl, + body_id, + item.span, + item.owner_id.def_id, + ) + } ItemKind::Macro(..) => { visitor.visit_id(item.hir_id()); } @@ -733,7 +737,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_arm, arms); } ExprKind::Closure(&Closure { - def_id: _, + def_id, binder: _, bound_generic_params, fn_decl, @@ -745,7 +749,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); - visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) + visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id) } ExprKind::Block(ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); @@ -923,9 +927,8 @@ pub fn walk_fn<'v, V: Visitor<'v>>( function_kind: FnKind<'v>, function_declaration: &'v FnDecl<'v>, body_id: BodyId, - id: HirId, + _: LocalDefId, ) { - visitor.visit_id(id); visitor.visit_fn_decl(function_declaration); walk_fn_kind(visitor, function_kind); visitor.visit_nested_body(body_id) @@ -953,26 +956,30 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); visitor.visit_ident(ident); - visitor.visit_generics(generics); - visitor.visit_defaultness(defaultness); + visitor.visit_generics(&generics); + visitor.visit_defaultness(&defaultness); + visitor.visit_id(hir_id); match *kind { TraitItemKind::Const(ref ty, default) => { - visitor.visit_id(hir_id); visitor.visit_ty(ty); walk_list!(visitor, visit_nested_body, default); } TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { - visitor.visit_id(hir_id); visitor.visit_fn_decl(sig.decl); for ¶m_name in param_names { visitor.visit_ident(param_name); } } TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { - visitor.visit_fn(FnKind::Method(ident, sig), sig.decl, body_id, span, hir_id); + visitor.visit_fn( + FnKind::Method(ident, sig), + sig.decl, + body_id, + span, + trait_item.owner_id.def_id, + ); } TraitItemKind::Type(bounds, ref default) => { - visitor.visit_id(hir_id); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, default); } @@ -1002,9 +1009,9 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_ident(ident); visitor.visit_generics(generics); visitor.visit_defaultness(defaultness); + visitor.visit_id(impl_item.hir_id()); match *kind { ImplItemKind::Const(ref ty, body) => { - visitor.visit_id(impl_item.hir_id()); visitor.visit_ty(ty); visitor.visit_nested_body(body); } @@ -1014,11 +1021,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt sig.decl, body_id, impl_item.span, - impl_item.hir_id(), + impl_item.owner_id.def_id, ); } ImplItemKind::Type(ref ty) => { - visitor.visit_id(impl_item.hir_id()); visitor.visit_ty(ty); } } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 54fa5702fbc..9158fc08247 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -244,6 +244,14 @@ language_item_table! { /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; + // Lang items needed for `format_args!()`. + FormatAlignment, sym::format_alignment, format_alignment, Target::Enum, GenericRequirement::None; + FormatArgument, sym::format_argument, format_argument, Target::Struct, GenericRequirement::None; + FormatArguments, sym::format_arguments, format_arguments, Target::Struct, GenericRequirement::None; + FormatCount, sym::format_count, format_count, Target::Enum, GenericRequirement::None; + FormatPlaceholder, sym::format_placeholder, format_placeholder, Target::Struct, GenericRequirement::None; + FormatUnsafeArg, sym::format_unsafe_arg, format_unsafe_arg, Target::Struct, GenericRequirement::None; + ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None; BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1); DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 23423e8f3b3..85d0e02d0b6 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -100,13 +100,8 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<' // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing // the body satisfies the condition of two nodes being different have different // `hash_stable` results. - let OwnerNodes { - hash_including_bodies, - hash_without_bodies: _, - nodes: _, - bodies: _, - local_id_to_def_id: _, - } = *self; + let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } = + *self; hash_including_bodies.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6435b05cef8..bec9f0ff077 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -27,7 +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_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; @@ -37,7 +37,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::astconv_object_safety_violations; @@ -54,7 +54,7 @@ use std::slice; pub struct PathSeg(pub DefId, pub usize); pub trait AstConv<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + fn tcx(&self) -> TyCtxt<'tcx>; fn item_def_id(&self) -> DefId; @@ -131,6 +131,8 @@ pub trait AstConv<'tcx> { { self } + + fn infcx(&self) -> Option<&InferCtxt<'tcx>>; } #[derive(Debug)] @@ -2132,48 +2134,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .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(); + let traits: Vec<_> = + self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); // Don't print `TyErr` to the user. self.report_ambiguous_associated_type( @@ -2232,6 +2194,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Ok((ty, DefKind::AssocTy, assoc_ty_did)) } + fn probe_traits_that_match_assoc_ty( + &self, + qself_ty: Ty<'tcx>, + assoc_ident: Ident, + ) -> Vec<String> { + let tcx = self.tcx(); + + // In contexts that have no inference context, just make a new one. + // We do need a local variable to store it, though. + let infcx_; + let infcx = if let Some(infcx) = self.infcx() { + infcx + } else { + assert!(!qself_ty.needs_infer()); + infcx_ = tcx.infer_ctxt().build(); + &infcx_ + }; + + 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(DUMMY_SP, impl_def_id), + ); + infcx + .can_eq( + ty::ParamEnv::empty(), + 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() + } + fn lookup_assoc_ty( &self, ident: Ident, @@ -3124,8 +3140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = hir.get(fn_hir_id) else { return None }; - let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) = - hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") }; + let i = hir.get_parent(fn_hir_id).expect_item().expect_impl(); let trait_ref = self.instantiate_mono_trait_ref( i.of_trait.as_ref()?, @@ -3140,7 +3155,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref.def_id, )?; - let fn_sig = tcx.bound_fn_sig(assoc.def_id).subst( + let fn_sig = tcx.fn_sig(assoc.def_id).subst( tcx, trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), ); diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 730560cc686..a5c96a8b016 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -2,11 +2,11 @@ use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::NormalizeExt; use crate::traits::{self, TraitEngine, TraitEngineExt}; -use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Limit; +use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; @@ -28,7 +28,7 @@ pub struct Autoderef<'a, 'tcx> { // Meta infos: infcx: &'a InferCtxt<'tcx>, span: Span, - body_id: hir::HirId, + body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, // Current state: @@ -96,14 +96,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { pub fn new( infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_def_id: LocalDefId, span: Span, base_ty: Ty<'tcx>, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, - body_id, + body_id: body_def_id, param_env, state: AutoderefSnapshot { steps: vec![], diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index abc1c2d7b8d..6f4ebc987e6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -14,7 +14,7 @@ use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; @@ -28,7 +28,7 @@ use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCtxt}; +use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _}; use std::ops::ControlFlow; @@ -412,7 +412,6 @@ fn check_opaque_meets_bounds<'tcx>( span: Span, origin: &hir::OpaqueTyOrigin, ) { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, hir::OpaqueTyOrigin::TyAlias => def_id, @@ -438,7 +437,7 @@ fn check_opaque_meets_bounds<'tcx>( _ => re, }); - let misc_cause = traits::ObligationCause::misc(span, hir_id); + let misc_cause = traits::ObligationCause::misc(span, def_id); match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { Ok(()) => {} @@ -666,7 +665,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { DefKind::GlobalAsm => { let it = tcx.hir().item(id); let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; - InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id()); + InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); } _ => {} } @@ -1461,7 +1460,8 @@ fn opaque_type_cycle_error( for def_id in visitor.opaques { let ty_span = tcx.def_span(def_id); if !seen.contains(&ty_span) { - err.span_label(ty_span, &format!("returning this opaque type `{ty}`")); + let descr = if ty.is_impl_trait() { "opaque " } else { "" }; + err.span_label(ty_span, &format!("returning this {descr}type `{ty}`")); seen.insert(ty_span); } err.span_label(sp, &format!("returning here with type `{ty}`")); @@ -1508,3 +1508,34 @@ fn opaque_type_cycle_error( } err.emit() } + +pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator)); + + let typeck = tcx.typeck(def_id); + let param_env = tcx.param_env(def_id); + + let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id]; + debug!(?generator_interior_predicates); + + let infcx = tcx + .infer_ctxt() + // typeck writeback gives us predicates with their regions erased. + // As borrowck already has checked lifetimes, we do not need to do it again. + .ignoring_regions() + // Bind opaque types to `def_id` as they should have been checked by borrowck. + .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) + .build(); + + let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + for (predicate, cause) in generator_interior_predicates { + let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + let errors = fulfillment_cx.select_all_or_error(&infcx); + debug!(?errors); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None); + } +} diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index cfebcceef3c..3115f5f464a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -8,7 +8,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; -use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -147,12 +147,12 @@ fn compare_method_predicate_entailment<'tcx>( // // FIXME(@lcnr): remove that after removing `cause.body_id` from // obligations. - let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); + let impl_m_def_id = impl_m.def_id.expect_local(); let cause = ObligationCause::new( impl_m_span, - impl_m_hir_id, + impl_m_def_id, ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_m.def_id.expect_local(), + impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, }, @@ -198,7 +198,7 @@ fn compare_method_predicate_entailment<'tcx>( // Construct trait parameter environment and then shift it into the placeholder viewpoint. // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. - let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id); + let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); let param_env = ty::ParamEnv::new( tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing, @@ -213,14 +213,14 @@ fn compare_method_predicate_entailment<'tcx>( let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); for (predicate, span) in impl_m_own_bounds { - let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); + let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); let predicate = ocx.normalize(&normalize_cause, param_env, predicate); let cause = ObligationCause::new( span, - impl_m_hir_id, + impl_m_def_id, ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_m.def_id.expect_local(), + impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, }, @@ -249,15 +249,15 @@ fn compare_method_predicate_entailment<'tcx>( let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, - tcx.fn_sig(impl_m.def_id), + tcx.fn_sig(impl_m.def_id).subst_identity(), ); let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig)); - let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id); + let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); debug!("compare_impl_method: impl_fty={:?}", impl_sig); - let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); + let trait_sig = tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); // Next, add all inputs and output as well-formed tys. Importantly, @@ -311,6 +311,7 @@ fn compare_method_predicate_entailment<'tcx>( if !errors.is_empty() { match check_implied_wf { CheckImpliedWfMode::Check => { + let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); return compare_method_predicate_entailment( tcx, impl_m, @@ -336,7 +337,7 @@ fn compare_method_predicate_entailment<'tcx>( let outlives_env = OutlivesEnvironment::with_bounds( param_env, Some(infcx), - infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()), + infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()), ); infcx.process_registered_region_obligations( outlives_env.region_bound_pairs(), @@ -346,6 +347,7 @@ fn compare_method_predicate_entailment<'tcx>( if !errors.is_empty() { // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` + let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); match check_implied_wf { CheckImpliedWfMode::Check => { return compare_method_predicate_entailment( @@ -371,7 +373,7 @@ fn compare_method_predicate_entailment<'tcx>( } CheckImpliedWfMode::Skip => { if infcx.tainted_by_errors().is_none() { - infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors); + infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors); } return Err(tcx .sess @@ -420,8 +422,8 @@ fn extract_bad_args_for_implies_lint<'tcx>( // 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(), + tcx.fn_sig(trait_m.def_id).skip_binder().bound_vars(), + tcx.fn_sig(impl_m.def_id).skip_binder().bound_vars(), ) .filter_map(|(impl_bv, trait_bv)| { if let ty::BoundVariableKind::Region(impl_bv) = impl_bv @@ -538,7 +540,7 @@ fn compare_asyncness<'tcx>( trait_item_span: Option<Span>, ) -> Result<(), ErrorGuaranteed> { if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async { - match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() { + match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { ty::Alias(ty::Opaque, ..) => { // allow both `async fn foo()` and `fn foo() -> impl Future` } @@ -610,13 +612,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let trait_to_impl_substs = impl_trait_ref.substs; - let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); + let impl_m_def_id = impl_m.def_id.expect_local(); + let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = ObligationCause::new( return_span, - impl_m_hir_id, + impl_m_def_id, ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_m.def_id.expect_local(), + impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, }, @@ -633,14 +636,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let ocx = ObligationCtxt::new(infcx); // Normalize the impl signature with fresh variables for lifetime inference. - let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id); + let norm_cause = ObligationCause::misc(return_span, impl_m_def_id); let impl_sig = ocx.normalize( &norm_cause, param_env, infcx.replace_bound_vars_with_fresh_vars( return_span, infer::HigherRankedType, - tcx.fn_sig(impl_m.def_id), + tcx.fn_sig(impl_m.def_id).subst_identity(), ), ); impl_sig.error_reported()?; @@ -650,11 +653,11 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces // them with inference variables. // We will use these inference variables to collect the hidden types of RPITITs. - let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id); + let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_def_id); let unnormalized_trait_sig = tcx .liberate_late_bound_regions( impl_m.def_id, - tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), + tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), ) .fold_with(&mut collector); let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); @@ -732,12 +735,11 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let outlives_environment = OutlivesEnvironment::with_bounds( param_env, Some(infcx), - infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys), ); - infcx.err_ctxt().check_region_obligations_and_report_errors( - impl_m.def_id.expect_local(), - &outlives_environment, - )?; + infcx + .err_ctxt() + .check_region_obligations_and_report_errors(impl_m_def_id, &outlives_environment)?; let mut collected_tys = FxHashMap::default(); for (def_id, (ty, substs)) in collector.types { @@ -819,7 +821,7 @@ struct ImplTraitInTraitCollector<'a, 'tcx> { types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, } impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { @@ -827,7 +829,7 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { ocx: &'a ObligationCtxt<'a, 'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, ) -> Self { ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id } } @@ -916,7 +918,7 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the // span points only at the type `Box<Self`>, but we want to cover the whole // argument pattern and type. - let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") }; + let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx .hir() .body_param_names(body) @@ -1078,12 +1080,12 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option<Span>) { let tcx = infcx.tcx; let mut impl_args = { - let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { - let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) }; + let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }); @@ -1115,7 +1117,7 @@ fn compare_self_type<'tcx>( ty::ImplContainer => impl_trait_ref.self_ty(), ty::TraitContainer => tcx.types.self_param, }; - let self_arg_ty = tcx.fn_sig(method.def_id).input(0); + let self_arg_ty = tcx.fn_sig(method.def_id).subst_identity().input(0); let param_env = ty::ParamEnv::reveal_all(); let infcx = tcx.infer_ctxt().build(); @@ -1348,15 +1350,15 @@ fn compare_number_of_method_arguments<'tcx>( ) -> Result<(), ErrorGuaranteed> { let impl_m_fty = tcx.fn_sig(impl_m.def_id); let trait_m_fty = tcx.fn_sig(trait_m.def_id); - let trait_number_args = trait_m_fty.inputs().skip_binder().len(); - let impl_number_args = impl_m_fty.inputs().skip_binder().len(); + let trait_number_args = trait_m_fty.skip_binder().inputs().skip_binder().len(); + let impl_number_args = impl_m_fty.skip_binder().inputs().skip_binder().len(); if trait_number_args != impl_number_args { let trait_span = trait_m .def_id .as_local() .and_then(|def_id| { - let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) }; + let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); trait_m_sig.decl.inputs.get(pos).map(|arg| { if pos == 0 { @@ -1368,7 +1370,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .or(trait_item_span); - let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let pos = impl_number_args.saturating_sub(1); let impl_span = impl_m_sig .decl @@ -1504,7 +1506,7 @@ fn compare_synthetic_generics<'tcx>( let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); - let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() }; + let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; struct Visitor(Option<Span>, hir::def_id::LocalDefId); @@ -1671,14 +1673,12 @@ pub(super) fn compare_impl_const_raw( // Create a parameter environment that represents the implementation's // method. - let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def); - // Compute placeholder form of impl and trait const tys. let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()); let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs); let mut cause = ObligationCause::new( impl_c_span, - impl_c_hir_id, + impl_const_item_def, ObligationCauseCode::CompareImplItemObligation { impl_item_def_id: impl_const_item_def, trait_item_def_id: trait_const_item_def, @@ -1704,7 +1704,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") }; + let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1717,7 +1717,7 @@ pub(super) fn compare_impl_const_raw( let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { // Add a label to the Span containing just the type of the const - let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") }; + let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); ty.span }); @@ -1799,7 +1799,7 @@ fn compare_type_predicate_entailment<'tcx>( // This `HirId` should be used for the `body_id` field on each // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. - let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); + let impl_ty_def_id = impl_ty.def_id.expect_local(); debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs); // The predicates declared by the impl definition, the trait and the @@ -1814,7 +1814,7 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); - let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); + let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id); let param_env = ty::ParamEnv::new( tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing, @@ -1827,12 +1827,12 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); for (predicate, span) in impl_ty_own_bounds { - let cause = ObligationCause::misc(span, impl_ty_hir_id); + let cause = ObligationCause::misc(span, impl_ty_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); let cause = ObligationCause::new( span, - impl_ty_hir_id, + impl_ty_def_id, ObligationCauseCode::CompareImplItemObligation { impl_item_def_id: impl_ty.def_id.expect_local(), trait_item_def_id: trait_ty.def_id, @@ -2008,7 +2008,7 @@ pub(super) fn check_type_bounds<'tcx>( }; debug!(?normalize_param_env); - let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); + let impl_ty_def_id = impl_ty.def_id.expect_local(); let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); @@ -2020,7 +2020,7 @@ pub(super) fn check_type_bounds<'tcx>( let normalize_cause = ObligationCause::new( impl_ty_span, - impl_ty_hir_id, + impl_ty_def_id, ObligationCauseCode::CheckAssociatedTypeBounds { impl_item_def_id: impl_ty.def_id.expect_local(), trait_item_def_id: trait_ty.def_id, @@ -2032,7 +2032,7 @@ pub(super) fn check_type_bounds<'tcx>( } else { traits::BindingObligation(trait_ty.def_id, span) }; - ObligationCause::new(impl_ty_span, impl_ty_hir_id, code) + ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; let obligations = tcx @@ -2063,7 +2063,7 @@ pub(super) fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types); + let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types); let outlives_environment = OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 598dc2dca5c..955cacf03b1 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -56,8 +56,14 @@ fn equate_intrinsic_type<'tcx>( && gen_count_ok(own_counts.consts, 0, "const") { let fty = tcx.mk_fn_ptr(sig); - let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType); - require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty); + let it_def_id = it.owner_id.def_id; + let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType); + require_same_types( + tcx, + &cause, + tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), + fty, + ); } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 82030d82f57..122b6ead8e9 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy}; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::{Symbol, DUMMY_SP}; use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; @@ -253,10 +254,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { Some(asm_ty) } - pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) { - let hir = self.tcx.hir(); - let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id(); - let target_features = self.tcx.asm_target_features(enclosing_def_id); + pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { + let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id()); let Some(asm_arch) = self.tcx.sess.asm_arch else { self.tcx.sess.delay_span_bug(DUMMY_SP, "target architecture does not support asm"); return; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 14bca34b77b..bec693439a4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -105,6 +105,7 @@ pub fn provide(providers: &mut Providers) { region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, + check_generator_obligations: check::check_generator_obligations, ..*providers }; } @@ -445,7 +446,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { // regions just fine, showing `fn(&MyType)`. fn_sig_suggestion( tcx, - tcx.fn_sig(assoc.def_id).skip_binder(), + tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(), assoc.ident(tcx), tcx.predicates_of(assoc.def_id), assoc, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 11237afe8a0..5b9b57da382 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -37,7 +37,7 @@ use std::ops::{ControlFlow, Deref}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { pub(super) ocx: ObligationCtxt<'a, 'tcx>, span: Span, - body_id: hir::HirId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> { @@ -59,7 +59,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { T: TypeFoldable<'tcx>, { self.ocx.normalize( - &ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)), + &ObligationCause::new(span, self.body_def_id, ObligationCauseCode::WellFormed(loc)), self.param_env, value, ) @@ -71,8 +71,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { loc: Option<WellFormedLoc>, arg: ty::GenericArg<'tcx>, ) { - let cause = - traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)); + let cause = traits::ObligationCause::new( + span, + self.body_def_id, + ObligationCauseCode::WellFormed(loc), + ); // for a type to be WF, we do not need to check if const trait predicates satisfy. let param_env = self.param_env.without_const(); self.ocx.register_obligation(traits::Obligation::new( @@ -93,11 +96,10 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>), { let param_env = tcx.param_env(body_def_id); - let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id); let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(infcx); - let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env }; + let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; if !tcx.features().trivial_bounds { wfcx.check_false_global_bounds() @@ -105,7 +107,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( f(&mut wfcx); let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id); - let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types); + let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); let errors = wfcx.select_all_or_error(); if !errors.is_empty() { @@ -374,7 +376,6 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe continue; } - let item_hir_id = item.id.hir_id(); let param_env = tcx.param_env(item_def_id); let item_required_bounds = match item.kind { @@ -385,12 +386,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. let sig: ty::FnSig<'_> = tcx.liberate_late_bound_regions( item_def_id.to_def_id(), - tcx.fn_sig(item_def_id), + tcx.fn_sig(item_def_id).subst_identity(), ); gather_gat_bounds( tcx, param_env, - item_hir_id, + item_def_id, sig.inputs_and_output, // We also assume that all of the function signature's parameter types // are well formed. @@ -412,7 +413,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe gather_gat_bounds( tcx, param_env, - item_hir_id, + item_def_id, tcx.explicit_item_bounds(item_def_id).to_vec(), &FxIndexSet::default(), gat_def_id.def_id, @@ -458,7 +459,6 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id); debug!(?required_bounds); let param_env = tcx.param_env(gat_def_id); - let gat_hir = gat_item_hir.hir_id(); let mut unsatisfied_bounds: Vec<_> = required_bounds .into_iter() @@ -466,13 +466,25 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( a, b, - ))) => { - !region_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b) - } + ))) => !region_known_to_outlive( + tcx, + gat_def_id.def_id, + param_env, + &FxIndexSet::default(), + a, + b, + ), ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( a, b, - ))) => !ty_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b), + ))) => !ty_known_to_outlive( + tcx, + gat_def_id.def_id, + param_env, + &FxIndexSet::default(), + a, + b, + ), _ => bug!("Unexpected PredicateKind"), }) .map(|clause| clause.to_string()) @@ -551,7 +563,7 @@ fn augment_param_env<'tcx>( fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - item_hir: hir::HirId, + item_def_id: hir::OwnerId, to_check: T, wf_tys: &FxIndexSet<Ty<'tcx>>, gat_def_id: LocalDefId, @@ -584,7 +596,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( // reflected in a where clause on the GAT itself. for (ty, ty_idx) in &types { // In our example, requires that `Self: 'a` - if ty_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *ty, *region_a) { + if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) { debug!(?ty_idx, ?region_a_idx); debug!("required clause: {ty} must outlive {region_a}"); // Translate into the generic parameters of the GAT. In @@ -622,7 +634,14 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( if ty::ReStatic == **region_b || region_a == region_b { continue; } - if region_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *region_a, *region_b) { + if region_known_to_outlive( + tcx, + item_def_id.def_id, + param_env, + &wf_tys, + *region_a, + *region_b, + ) { debug!(?region_a_idx, ?region_b_idx); debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. @@ -658,7 +677,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( /// `ty` outlives `region`. fn ty_known_to_outlive<'tcx>( tcx: TyCtxt<'tcx>, - id: hir::HirId, + id: LocalDefId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxIndexSet<Ty<'tcx>>, ty: Ty<'tcx>, @@ -675,7 +694,7 @@ fn ty_known_to_outlive<'tcx>( /// `region_a` outlives `region_b` fn region_known_to_outlive<'tcx>( tcx: TyCtxt<'tcx>, - id: hir::HirId, + id: LocalDefId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxIndexSet<Ty<'tcx>>, region_a: ty::Region<'tcx>, @@ -699,7 +718,7 @@ fn region_known_to_outlive<'tcx>( /// to be tested), then resolve region and return errors fn resolve_regions_with_wf_tys<'tcx>( tcx: TyCtxt<'tcx>, - id: hir::HirId, + id: LocalDefId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxIndexSet<Ty<'tcx>>, add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>), @@ -822,7 +841,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if tcx.object_safety_violations(trait_def_id).is_empty() { + if tcx.check_is_object_safe(trait_def_id) { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); @@ -1006,7 +1025,7 @@ fn check_associated_item( wfcx.register_wf_obligation(span, loc, ty.into()); } ty::AssocKind::Fn => { - let sig = tcx.fn_sig(item.def_id); + let sig = tcx.fn_sig(item.def_id).subst_identity(); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( wfcx, @@ -1053,8 +1072,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // All field types must be well-formed. for field in &variant.fields { let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_wf_obligation( hir_ty.span, @@ -1087,13 +1106,13 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_bound( traits::ObligationCause::new( hir_ty.span, - wfcx.body_id, + wfcx.body_def_id, traits::FieldSized { adt_kind: match item_adt_kind(&item.kind) { Some(i) => i, @@ -1113,7 +1132,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr { let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), - wfcx.body_id, + wfcx.body_def_id, traits::MiscObligation, ); wfcx.register_obligation(traits::Obligation::new( @@ -1174,7 +1193,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: &ty::AssocI traits::wf::predicate_obligations( wfcx.infcx, wfcx.param_env, - wfcx.body_id, + wfcx.body_def_id, normalized_bound, bound_span, ) @@ -1191,7 +1210,7 @@ fn check_item_fn( decl: &hir::FnDecl<'_>, ) { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { - let sig = tcx.fn_sig(def_id); + let sig = tcx.fn_sig(def_id).subst_identity(); check_fn_or_method(wfcx, ident.span, sig, decl, def_id); }) } @@ -1214,7 +1233,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { wfcx.register_bound( - traits::ObligationCause::new(ty_span, wfcx.body_id, traits::WellFormed(None)), + traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::WellFormed(None)), wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sized, None), @@ -1229,7 +1248,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo if should_check_for_sync { wfcx.register_bound( - traits::ObligationCause::new(ty_span, wfcx.body_id, traits::SharedStatic), + traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::SharedStatic), wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sync, Some(ty_span)), @@ -1269,7 +1288,7 @@ fn check_impl<'tcx>( let mut obligations = traits::wf::trait_obligations( wfcx.infcx, wfcx.param_env, - wfcx.body_id, + wfcx.body_def_id, &trait_pred, ast_trait_ref.path.span, item, @@ -1466,7 +1485,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let pred = wfcx.normalize(sp, None, pred); let cause = traits::ObligationCause::new( sp, - wfcx.body_id, + wfcx.body_def_id, traits::ItemObligation(def_id.to_def_id()), ); traits::Obligation::new(tcx, cause, wfcx.param_env, pred) @@ -1482,12 +1501,11 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id traits::wf::predicate_obligations( infcx, wfcx.param_env.without_const(), - wfcx.body_id, + wfcx.body_def_id, p, sp, ) }); - let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); } @@ -1549,7 +1567,7 @@ fn check_fn_or_method<'tcx>( // Check that the argument is a tuple if let Some(ty) = inputs.next() { wfcx.register_bound( - ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall), + ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, tcx.require_lang_item(hir::LangItem::Tuple, Some(span)), @@ -1597,7 +1615,7 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( traits::wf::predicate_obligations( wfcx.infcx, wfcx.param_env, - wfcx.body_id, + wfcx.body_def_id, normalized_bound, bound_span, ) @@ -1627,7 +1645,7 @@ fn check_method_receiver<'tcx>( let span = fn_sig.decl.inputs[0].span; - let sig = tcx.fn_sig(method.def_id); + let sig = tcx.fn_sig(method.def_id).subst_identity(); let sig = tcx.liberate_late_bound_regions(method.def_id, sig); let sig = wfcx.normalize(span, None, sig); @@ -1697,7 +1715,7 @@ fn receiver_is_valid<'tcx>( let infcx = wfcx.infcx; let tcx = wfcx.tcx(); let cause = - ObligationCause::new(span, wfcx.body_id, traits::ObligationCauseCode::MethodReceiver); + ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver); let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty).is_ok(); @@ -1709,7 +1727,7 @@ fn receiver_is_valid<'tcx>( return true; } - let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty); + let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. if arbitrary_self_types_enabled { @@ -1894,8 +1912,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let mut span = self.span; let empty_env = ty::ParamEnv::empty(); - let def_id = tcx.hir().local_def_id(self.body_id); - let predicates_with_span = tcx.predicates_of(def_id).predicates.iter().copied(); + let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied(); // Check elaborated bounds. let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); @@ -1910,7 +1927,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // Match the existing behavior. if pred.is_global() && !pred.has_late_bound_vars() { let pred = self.normalize(span, None, pred); - let hir_node = tcx.hir().find(self.body_id); + let hir_node = tcx.hir().find_by_def_id(self.body_def_id); // only use the span of the predicate clause (#90869) @@ -1929,7 +1946,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let obligation = traits::Obligation::new( tcx, - traits::ObligationCause::new(span, self.body_id, traits::TrivialBound), + traits::ObligationCause::new(span, self.body_def_id, traits::TrivialBound), empty_env, pred, ); diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index ebb78213a63..5716be4f1a9 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -29,7 +29,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if item.span.is_dummy() { continue; } - let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; + let (path, _) = item.expect_use(); let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 28c04087868..6600e4216bd 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -56,7 +56,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => {} } - let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") }; + let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span }); } @@ -64,8 +64,6 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: impl_did={:?}", impl_did); - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); - let self_type = tcx.type_of(impl_did); debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type); @@ -80,7 +78,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => bug!("expected Copy impl item"), }; - let cause = traits::ObligationCause::misc(span, impl_hir_id); + let cause = traits::ObligationCause::misc(span, impl_did); match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { @@ -224,7 +222,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg); let infcx = tcx.infer_ctxt().build(); - let cause = ObligationCause::misc(span, impl_hir_id); + let cause = ObligationCause::misc(span, impl_did); use rustc_type_ir::sty::TyKind::*; match (source.kind(), target.kind()) { @@ -386,8 +384,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); let infcx = tcx.infer_ctxt().build(); - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); - let cause = ObligationCause::misc(span, impl_hir_id); + let cause = ObligationCause::misc(span, impl_did); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { @@ -575,7 +572,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn }; // Register an obligation for `A: Trait<B>`. - let cause = traits::ObligationCause::misc(span, impl_hir_id); + let cause = traits::ObligationCause::misc(span, impl_did); let predicate = predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); let errors = traits::fully_solve_obligation(&infcx, predicate); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index dfb98240943..c1b0237b2d1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -240,6 +240,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index d3b5778ba3b..bbde59c953a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -169,7 +169,7 @@ fn check_object_overlap<'tcx>( }); for component_def_id in component_def_ids { - if !tcx.is_object_safe(component_def_id) { + if !tcx.check_is_object_safe(component_def_id) { // Without the 'object_safe_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index fe6119dce87..c6b16171311 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,15 +3,13 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = item.expect_impl(); if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_ref = trait_ref.subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c17778ce8bc..cc7235a61c0 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -25,7 +25,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; @@ -517,6 +517,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) { // There's no place to record types from signatures? } + + fn infcx(&self) -> Option<&InferCtxt<'tcx>> { + None + } } /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. @@ -1087,7 +1091,7 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir } #[instrument(level = "debug", skip(tcx))] -fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { +fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; @@ -1096,7 +1100,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let icx = ItemCtxt::new(tcx, def_id.to_def_id()); - match tcx.hir().get(hir_id) { + let output = match tcx.hir().get(hir_id) { TraitItem(hir::TraitItem { kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)), generics, @@ -1169,7 +1173,8 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { x => { bug!("unexpected sort of node in fn_sig(): {:?}", x); } - } + }; + ty::EarlyBinder(output) } fn infer_return_ty_for_fn_sig<'tcx>( @@ -1248,11 +1253,12 @@ fn infer_return_ty_for_fn_sig<'tcx>( } } +// FIXME(vincenzopalazzo): remove the hir item when the refactoring is stable fn suggest_impl_trait<'tcx>( tcx: TyCtxt<'tcx>, ret_ty: Ty<'tcx>, span: Span, - hir_id: hir::HirId, + _hir_id: hir::HirId, def_id: LocalDefId, ) -> Option<String> { let format_as_assoc: fn(_, _, _, _, _) -> _ = @@ -1324,7 +1330,7 @@ fn suggest_impl_trait<'tcx>( } let ocx = ObligationCtxt::new_in_snapshot(&infcx); let item_ty = ocx.normalize( - &ObligationCause::misc(span, hir_id), + &ObligationCause::misc(span, def_id), param_env, tcx.mk_projection(assoc_item_def_id, substs), ); @@ -1342,8 +1348,7 @@ fn suggest_impl_trait<'tcx>( 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()); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); impl_ .of_trait .as_ref() diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs index 359122d4e16..3c67722b637 100644 --- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs +++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs @@ -829,7 +829,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fd: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, _: Span, - _: hir::HirId, + _: LocalDefId, ) { let output = match fd.output { hir::FnRetTy::DefaultReturn(_) => None, @@ -1264,14 +1264,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } else if let Some(body_id) = outermost_body { let fn_id = self.tcx.hir().body_owner(body_id); match self.tcx.hir().get(fn_id) { - Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) + Node::Item(hir::Item { owner_id, kind: hir::ItemKind::Fn(..), .. }) | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(..), .. + owner_id, + kind: hir::TraitItemKind::Fn(..), + .. }) - | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) - | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { - let scope = self.tcx.hir().local_def_id(fn_id); - def = Region::Free(scope.to_def_id(), def.id().unwrap()); + | Node::ImplItem(hir::ImplItem { + owner_id, + kind: hir::ImplItemKind::Fn(..), + .. + }) => { + def = Region::Free(owner_id.to_def_id(), def.id().unwrap()); + } + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => { + def = Region::Free(closure.def_id.to_def_id(), def.id().unwrap()); } _ => {} } @@ -1658,10 +1665,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// "Constrained" basically means that it appears in any type but /// not amongst the inputs to a projection. In other words, `<&'a /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. -fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?; - let generics = tcx.hir().get_generics(def_id)?; +fn is_late_bound_map( + tcx: TyCtxt<'_>, + owner_id: hir::OwnerId, +) -> Option<&FxIndexSet<hir::ItemLocalId>> { + let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?; + let generics = tcx.hir().get_generics(owner_id.def_id)?; let mut late_bound = FxIndexSet::default(); @@ -1695,24 +1704,22 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet< hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, } - let param_def_id = tcx.hir().local_def_id(param.hir_id); - // appears in the where clauses? early-bound. - if appears_in_where_clause.regions.contains(¶m_def_id) { + if appears_in_where_clause.regions.contains(¶m.def_id) { continue; } // does not appear in the inputs, but appears in the return type? early-bound. - if !constrained_by_input.regions.contains(¶m_def_id) - && appears_in_output.regions.contains(¶m_def_id) + if !constrained_by_input.regions.contains(¶m.def_id) + && appears_in_output.regions.contains(¶m.def_id) { continue; } - debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); + debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.def_id); - let inserted = late_bound.insert(param_def_id); - assert!(inserted, "visited lifetime {:?} twice", param.hir_id); + let inserted = late_bound.insert(param.hir_id.local_id); + assert!(inserted, "visited lifetime {:?} twice", param.def_id); } debug!(?late_bound); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 46b277d9803..d0d67ae9257 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -280,7 +280,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue }; - let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id(); + let dup_def = duplicate.def_id.to_def_id(); let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 5e388a2f2ba..e7b0846e103 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -54,15 +54,14 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // ty which is a fully resolved projection. // For the code example above, this would mean converting Self::Assoc<3> // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>) - let item_hir_id = tcx + let item_def_id = tcx .hir() - .parent_iter(hir_id) - .filter(|(_, node)| matches!(node, Node::Item(_))) - .map(|(id, _)| id) - .next() - .unwrap(); - let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id(); - let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; + .parent_owner_iter(hir_id) + .find(|(_, node)| matches!(node, OwnerNode::Item(_))) + .unwrap() + .0 + .to_def_id(); + let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>; let ty = item_ctxt.ast_ty_to_ty(hir_ty); // Iterate through the generics of the projection to find the one that corresponds to @@ -867,7 +866,9 @@ fn infer_placeholder_type<'a>( } match ty.kind() { - ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)), + ty::FnDef(def_id, substs) => { + self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id).subst(self.tcx, substs)) + } // FIXME: non-capturing closures should also suggest a function pointer ty::Closure(..) | ty::Generator(..) => { self.success = false; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 17dbb126bd1..9cf82b39ec9 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -1,11 +1,12 @@ use crate::collect::ItemCtxt; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{ForeignItem, ForeignItemKind, HirId}; +use rustc_hir::{ForeignItem, ForeignItemKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; +use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits; pub fn provide(providers: &mut Providers) { @@ -57,7 +58,7 @@ fn diagnostic_hir_wf_check<'tcx>( cause: Option<ObligationCause<'tcx>>, cause_depth: usize, icx: ItemCtxt<'tcx>, - hir_id: HirId, + def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, depth: usize, } @@ -68,7 +69,7 @@ fn diagnostic_hir_wf_check<'tcx>( let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( ty.span, - self.hir_id, + self.def_id, traits::ObligationCauseCode::WellFormed(None), ); let errors = traits::fully_solve_obligation( @@ -106,7 +107,7 @@ fn diagnostic_hir_wf_check<'tcx>( cause: None, cause_depth: 0, icx, - hir_id, + def_id, param_env: tcx.param_env(def_id.to_def_id()), depth: 0, }; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index bcda26c4cc8..a5dcfab9be8 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -164,7 +164,6 @@ fn get_impl_substs( let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(infcx); let param_env = tcx.param_env(impl1_def_id); - let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id); let assumed_wf_types = ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); @@ -179,7 +178,7 @@ fn get_impl_substs( return None; } - let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types); + let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types); let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); @@ -372,15 +371,9 @@ 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().subst_identity().substs { let infcx = &tcx.infer_ctxt().build(); - let obligations = wf::obligations( - infcx, - tcx.param_env(impl1_def_id), - tcx.hir().local_def_id_to_hir_id(impl1_def_id), - 0, - arg, - span, - ) - .unwrap(); + let obligations = + wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span) + .unwrap(); assert!(!obligations.needs_infer()); impl2_predicates.extend( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 02548ae893f..c2fa46e563e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -100,14 +100,14 @@ mod variance; use rustc_errors::{struct_span_err, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_hir::{Node, CRATE_HIR_ID}; +use rustc_hir::Node; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_middle::middle; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util; use rustc_session::{config::EntryFnType, parse::feature_err}; +use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -182,19 +182,18 @@ fn require_same_types<'tcx>( } fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { - let main_fnsig = tcx.fn_sig(main_def_id); + let main_fnsig = tcx.fn_sig(main_def_id).subst_identity(); let main_span = tcx.def_span(main_def_id); - fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId { + fn main_fn_diagnostics_def_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> LocalDefId { if let Some(local_def_id) = def_id.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); let hir_type = tcx.type_of(local_def_id); if !matches!(hir_type.kind(), ty::FnDef(..)) { span_bug!(sp, "main has a non-function type: found `{}`", hir_type); } - hir_id + local_def_id } else { - CRATE_HIR_ID + CRATE_DEF_ID } } @@ -251,7 +250,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } let mut error = false; - let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span); + let main_diagnostics_def_id = main_fn_diagnostics_def_id(tcx, main_def_id, main_span); let main_fn_generics = tcx.generics_of(main_def_id); let main_fn_predicates = tcx.predicates_of(main_def_id); if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() { @@ -326,7 +325,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let param_env = ty::ParamEnv::empty(); let cause = traits::ObligationCause::new( return_ty_span, - main_diagnostics_hir_id, + main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ); let ocx = traits::ObligationCtxt::new(&infcx); @@ -356,7 +355,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { tcx, &ObligationCause::new( main_span, - main_diagnostics_hir_id, + main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ), se_ty, @@ -444,9 +443,13 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { require_same_types( tcx, - &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType), + &ObligationCause::new( + start_span, + start_def_id, + ObligationCauseCode::StartFunctionType, + ), se_ty, - tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)), + tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()), ); } _ => { diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 5e4d82b6fd5..165782f209a 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -119,7 +119,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::FnDef(..) => { - self.add_constraints_from_sig(current_item, tcx.fn_sig(def_id), self.covariant); + self.add_constraints_from_sig( + current_item, + tcx.fn_sig(def_id).subst_identity(), + self.covariant, + ); } ty::Error(_) => {} @@ -221,8 +225,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Ref(region, ty, mutbl) => { - let contra = self.contravariant(variance); - self.add_constraints_from_region(current, region, contra); + self.add_constraints_from_region(current, region, variance); self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance); } @@ -254,9 +257,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Dynamic(data, r, _) => { - // The type `Foo<T+'a>` is contravariant w/r/t `'a`: - let contra = self.contravariant(variance); - self.add_constraints_from_region(current, r, contra); + // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`: + self.add_constraints_from_region(current, r, variance); if let Some(poly_trait_ref) = data.principal() { self.add_constraints_from_invariant_substs( @@ -291,12 +293,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => { - bug!( - "unexpected type encountered in \ - variance inference: {}", - ty - ); + ty::Placeholder(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Bound(..) + | ty::Infer(..) => { + bug!("unexpected type encountered in variance inference: {}", ty); } } } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index b6f19d3cc68..88fb2653586 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -188,8 +188,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir = self.tcx.hir(); // First, check that we're actually in the tail of a function. - let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. }) = - hir.get(self.body_id) else { return; }; + let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { return; }; + let body = hir.body(body_id); + let hir::ExprKind::Block(block, _) = body.value.kind else { return; }; let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. }) = block.innermost_block().stmts.last() else { return; }; if last_expr.hir_id != expr.hir_id { @@ -198,7 +199,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Next, make sure that we have no type expectation. let Some(ret) = hir - .find_by_def_id(self.body_id.owner.def_id) + .find_by_def_id(self.body_id) .and_then(|owner| owner.fn_decl()) .map(|decl| decl.output.span()) else { return; }; let Expectation::IsLast(stmt) = expectation else { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index b617821fbd6..c220956a201 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, subst) => { - let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, subst); + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst); // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 712f9b87aed..8e21c084841 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Float(_) | ty::Array(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::FnDef(..) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 57feefbcab6..1c70c1b71e7 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -43,7 +43,7 @@ pub(super) fn check_fn<'a, 'tcx>( let ret_ty = fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars( declared_ret_ty, - body.value.hir_id, + fn_def_id, decl.output.span(), fcx.param_env, )); @@ -130,7 +130,12 @@ pub(super) fn check_fn<'a, 'tcx>( let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { let interior = fcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); + fcx.deferred_generator_interiors.borrow_mut().push(( + fn_def_id, + body.id(), + interior, + gen_kind, + )); let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); Some(GeneratorTypes { @@ -167,12 +172,12 @@ pub(super) fn check_fn<'a, 'tcx>( // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` if let Some(panic_impl_did) = tcx.lang_items().panic_impl() - && panic_impl_did == hir.local_def_id(fn_id).to_def_id() + && panic_impl_did == fn_def_id.to_def_id() { 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() { + if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() { check_lang_start_fn(tcx, fn_sig, decl, fn_def_id); } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 12a2abfa76a..329b69eff54 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -4,7 +4,6 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use hir::def::DefKind; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -14,6 +13,7 @@ use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitor}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; @@ -80,7 +80,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?bound_sig, ?liberated_sig); - let mut fcx = FnCtxt::new(self, self.param_env.without_const(), body.value.hir_id); + let mut fcx = FnCtxt::new(self, self.param_env.without_const(), closure.def_id); let generator_types = check_fn( &mut fcx, liberated_sig, @@ -620,8 +620,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // function. Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { debug!("closure is async fn body"); - self.deduce_future_output_from_obligations(expr_def_id, body.id().hir_id) - .unwrap_or_else(|| { + let def_id = self.tcx.hir().body_owner_def_id(body.id()); + self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else( + || { // AFAIK, deducing the future output // always succeeds *except* in error cases // like #65159. I'd like to return Error @@ -630,7 +631,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // *have* reported an // error. --nikomatsakis astconv.ty_infer(None, decl.output.span()) - }) + }, + ) } _ => astconv.ty_infer(None, decl.output.span()), @@ -665,7 +667,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_future_output_from_obligations( &self, expr_def_id: LocalDefId, - body_id: hir::HirId, + body_def_id: LocalDefId, ) -> Option<Ty<'tcx>> { let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") @@ -725,7 +727,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let InferOk { value: output_ty, obligations } = self .replace_opaque_types_with_inference_vars( output_ty, - body_id, + body_def_id, self.tcx.def_span(expr_def_id), self.param_env, ); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index bbf7b81a2cc..ade9c037c51 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1613,12 +1613,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if visitor.ret_exprs.len() > 0 && let Some(expr) = expression { self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); } + let reported = err.emit_unless(unsized_return); self.final_ty = Some(fcx.tcx.ty_error_with_guaranteed(reported)); } } } + fn note_unreachable_loop_return( &self, err: &mut Diagnostic, @@ -1821,7 +1823,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { .trait_ref() .and_then(|t| t.trait_def_id()) .map_or(false, |def_id| { - fcx.tcx.object_safety_violations(def_id).is_empty() + fcx.tcx.check_is_object_safe(def_id) }) }) } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index bd1626dff79..19b8fb96cde 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -59,9 +59,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_clone_for_ref(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) - || self.suggest_floating_point_literal(err, expr, expected); + || self.suggest_floating_point_literal(err, expr, expected) + || self.note_result_coercion(err, expr, expected, expr_ty); if !suggested { - self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected); + self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span); } } @@ -81,7 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr, error); self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error); self.note_type_is_not_clone(err, expected, expr_ty, expr); - self.note_need_for_fn_pointer(err, expected, expr_ty); 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); @@ -222,6 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, found: Ty<'tcx>, expected: Ty<'tcx>, + mismatch_span: Span, ) -> bool { let map = self.tcx.hir(); @@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lt_op: |_| self.tcx.lifetimes.re_erased, ct_op: |c| c, ty_op: |t| match *t.kind() { - ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))), + ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)), ty::Infer(ty::IntVar(_)) => { self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 })) } @@ -281,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; let mut prev = eraser.fold_ty(ty); - let mut prev_span = None; + let mut prev_span: Option<Span> = None; for binding in expr_finder.uses { // In every expression where the binding is referenced, we will look at that @@ -298,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // We special case methods, because they can influence inference through the // call's arguments and we can provide a more explicit span. - let sig = self.tcx.fn_sig(def_id); + let sig = self.tcx.fn_sig(def_id).subst_identity(); let def_self_ty = sig.input(0).skip_binder(); let rcvr_ty = self.node_ty(rcvr.hir_id); // Get the evaluated type *after* calling the method call, so that the influence @@ -333,13 +334,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inferred in this method call. let arg = &args[i]; let arg_ty = self.node_ty(arg.hir_id); - err.span_label( - arg.span, - &format!( - "this is of type `{arg_ty}`, which causes `{ident}` to be \ - inferred as `{ty}`", - ), - ); + if !arg.span.overlaps(mismatch_span) { + err.span_label( + arg.span, + &format!( + "this is of type `{arg_ty}`, which causes `{ident}` to be \ + inferred as `{ty}`", + ), + ); + } param_args.insert(param_ty, (arg, arg_ty)); } } @@ -382,12 +385,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.can_eq(self.param_env, ty, found).is_ok() { // We only point at the first place where the found type was inferred. + if !segment.ident.span.overlaps(mismatch_span) { err.span_label( segment.ident.span, with_forced_trimmed_paths!(format!( "here the type of `{ident}` is inferred to be `{ty}`", )), - ); + );} break; } else if !param_args.is_empty() { break; @@ -406,12 +410,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We use the *previous* span because if the type is known *here* it means // it was *evaluated earlier*. We don't do this for method calls because we // evaluate the method's self type eagerly, but not in any other case. - err.span_label( - span, - with_forced_trimmed_paths!(format!( - "here the type of `{ident}` is inferred to be `{ty}`", - )), - ); + if !span.overlaps(mismatch_span) { + err.span_label( + span, + with_forced_trimmed_paths!(format!( + "here the type of `{ident}` is inferred to be `{ty}`", + )), + ); + } break; } prev = ty; @@ -597,6 +603,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| { self.var_for_def(deref.span, param) }); + let mutability = + match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() { + ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", + ty::Ref(_, _, _) => "&", + _ => "", + }; vec![ ( deref.span.until(base.span), @@ -605,11 +617,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { with_no_trimmed_paths!( self.tcx.def_path_str_with_substs(m.def_id, substs,) ), - match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() { - ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", - ty::Ref(_, _, _) => "&", - _ => "", - }, + mutability, ), ), match &args[..] { @@ -697,6 +705,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + pub(crate) fn note_result_coercion( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + let ty::Adt(e, substs_e) = expected.kind() else { return false; }; + let ty::Adt(f, substs_f) = found.kind() else { return false; }; + if e.did() != f.did() { + return false; + } + if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) { + return false; + } + let map = self.tcx.hir(); + if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id) + && let hir::ExprKind::Ret(_) = expr.kind + { + // `return foo;` + } else if map.get_return_block(expr.hir_id).is_some() { + // Function's tail expression. + } else { + return false; + } + let e = substs_e.type_at(1); + let f = substs_f.type_at(1); + if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::Into).unwrap(), + [f, e], + self.param_env, + ) + .must_apply_modulo_regions() + { + err.multipart_suggestion( + "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \ + in `Ok` so the expression remains of type `Result`", + vec![ + (expr.span.shrink_to_lo(), "Ok(".to_string()), + (expr.span.shrink_to_hi(), "?)".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return true; + } + false + } + /// If the expected type is an enum (Issue #55250) with any variants whose /// sole field is of the found type, suggest such variants. (Issue #42764) fn suggest_compatible_variants( @@ -980,7 +1038,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match method.kind { ty::AssocKind::Fn => { method.fn_has_self_parameter - && self.tcx.fn_sig(method.def_id).inputs().skip_binder().len() == 1 + && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() + == 1 } _ => false, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index bc7474cdfcf..74913bac724 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -542,7 +542,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::FnDef(did, ..) = *ty.kind() { let fn_sig = ty.fn_sig(tcx); - if tcx.fn_sig(did).abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { + if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic + && tcx.item_name(did) == sym::transmute + { let from = fn_sig.inputs().skip_binder()[0]; let to = fn_sig.output().skip_binder(); // We defer the transmute to the end of typeck, once all inference vars have @@ -852,7 +854,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Point any obligations that were registered due to opaque type // inference at the return expression. self.select_obligations_where_possible(|errors| { - self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty); + self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty, return_expr.span); }); } } @@ -862,9 +864,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { errors: &mut Vec<traits::FulfillmentError<'tcx>>, span: Span, return_expr_ty: Ty<'tcx>, + return_span: Span, ) { // Don't point at the whole block if it's empty - if span == self.tcx.hir().span(self.body_id) { + if span == return_span { return; } for err in errors { @@ -1374,7 +1377,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let body = self.tcx.hir().body(anon_const.body); // Create a new function context. - let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id); + let def_id = anon_const.def_id; + let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id); crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(&body.value, expected); @@ -2151,13 +2155,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, access_span: Span, ) -> Vec<Symbol> { + let body_owner_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); variant .fields .iter() .filter(|field| { let def_scope = self .tcx - .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id) + .adjust_ident_and_get_scope( + field.ident(self.tcx), + variant.def_id, + body_owner_hir_id, + ) .1; field.vis.is_accessible_from(def_scope, self.tcx) && !matches!( @@ -2199,8 +2208,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match deref_base_ty.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", deref_base_ty); + let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = - self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id); + self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); let fields = &base_def.non_enum_variant().fields; if let Some(index) = fields .iter() @@ -2538,7 +2548,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn point_at_param_definition(&self, err: &mut Diagnostic, param: ty::ParamTy) { - let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); + let generics = self.tcx.generics_of(self.body_id); let generic_param = generics.type_param(¶m, self.tcx); if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind { return; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 6ed8adb4742..a355a54d695 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -517,16 +517,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) { + if self.tcx.sess.opts.unstable_opts.drop_tracking_mir { + self.save_generator_interior_predicates(def_id); + return; + } + + self.select_obligations_where_possible(|_| {}); + let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (body_id, interior, kind) in generators.drain(..) { - self.select_obligations_where_possible(|_| {}); + for (_, body_id, interior, kind) in generators.drain(..) { crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); + self.select_obligations_where_possible(|_| {}); + } + } + + /// Unify the inference variables corresponding to generator witnesses, and save all the + /// predicates that were stalled on those inference variables. + /// + /// This process allows to conservatively save all predicates that do depend on the generator + /// interior types, for later processing by `check_generator_obligations`. + /// + /// We must not attempt to select obligations after this method has run, or risk query cycle + /// ICE. + #[instrument(level = "debug", skip(self))] + fn save_generator_interior_predicates(&self, def_id: DefId) { + // Try selecting all obligations that are not blocked on inference variables. + // Once we start unifying generator witnesses, trying to select obligations on them will + // trigger query cycle ICEs, as doing so requires MIR. + self.select_obligations_where_possible(|_| {}); + + let generators = std::mem::take(&mut *self.deferred_generator_interiors.borrow_mut()); + debug!(?generators); + + for &(expr_def_id, body_id, interior, _) in generators.iter() { + debug!(?expr_def_id); + + // Create the `GeneratorWitness` type that we will unify with `interior`. + let substs = ty::InternalSubsts::identity_for_item( + self.tcx, + self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), + ); + let witness = self.tcx.mk_generator_witness_mir(expr_def_id.to_def_id(), substs); + + // Unify `interior` with `witness` and collect all the resulting obligations. + let span = self.tcx.hir().body(body_id).value.span; + let ok = self + .at(&self.misc(span), self.param_env) + .eq(interior, witness) + .expect("Failed to unify generator interior type"); + let mut obligations = ok.obligations; + + // Also collect the obligations that were unstalled by this unification. + obligations + .extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx)); + + let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect(); + debug!(?obligations); + self.typeck_results + .borrow_mut() + .generator_interior_predicates + .insert(expr_def_id, obligations); } } #[instrument(skip(self), level = "debug")] - pub(in super::super) fn select_all_obligations_or_error(&self) { - let mut errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self); + pub(in super::super) fn report_ambiguity_errors(&self) { + let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(); if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); @@ -926,43 +982,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(in super::super) fn note_need_for_fn_pointer( - &self, - err: &mut Diagnostic, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - let (sig, did, substs) = match (&expected.kind(), &found.kind()) { - (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2); - if sig1 != sig2 { - return; - } - err.note( - "different `fn` items always have unique types, even if their signatures are \ - the same", - ); - (sig1, *did1, substs1) - } - (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.bound_fn_sig(*did).subst(self.tcx, substs); - if sig1 != *sig2 { - return; - } - (sig1, *did, substs) - } - _ => return, - }; - err.help(&format!("change the expected type to be function pointer `{}`", sig)); - err.help(&format!( - "if the expected type is due to type inference, cast the expected `fn` to a function \ - pointer: `{} as {}`", - self.tcx.def_path_str_with_substs(did, substs), - sig - )); - } - // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. #[instrument(skip(self, span), level = "debug")] diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c9609e69439..47ef106e750 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) - .check_asm(asm, self.tcx.hir().local_def_id_to_hir_id(enclosing_id)); + .check_asm(asm, enclosing_id); } } @@ -808,7 +808,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::MiscVariable, span: full_call_span, }); - self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty); + self.point_at_expr_source_of_inferred_type( + &mut err, + rcvr, + expected, + callee_ty, + provided_arg_span, + ); } // Call out where the function is defined self.label_fn_like( @@ -2126,7 +2132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *callee_ty.kind() { ty::Param(param) => { let param = - self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx); + self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx); if param.kind.is_synthetic() { // if it's `impl Fn() -> ..` then just fall down to the def-id based logic def_id = param.def_id; @@ -2135,7 +2141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // and point at that. let instantiated = self .tcx - .explicit_predicates_of(self.body_id.owner) + .explicit_predicates_of(self.body_id) .instantiate_identity(self.tcx); // FIXME(compiler-errors): This could be problematic if something has two // fn-like predicates with different args, but callable types really never diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 428fde642bc..4940015ddd5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -10,7 +10,7 @@ pub use suggestions::*; use crate::coercion::DynamicCoerceMany; use crate::{Diverges, EnclosingBreakables, Inherited}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer; use rustc_infer::infer::error_reporting::TypeErrCtxt; @@ -38,7 +38,7 @@ use std::ops::Deref; /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt /// [`InferCtxt`]: infer::InferCtxt pub struct FnCtxt<'a, 'tcx> { - pub(super) body_id: hir::HirId, + pub(super) body_id: LocalDefId, /// The parameter environment used for proving trait obligations /// in this function. This can change when we descend into @@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn new( inh: &'a Inherited<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, ) -> FnCtxt<'a, 'tcx> { FnCtxt { body_id, @@ -204,7 +204,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn item_def_id(&self) -> DefId { - self.body_id.owner.to_def_id() + self.body_id.to_def_id() } fn get_type_parameter_bounds( @@ -324,6 +324,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; self.write_ty(hir_id, ty) } + + fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { + Some(&self.infcx) + } } /// Represents a user-provided type in the raw form (never normalized). diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 4d673ac9147..6046e55c65c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -31,7 +31,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results .borrow() .liberated_fn_sigs() - .get(self.tcx.hir().parent_id(self.body_id)) + .get(self.tcx.hir().local_def_id_to_hir_id(self.body_id)) .copied() } @@ -164,7 +164,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { - self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty) + let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty) } pub fn suggest_two_fn_call( diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 15dd3412c34..38445f28440 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -5,6 +5,7 @@ use rustc_hir::PatKind; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::Ty; use rustc_middle::ty::UserType; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; @@ -156,7 +157,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { _: &'tcx hir::FnDecl<'tcx>, _: hir::BodyId, _: Span, - _: hir::HirId, + _: LocalDefId, ) { } } diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index ba34f299453..87e54025330 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -56,7 +56,7 @@ pub struct Inherited<'tcx> { pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>, pub(super) deferred_generator_interiors: - RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, + RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, pub(super) body_id: Option<hir::BodyId>, diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 3c873024c92..2c76582f2ec 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -38,6 +38,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { let tcx = self.tcx; + let dl = &tcx.data_layout; let span = tcx.hir().span(hir_id); let normalize = |ty| { let ty = self.resolve_vars_if_possible(ty); @@ -69,7 +70,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Special-case transmuting from `typeof(function)` and // `Option<typeof(function)>` to present a clearer error. let from = unpack_option_like(tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) { + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) { struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type") .note(&format!("source type: {from}")) .note(&format!("target type: {to}")) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 7ddf9eaa4d8..323bacf70ab 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -201,13 +201,13 @@ fn typeck_with_fallback<'tcx>( let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { let param_env = tcx.param_env(def_id); - let mut fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + let mut fcx = FnCtxt::new(&inh, param_env, def_id); if let Some(hir::FnSig { header, decl, .. }) = fn_sig { let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() { fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None) } else { - tcx.fn_sig(def_id) + tcx.fn_sig(def_id).subst_identity() }; check_abi(tcx, id, span, fn_sig.abi()); @@ -294,14 +294,24 @@ fn typeck_with_fallback<'tcx>( // Before the generator analysis, temporary scopes shall be marked to provide more // precise information on types to be captured. fcx.resolve_rvalue_scopes(def_id.to_def_id()); - fcx.resolve_generator_interiors(def_id.to_def_id()); for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { let ty = fcx.normalize(span, ty); fcx.require_type_is_sized(ty, span, code); } - fcx.select_all_obligations_or_error(); + fcx.select_obligations_where_possible(|_| {}); + + debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); + + // This must be the last thing before `report_ambiguity_errors`. + fcx.resolve_generator_interiors(def_id.to_def_id()); + + debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); + + if let None = fcx.infcx.tainted_by_errors() { + fcx.report_ambiguity_errors(); + } if let None = fcx.infcx.tainted_by_errors() { fcx.check_transmutes(); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 372ea30ebd0..65ca47bfe53 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -503,9 +503,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { debug!("method_predicates after subst = {:?}", method_predicates); - let sig = self.tcx.bound_fn_sig(def_id); - - let sig = sig.subst(self.tcx, all_substs); + let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs); debug!("type scheme substituted, sig={:?}", sig); let sig = self.replace_bound_vars_with_fresh_vars(sig); diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 47396204b14..60d4dc326ee 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .map(|pick| { let sig = self.tcx.fn_sig(pick.item.def_id); - sig.inputs().skip_binder().len().saturating_sub(1) + sig.skip_binder().inputs().skip_binder().len().saturating_sub(1) }) .unwrap_or(0); @@ -399,8 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // N.B., instantiate late-bound regions before normalizing the // function signature so that normalization does not need to deal // with bound regions. - let fn_sig = tcx.bound_fn_sig(def_id); - let fn_sig = fn_sig.subst(self.tcx, substs); + let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs); let fn_sig = self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9c06a22315b..9fc4c16fb07 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -508,9 +508,10 @@ fn method_autoderef_steps<'tcx>( let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); let ParamEnvAnd { param_env, value: self_ty } = goal; - let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .silence_errors(); + let mut autoderef = + Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty) + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef .by_ref() @@ -610,10 +611,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) { let is_accessible = if let Some(name) = self.method_name { let item = candidate.item; - let def_scope = self - .tcx - .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id) - .1; + let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let def_scope = + self.tcx.adjust_ident_and_get_scope(name, item.container_id(self.tcx), hir_id).1; item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx) } else { true @@ -921,26 +921,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { expected: Ty<'tcx>, ) -> bool { match method.kind { - ty::AssocKind::Fn => { - let fty = self.tcx.bound_fn_sig(method.def_id); - self.probe(|_| { - let substs = self.fresh_substs_for_item(self.span, method.def_id); - let fty = fty.subst(self.tcx, substs); - let fty = - self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty); - - if let Some(self_ty) = self_ty { - if self - .at(&ObligationCause::dummy(), self.param_env) - .sup(fty.inputs()[0], self_ty) - .is_err() - { - return false; - } + ty::AssocKind::Fn => self.probe(|_| { + let substs = self.fresh_substs_for_item(self.span, method.def_id); + let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs); + let fty = self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty); + + if let Some(self_ty) = self_ty { + if self + .at(&ObligationCause::dummy(), self.param_env) + .sup(fty.inputs()[0], self_ty) + .is_err() + { + return false; } - self.can_sub(self.param_env, fty.output(), expected).is_ok() - }) - } + } + self.can_sub(self.param_env, fty.output(), expected).is_ok() + }), _ => false, } } @@ -1887,7 +1883,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> { - let fn_sig = self.tcx.bound_fn_sig(method); + let fn_sig = self.tcx.fn_sig(method); debug!(?fn_sig); assert!(!substs.has_escaping_bound_vars()); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8c54e9bdb5f..31d55a41d8a 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -352,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty_span = match rcvr_ty.kind() { ty::Param(param_type) => { - Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id())) + Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id())) } ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())), _ => None, @@ -403,7 +403,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, sugg_span, ); - self.note_candidates_on_method_error( rcvr_ty, item_name, @@ -496,9 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(_) => { // Account for `fn` items like in `issue-35677.rs` to // suggest restricting its type params. - let parent_body = - hir.body_owner(hir::BodyId { hir_id: self.body_id }); - Some(hir.get(parent_body)) + Some(hir.get_by_def_id(self.body_id)) } ty::Adt(def, _) => { def.did().as_local().map(|def_id| hir.get_by_def_id(def_id)) @@ -1131,6 +1128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::AssocKind::Fn => self .tcx .fn_sig(item.def_id) + .subst_identity() .inputs() .skip_binder() .get(0) @@ -1267,7 +1265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(assoc) = self.associated_value(*impl_did, item_name) && assoc.kind == ty::AssocKind::Fn { - let sig = self.tcx.fn_sig(assoc.def_id); + let sig = self.tcx.fn_sig(assoc.def_id).subst_identity(); sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() { None } else { @@ -1343,7 +1341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }); if let Some((field, field_ty)) = field_receiver { - let scope = tcx.parent_module(self.body_id); + let scope = tcx.parent_module_from_def_id(self.body_id); let is_accessible = field.vis.is_accessible_from(scope, tcx); if is_accessible { @@ -1593,7 +1591,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else { return }; let map = self.infcx.tcx.hir(); - let body = map.body(rustc_hir::BodyId { hir_id: self.body_id }); + let body_id = self.tcx.hir().body_owned_by(self.body_id); + let body = map.body(body_id); struct LetVisitor<'a> { result: Option<&'a hir::Expr<'a>>, ident_name: Symbol, @@ -2100,7 +2099,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // just changing the path. && pick.item.fn_has_self_parameter && let Some(self_ty) = - self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0) + self.tcx.fn_sig(pick.item.def_id).subst_identity().inputs().skip_binder().get(0) && self_ty.is_ref() { let suggested_path = match deref_ty.kind() { @@ -2195,7 +2194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true }); - let module_did = self.tcx.parent_module(self.body_id); + let module_did = self.tcx.parent_module_from_def_id(self.body_id); let (module, _, _) = self.tcx.hir().get_module(module_did); let span = module.spans.inject_use_span; @@ -2353,7 +2352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // implement the `AsRef` trait. let skip = skippable.contains(&did) || (("Pin::new" == *pre) && (sym::as_ref == item_name.name)) - || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().inputs().len() != inputs_len); + || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len); // Make sure the method is defined for the *actual* receiver: we don't // want to treat `Box<Self>` as a receiver if it only works because of // an autoderef to `&self` @@ -2517,7 +2516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Obtain the span for `param` and use it for a structured suggestion. if let Some(param) = param_type { - let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); + let generics = self.tcx.generics_of(self.body_id.to_def_id()); let type_param = generics.type_param(param, self.tcx); let hir = self.tcx.hir(); if let Some(def_id) = type_param.def_id.as_local() { @@ -2733,7 +2732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // check the method arguments number if let Ok(pick) = probe && let fn_sig = self.tcx.fn_sig(pick.item.def_id) && - let fn_args = fn_sig.skip_binder().inputs() && + let fn_args = fn_sig.skip_binder().skip_binder().inputs() && fn_args.len() == args.len() + 1 { err.span_suggestion_verbose( method_name.span.shrink_to_hi(), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 250f4cd3f65..0aa34f9dd70 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -40,8 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, body: &'tcx hir::Body<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { - let item_id = self.tcx.hir().body_owner(body.id()); - let item_def_id = self.tcx.hir().local_def_id(item_id); + let item_def_id = self.tcx.hir().body_owner_def_id(body.id()); // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. @@ -55,7 +54,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_def_id) { hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { - wbcx.visit_node_id(body.value.span, item_id); + let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id); + wbcx.visit_node_id(body.value.span, item_hir_id); } hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), } @@ -545,6 +545,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); self.typeck_results.generator_interior_types = fcx_typeck_results.generator_interior_types.clone(); + for (&expr_def_id, predicates) in fcx_typeck_results.generator_interior_predicates.iter() { + let predicates = self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id)); + self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates); + } } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 33a9a0cabb9..6703d53f380 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -38,7 +38,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING}; use rustc_graphviz as dot; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, @@ -74,7 +74,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let (if_this_changed, then_this_would_need) = { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; - visitor.process_attrs(hir::CRATE_HIR_ID); + visitor.process_attrs(CRATE_DEF_ID); tcx.hir().visit_all_item_likes_in_crate(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -119,9 +119,9 @@ impl<'tcx> IfThisChanged<'tcx> { value } - fn process_attrs(&mut self, hir_id: hir::HirId) { - let def_id = self.tcx.hir().local_def_id(hir_id); + fn process_attrs(&mut self, def_id: LocalDefId) { let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id()); + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { if attr.has_name(sym::rustc_if_this_changed) { @@ -180,22 +180,22 @@ impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - self.process_attrs(item.hir_id()); + self.process_attrs(item.owner_id.def_id); intravisit::walk_item(self, item); } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - self.process_attrs(trait_item.hir_id()); + self.process_attrs(trait_item.owner_id.def_id); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - self.process_attrs(impl_item.hir_id()); + self.process_attrs(impl_item.owner_id.def_id); intravisit::walk_impl_item(self, impl_item); } fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { - self.process_attrs(s.hir_id); + self.process_attrs(s.def_id); intravisit::walk_field_def(self, s); } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 091635e6c73..87c6dfad5fa 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -435,6 +435,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index e59715b706b..f7e3e4a1cc0 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -26,7 +26,7 @@ use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVari use rustc_index::vec::IndexVec; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BoundVar, List}; +use rustc_middle::ty::{self, List}; use rustc_span::source_map::Span; pub use rustc_middle::infer::canonical::*; @@ -87,12 +87,13 @@ impl<'tcx> InferCtxt<'tcx> { variables: &List<CanonicalVarInfo<'tcx>>, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> CanonicalVarValues<'tcx> { - let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables - .iter() - .map(|info| self.instantiate_canonical_var(span, info, &universe_map)) - .collect(); - - CanonicalVarValues { var_values } + CanonicalVarValues { + var_values: self.tcx.mk_substs( + variables + .iter() + .map(|info| self.instantiate_canonical_var(span, info, &universe_map)), + ), + } } /// Given the "info" about a canonical variable, creates a fresh diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 3d49182f0b8..3e8e7734a5a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -17,7 +17,7 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::traits::{PredicateObligations, TraitEngine}; +use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; @@ -482,11 +482,8 @@ impl<'tcx> InferCtxt<'tcx> { // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. let result_subst = CanonicalVarValues { - var_values: query_response - .variables - .iter() - .enumerate() - .map(|(index, info)| { + var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map( + |(index, info)| { if info.is_existential() { match opt_values[BoundVar::new(index)] { Some(k) => k, @@ -499,8 +496,8 @@ impl<'tcx> InferCtxt<'tcx> { universe_map[u.as_usize()] }) } - }) - .collect(), + }, + )), }; let mut obligations = vec![]; diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 389afe22eb7..e77f2d37b7d 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -72,16 +72,15 @@ where value } else { let delegate = FnMutDelegate { - regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() { + regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() { GenericArgKind::Lifetime(l) => l, r => bug!("{:?} is a region but value is {:?}", br, r), }, - types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { + types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() { GenericArgKind::Type(ty) => ty, r => bug!("{:?} is a type but value is {:?}", bound_ty, r), }, - consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() - { + consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() { GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 72676b718fa..a567b6acdbe 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -37,7 +37,10 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{ + self, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeVisitable, +}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; @@ -140,8 +143,6 @@ impl<'tcx> InferCtxt<'tcx> { let a = self.shallow_resolve(a); let b = self.shallow_resolve(b); - let a_is_expected = relation.a_is_expected(); - match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)), @@ -158,11 +159,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected); + return self.unify_const_variable(vid, b); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected); + return self.unify_const_variable(vid, a); } (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { // FIXME(#59490): Need to remove the leak check to accommodate @@ -223,10 +224,8 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn unify_const_variable( &self, - param_env: ty::ParamEnv<'tcx>, target_vid: ty::ConstVid<'tcx>, ct: ty::Const<'tcx>, - vid_is_expected: bool, ) -> RelateResult<'tcx, ty::Const<'tcx>> { let (for_universe, span) = { let mut inner = self.inner.borrow_mut(); @@ -239,8 +238,12 @@ impl<'tcx> InferCtxt<'tcx> { ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), } }; - let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid } - .relate(ct, ct)?; + let value = ct.try_fold_with(&mut ConstInferUnifier { + infcx: self, + span, + for_universe, + target_vid, + })?; self.inner.borrow_mut().const_unification_table().union_value( target_vid, @@ -800,8 +803,6 @@ struct ConstInferUnifier<'cx, 'tcx> { span: Span, - param_env: ty::ParamEnv<'tcx>, - for_universe: ty::UniverseIndex, /// The vid of the const variable that is in the process of being @@ -810,61 +811,15 @@ struct ConstInferUnifier<'cx, 'tcx> { target_vid: ty::ConstVid<'tcx>, } -// We use `TypeRelation` here to propagate `RelateResult` upwards. -// -// Both inputs are expected to be the same. -impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn intercrate(&self) -> bool { - assert!(!self.infcx.intercrate); - false - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "ConstInferUnifier" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn mark_ambiguous(&mut self) { - bug!() - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - _variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - // We don't care about variance here. - self.relate(a, b) - } +impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> { + type Error = TypeError<'tcx>; - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.infcx.tcx } #[instrument(level = "debug", skip(self), ret)] - fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug_assert_eq!(t, _t); - + fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> { match t.kind() { &ty::Infer(ty::TyVar(vid)) => { let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); @@ -872,7 +827,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { match probe { TypeVariableValue::Known { value: u } => { debug!("ConstOccursChecker: known value {:?}", u); - self.tys(u, u) + u.try_fold_with(self) } TypeVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { @@ -892,16 +847,15 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), - _ => relate::super_relate_tys(self, t, t), + _ => t.try_super_fold_with(self), } } - fn regions( + #[instrument(level = "debug", skip(self), ret)] + fn try_fold_region( &mut self, r: ty::Region<'tcx>, - _r: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug_assert_eq!(r, _r); + ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> { debug!("ConstInferUnifier: r={:?}", r); match *r { @@ -930,14 +884,8 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } - #[instrument(level = "debug", skip(self))] - fn consts( - &mut self, - c: ty::Const<'tcx>, - _c: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug_assert_eq!(c, _c); - + #[instrument(level = "debug", skip(self), ret)] + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> { match c.kind() { ty::ConstKind::Infer(InferConst::Var(vid)) => { // Check if the current unification would end up @@ -958,7 +906,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { let var_value = self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid); match var_value.val { - ConstVariableValue::Known { value: u } => self.consts(u, u), + ConstVariableValue::Known { value: u } => u.try_fold_with(self), ConstVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { Ok(c) @@ -977,17 +925,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - let substs = self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - substs, - substs, - )?; - - Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) - } - _ => relate::super_relate_consts(self, c, c), + _ => c.try_super_fold_with(self), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 28fd03b878b..b11db8396c9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -79,6 +79,7 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; mod note; +mod note_and_explain; mod suggest; pub(crate) mod need_type_info; @@ -1344,8 +1345,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2); + let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); + let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); let mut values = self.cmp_fn_sig(&sig1, &sig2); let path1 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did1, substs1)); let path2 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did2, substs2)); @@ -1356,7 +1357,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1); + let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); let mut values = self.cmp_fn_sig(&sig1, sig2); values.0.push_highlighted(format!( " {{{}}}", @@ -1366,7 +1367,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (ty::FnPtr(sig1), ty::FnDef(did2, substs2)) => { - let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2); + let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); let mut values = self.cmp_fn_sig(sig1, &sig2); values.1.push_normal(format!( " {{{}}}", @@ -1841,19 +1842,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); + self.suggest_function_pointers(cause, span, &exp_found, diag); } } - // In some (most?) cases cause.body_id points to actual body, but in some cases - // it's an actual definition. According to the comments (e.g. in - // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter - // is relied upon by some other code. This might (or might not) need cleanup. - let body_owner_def_id = - self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| { - self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id }) - }); self.check_and_note_conflicting_crates(diag, terr); - self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id()); + + self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id()); if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() @@ -2585,7 +2580,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. - pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + pub fn same_type_modulo_infer<T: relate::Relate<'tcx>>(&self, a: T, b: T) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index fd26d7d29c5..4c0f457b46a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -65,7 +65,7 @@ pub fn find_param_with_region<'tcx>( let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); - let poly_fn_sig = tcx.fn_sig(id); + let poly_fn_sig = tcx.fn_sig(id).subst_identity(); let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig); let body = hir.body(body_id); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs new file mode 100644 index 00000000000..34e8edd6140 --- /dev/null +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -0,0 +1,654 @@ +use super::TypeErrCtxt; +use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; +use rustc_errors::{pluralize, Diagnostic, MultiSpan}; +use rustc_hir::{self as hir, def::DefKind}; +use rustc_middle::traits::ObligationCauseCode; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::print::Printer; +use rustc_middle::{ + traits::ObligationCause, + ty::{self, error::TypeError, print::FmtPrinter, suggest_constraining_type_param, Ty}, +}; +use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol}; + +impl<'tcx> TypeErrCtxt<'_, 'tcx> { + pub fn note_and_explain_type_err( + &self, + diag: &mut Diagnostic, + err: TypeError<'tcx>, + cause: &ObligationCause<'tcx>, + sp: Span, + body_owner_def_id: DefId, + ) { + use ty::error::TypeError::*; + debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); + + let tcx = self.tcx; + + match err { + ArgumentSorts(values, _) | Sorts(values) => { + match (values.expected.kind(), values.found.kind()) { + (ty::Closure(..), ty::Closure(..)) => { + diag.note("no two closures, even if identical, have the same type"); + diag.help("consider boxing your closure and/or using it as a trait object"); + } + (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => { + // Issue #63167 + diag.note("distinct uses of `impl Trait` result in different opaque types"); + } + (ty::Float(_), ty::Infer(ty::IntVar(_))) + if let Ok( + // Issue #53280 + snippet, + ) = tcx.sess.source_map().span_to_snippet(sp) => + { + if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { + diag.span_suggestion( + sp, + "use a float literal", + format!("{}.0", snippet), + MachineApplicable, + ); + } + } + (ty::Param(expected), ty::Param(found)) => { + let generics = tcx.generics_of(body_owner_def_id); + let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id); + if !sp.contains(e_span) { + diag.span_label(e_span, "expected type parameter"); + } + let f_span = tcx.def_span(generics.type_param(found, tcx).def_id); + if !sp.contains(f_span) { + diag.span_label(f_span, "found type parameter"); + } + diag.note( + "a type parameter was expected, but a different one was found; \ + you might be missing a type parameter or trait bound", + ); + diag.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch10-02-traits.html\ + #traits-as-parameters", + ); + } + (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => { + diag.note("an associated type was expected, but a different one was found"); + } + (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) + if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder => + { + let generics = tcx.generics_of(body_owner_def_id); + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "this type parameter"); + } + let hir = tcx.hir(); + let mut note = true; + if let Some(generics) = generics + .type_param(p, tcx) + .def_id + .as_local() + .map(|id| hir.local_def_id_to_hir_id(id)) + .and_then(|id| tcx.hir().find_parent(id)) + .as_ref() + .and_then(|node| node.generics()) + { + // Synthesize the associated type restriction `Add<Output = Expected>`. + // FIXME: extract this logic for use in other diagnostics. + let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx); + let path = + tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); + let item_name = tcx.item_name(proj.def_id); + let item_args = self.format_generic_args(assoc_substs); + + let path = if path.ends_with('>') { + format!( + "{}, {}{} = {}>", + &path[..path.len() - 1], + item_name, + item_args, + p + ) + } else { + format!("{}<{}{} = {}>", path, item_name, item_args, p) + }; + note = !suggest_constraining_type_param( + tcx, + generics, + diag, + &format!("{}", proj.self_ty()), + &path, + None, + ); + } + if note { + diag.note("you might be missing a type parameter or trait bound"); + } + } + (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..)) + | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => { + let generics = tcx.generics_of(body_owner_def_id); + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "this type parameter"); + } + diag.help("type parameters must be constrained to match other types"); + if tcx.sess.teach(&diag.get_code().unwrap()) { + diag.help( + "given a type parameter `T` and a method `foo`: +``` +trait Trait<T> { fn foo(&tcx) -> T; } +``` +the only ways to implement method `foo` are: +- constrain `T` with an explicit type: +``` +impl Trait<String> for X { + fn foo(&tcx) -> String { String::new() } +} +``` +- add a trait bound to `T` and call a method on that trait that returns `Self`: +``` +impl<T: std::default::Default> Trait<T> for X { + fn foo(&tcx) -> T { <T as std::default::Default>::default() } +} +``` +- change `foo` to return an argument of type `T`: +``` +impl<T> Trait<T> for X { + fn foo(&tcx, x: T) -> T { x } +} +```", + ); + } + diag.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch10-02-traits.html\ + #traits-as-parameters", + ); + } + (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => { + let generics = tcx.generics_of(body_owner_def_id); + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "this type parameter"); + } + diag.help(&format!( + "every closure has a distinct type and so could not always match the \ + caller-chosen type of parameter `{}`", + p + )); + } + (ty::Param(p), _) | (_, ty::Param(p)) => { + let generics = tcx.generics_of(body_owner_def_id); + let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "this type parameter"); + } + } + (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { + self.expected_projection( + diag, + proj_ty, + values, + body_owner_def_id, + cause.code(), + ); + } + (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { + let msg = format!( + "consider constraining the associated type `{}` to `{}`", + values.found, values.expected, + ); + if !(self.suggest_constraining_opaque_associated_type( + diag, + &msg, + proj_ty, + values.expected, + ) || self.suggest_constraint( + diag, + &msg, + body_owner_def_id, + proj_ty, + values.expected, + )) { + diag.help(&msg); + diag.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", + ); + } + } + _ => {} + } + debug!( + "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", + values.expected, + values.expected.kind(), + values.found, + values.found.kind(), + ); + } + CyclicTy(ty) => { + // Watch out for various cases of cyclic types and try to explain. + if ty.is_closure() || ty.is_generator() { + diag.note( + "closures cannot capture themselves or take themselves as argument;\n\ + this error may be the result of a recent compiler bug-fix,\n\ + see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\ + for more information", + ); + } + } + TargetFeatureCast(def_id) => { + let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); + diag.note( + "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" + ); + diag.span_labels(target_spans, "`#[target_feature]` added here"); + } + _ => {} + } + } + + fn suggest_constraint( + &self, + diag: &mut Diagnostic, + msg: &str, + body_owner_def_id: DefId, + proj_ty: &ty::AliasTy<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let tcx = self.tcx; + let assoc = tcx.associated_item(proj_ty.def_id); + let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx); + if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) { + if let Some(hir_generics) = item.generics() { + // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. + // This will also work for `impl Trait`. + let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { + let generics = tcx.generics_of(body_owner_def_id); + generics.type_param(param_ty, tcx).def_id + } else { + return false; + }; + let Some(def_id) = def_id.as_local() else { + return false; + }; + + // First look in the `where` clause, as this might be + // `fn foo<T>(x: T) where T: Trait`. + for pred in hir_generics.bounds_for_param(def_id) { + if self.constrain_generic_bound_associated_type_structured_suggestion( + diag, + &trait_ref, + pred.bounds, + &assoc, + assoc_substs, + ty, + msg, + false, + ) { + return true; + } + } + } + } + false + } + + /// An associated type was expected and a different type was found. + /// + /// We perform a few different checks to see what we can suggest: + /// + /// - In the current item, look for associated functions that return the expected type and + /// suggest calling them. (Not a structured suggestion.) + /// - If any of the item's generic bounds can be constrained, we suggest constraining the + /// associated type to the found type. + /// - If the associated type has a default type and was expected inside of a `trait`, we + /// mention that this is disallowed. + /// - If all other things fail, and the error is not because of a mismatch between the `trait` + /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc + /// fn that returns the type. + fn expected_projection( + &self, + diag: &mut Diagnostic, + proj_ty: &ty::AliasTy<'tcx>, + values: ExpectedFound<Ty<'tcx>>, + body_owner_def_id: DefId, + cause_code: &ObligationCauseCode<'_>, + ) { + let tcx = self.tcx; + + let msg = format!( + "consider constraining the associated type `{}` to `{}`", + values.expected, values.found + ); + let body_owner = tcx.hir().get_if_local(body_owner_def_id); + let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); + + // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. + let callable_scope = matches!( + body_owner, + Some( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) + | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), + ) + ); + let impl_comparison = + matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); + let assoc = tcx.associated_item(proj_ty.def_id); + if !callable_scope || impl_comparison { + // We do not want to suggest calling functions when the reason of the + // type error is a comparison of an `impl` with its `trait` or when the + // scope is outside of a `Body`. + } else { + // If we find a suitable associated function that returns the expected type, we don't + // want the more general suggestion later in this method about "consider constraining + // the associated type or calling a method that returns the associated type". + let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( + diag, + assoc.container_id(tcx), + current_method_ident, + proj_ty.def_id, + values.expected, + ); + // Possibly suggest constraining the associated type to conform to the + // found type. + if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found) + || point_at_assoc_fn + { + return; + } + } + + self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found); + + if self.point_at_associated_type(diag, body_owner_def_id, values.found) { + return; + } + + if !impl_comparison { + // Generic suggestion when we can't be more specific. + if callable_scope { + diag.help(&format!( + "{} or calling a method that returns `{}`", + msg, values.expected + )); + } else { + diag.help(&msg); + } + diag.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", + ); + } + if tcx.sess.teach(&diag.get_code().unwrap()) { + diag.help( + "given an associated type `T` and a method `foo`: +``` +trait Trait { +type T; +fn foo(&tcx) -> Self::T; +} +``` +the only way of implementing method `foo` is to constrain `T` with an explicit associated type: +``` +impl Trait for X { +type T = String; +fn foo(&tcx) -> Self::T { String::new() } +} +```", + ); + } + } + + /// When the expected `impl Trait` is not defined in the current item, it will come from + /// a return type. This can occur when dealing with `TryStream` (#71035). + fn suggest_constraining_opaque_associated_type( + &self, + diag: &mut Diagnostic, + msg: &str, + proj_ty: &ty::AliasTy<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let tcx = self.tcx; + + let assoc = tcx.associated_item(proj_ty.def_id); + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { + let opaque_local_def_id = def_id.as_local(); + let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { + match &tcx.hir().expect_item(opaque_local_def_id).kind { + hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, + _ => bug!("The HirId comes from a `ty::Opaque`"), + } + } else { + return false; + }; + + let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx); + + self.constrain_generic_bound_associated_type_structured_suggestion( + diag, + &trait_ref, + opaque_hir_ty.bounds, + assoc, + assoc_substs, + ty, + msg, + true, + ) + } else { + false + } + } + + fn point_at_methods_that_satisfy_associated_type( + &self, + diag: &mut Diagnostic, + assoc_container_id: DefId, + current_method_ident: Option<Symbol>, + proj_ty_item_def_id: DefId, + expected: Ty<'tcx>, + ) -> bool { + let tcx = self.tcx; + + let items = tcx.associated_items(assoc_container_id); + // Find all the methods in the trait that could be called to construct the + // expected associated type. + // FIXME: consider suggesting the use of associated `const`s. + let methods: Vec<(Span, String)> = items + .in_definition_order() + .filter(|item| { + ty::AssocKind::Fn == item.kind && Some(item.name) != current_method_ident + }) + .filter_map(|item| { + let method = tcx.fn_sig(item.def_id).subst_identity(); + match *method.output().skip_binder().kind() { + ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. }) + if item_def_id == proj_ty_item_def_id => + { + Some(( + tcx.def_span(item.def_id), + format!("consider calling `{}`", tcx.def_path_str(item.def_id)), + )) + } + _ => None, + } + }) + .collect(); + if !methods.is_empty() { + // Use a single `help:` to show all the methods in the trait that can + // be used to construct the expected associated type. + let mut span: MultiSpan = + methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into(); + let msg = format!( + "{some} method{s} {are} available that return{r} `{ty}`", + some = if methods.len() == 1 { "a" } else { "some" }, + s = pluralize!(methods.len()), + are = pluralize!("is", methods.len()), + r = if methods.len() == 1 { "s" } else { "" }, + ty = expected + ); + for (sp, label) in methods.into_iter() { + span.push_span_label(sp, label); + } + diag.span_help(span, &msg); + return true; + } + false + } + + fn point_at_associated_type( + &self, + diag: &mut Diagnostic, + body_owner_def_id: DefId, + found: Ty<'tcx>, + ) -> bool { + let tcx = self.tcx; + + let Some(hir_id) = body_owner_def_id.as_local() else { + return false; + }; + let hir_id = tcx.hir().local_def_id_to_hir_id(hir_id); + // When `body_owner` is an `impl` or `trait` item, look in its associated types for + // `expected` and point at it. + let parent_id = tcx.hir().get_parent_item(hir_id); + let item = tcx.hir().find_by_def_id(parent_id.def_id); + + debug!("expected_projection parent item {:?}", item); + + let param_env = tcx.param_env(body_owner_def_id); + + match item { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => { + // FIXME: account for `#![feature(specialization)]` + for item in &items[..] { + match item.kind { + hir::AssocItemKind::Type => { + // FIXME: account for returning some type in a trait fn impl that has + // an assoc type as a return type (#72076). + if let hir::Defaultness::Default { has_value: true } = + tcx.impl_defaultness(item.id.owner_id) + { + let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity(); + if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() { + diag.span_label( + item.span, + "associated type defaults can't be assumed inside the \ + trait defining them", + ); + return true; + } + } + } + _ => {} + } + } + } + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { items, .. }), + .. + })) => { + for item in &items[..] { + if let hir::AssocItemKind::Type = item.kind { + let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity(); + + if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() { + diag.span_label(item.span, "expected this associated type"); + return true; + } + } + } + } + _ => {} + } + false + } + + /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` + /// requirement, provide a structured suggestion to constrain it to a given type `ty`. + /// + /// `is_bound_surely_present` indicates whether we know the bound we're looking for is + /// inside `bounds`. If that's the case then we can consider `bounds` containing only one + /// trait bound as the one we're looking for. This can help in cases where the associated + /// type is defined on a supertrait of the one present in the bounds. + fn constrain_generic_bound_associated_type_structured_suggestion( + &self, + diag: &mut Diagnostic, + trait_ref: &ty::TraitRef<'tcx>, + bounds: hir::GenericBounds<'_>, + assoc: &ty::AssocItem, + assoc_substs: &[ty::GenericArg<'tcx>], + ty: Ty<'tcx>, + msg: &str, + is_bound_surely_present: bool, + ) -> bool { + // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. + + let trait_bounds = bounds.iter().filter_map(|bound| match bound { + hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr), + _ => None, + }); + + let matching_trait_bounds = trait_bounds + .clone() + .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)) + .collect::<Vec<_>>(); + + let span = match &matching_trait_bounds[..] { + &[ptr] => ptr.span, + &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] { + &[ptr] => ptr.span, + _ => return false, + }, + _ => return false, + }; + + self.constrain_associated_type_structured_suggestion( + diag, + span, + assoc, + assoc_substs, + ty, + msg, + ) + } + + /// Given a span corresponding to a bound, provide a structured suggestion to set an + /// associated type to a given type `ty`. + fn constrain_associated_type_structured_suggestion( + &self, + diag: &mut Diagnostic, + span: Span, + assoc: &ty::AssocItem, + assoc_substs: &[ty::GenericArg<'tcx>], + ty: Ty<'tcx>, + msg: &str, + ) -> bool { + let tcx = self.tcx; + + if let Ok(has_params) = + tcx.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>')) + { + let (span, sugg) = if has_params { + let pos = span.hi() - BytePos(1); + let span = Span::new(pos, pos, span.ctxt(), span.parent()); + (span, format!(", {} = {}", assoc.ident(tcx), ty)) + } else { + let item_args = self.format_generic_args(assoc_substs); + (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty)) + }; + diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); + return true; + } + false + } + + pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String { + FmtPrinter::new(self.tcx, hir::def::Namespace::TypeNS) + .path_generic_args(Ok, args) + .expect("could not write to `String`.") + .into_buffer() + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 5b02956a106..23063e80b05 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -8,7 +8,7 @@ use rustc_middle::traits::{ StatementAsExpression, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self as ty, Ty, TypeVisitable}; +use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable}; use rustc_span::{sym, BytePos, Span}; use crate::errors::SuggAddLetForLetChains; @@ -351,6 +351,118 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + pub(super) fn suggest_function_pointers( + &self, + cause: &ObligationCause<'tcx>, + span: Span, + exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, + diag: &mut Diagnostic, + ) { + debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found); + let ty::error::ExpectedFound { expected, found } = exp_found; + let expected_inner = expected.peel_refs(); + let found_inner = found.peel_refs(); + if !expected_inner.is_fn() || !found_inner.is_fn() { + return; + } + match (&expected_inner.kind(), &found_inner.kind()) { + (ty::FnPtr(sig), ty::FnDef(did, substs)) => { + let expected_sig = &(self.normalize_fn_sig)(*sig); + let found_sig = + &(self.normalize_fn_sig)(self.tcx.fn_sig(*did).subst(self.tcx, substs)); + + let fn_name = self.tcx.def_path_str_with_substs(*did, substs); + + if !self.same_type_modulo_infer(*found_sig, *expected_sig) + || !sig.is_suggestable(self.tcx, true) + || ty::util::is_intrinsic(self.tcx, *did) + { + return; + } + + let (msg, sug) = match (expected.is_ref(), found.is_ref()) { + (true, false) => { + let msg = "consider using a reference"; + let sug = format!("&{fn_name}"); + (msg, sug) + } + (false, true) => { + let msg = "consider removing the reference"; + let sug = format!("{fn_name}"); + (msg, sug) + } + (true, true) => { + diag.note("fn items are distinct from fn pointers"); + let msg = "consider casting to a fn pointer"; + let sug = format!("&({fn_name} as {sig})"); + (msg, sug) + } + (false, false) => { + diag.note("fn items are distinct from fn pointers"); + let msg = "consider casting to a fn pointer"; + let sug = format!("{fn_name} as {sig}"); + (msg, sug) + } + }; + diag.span_suggestion(span, msg, sug, Applicability::MaybeIncorrect); + } + (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { + let expected_sig = + &(self.normalize_fn_sig)(self.tcx.fn_sig(*did1).subst(self.tcx, substs1)); + let found_sig = + &(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).subst(self.tcx, substs2)); + + if self.same_type_modulo_infer(*expected_sig, *found_sig) { + diag.note("different fn items have unique types, even if their signatures are the same"); + } + + if !self.same_type_modulo_infer(*found_sig, *expected_sig) + || !found_sig.is_suggestable(self.tcx, true) + || !expected_sig.is_suggestable(self.tcx, true) + || ty::util::is_intrinsic(self.tcx, *did1) + || ty::util::is_intrinsic(self.tcx, *did2) + { + return; + } + + let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2); + let sug = if found.is_ref() { + format!("&({fn_name} as {found_sig})") + } else { + format!("{fn_name} as {found_sig}") + }; + + let msg = format!( + "consider casting both fn items to fn pointers using `as {expected_sig}`" + ); + + diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect); + } + (ty::FnDef(did, substs), ty::FnPtr(sig)) => { + let expected_sig = + &(self.normalize_fn_sig)(self.tcx.fn_sig(*did).subst(self.tcx, substs)); + let found_sig = &(self.normalize_fn_sig)(*sig); + + if !self.same_type_modulo_infer(*found_sig, *expected_sig) { + return; + } + + let fn_name = self.tcx.def_path_str_with_substs(*did, substs); + + let casting = if expected.is_ref() { + format!("&({fn_name} as {found_sig})") + } else { + format!("{fn_name} as {found_sig}") + }; + + diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting)); + } + _ => { + return; + } + }; + } + pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> { if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) = (expected.kind(), found.kind()) @@ -411,8 +523,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, ) { let hir = self.tcx.hir(); - let fn_hir_id = hir.parent_id(cause.body_id); - if let Some(node) = self.tcx.hir().find(fn_hir_id) && + if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_sig, _, body_id), .. }) = node { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 8f53b1ccdf4..83d71edc2ab 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -209,6 +209,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { | ty::Foreign(..) | ty::Param(..) | ty::Closure(..) + | ty::GeneratorWitnessMIR(..) | ty::GeneratorWitness(..) => t.super_fold_with(self), ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t), diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 21b68ce9989..b92b162a978 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(Box::new(self.fields.trace.clone())); - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( + // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 + Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( self.tcx(), origin, a, diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index c07ac1d3ace..f6e0554fd1f 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(Box::new(self.fields.trace.clone())); - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( + // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 + Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( self.tcx(), origin, a, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index f235cb5ab45..f83219b8ee2 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -663,13 +663,13 @@ where debug!(?v_b); if self.ambient_covariance() { - // Covariance: a <= b. Hence, `b: a`. - self.push_outlives(v_b, v_a, self.ambient_variance_info); + // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. + self.push_outlives(v_a, v_b, self.ambient_variance_info); } if self.ambient_contravariance() { - // Contravariant: b <= a. Hence, `a: b`. - self.push_outlives(v_a, v_b, self.ambient_variance_info); + // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. + self.push_outlives(v_b, v_a, self.ambient_variance_info); } Ok(a) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index c54c66eab27..b68b0baaa40 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -3,7 +3,7 @@ use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; use hir::def::DefKind; use hir::def_id::{DefId, LocalDefId}; -use hir::{HirId, OpaqueTyOrigin}; +use hir::OpaqueTyOrigin; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; @@ -48,7 +48,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>( &self, value: T, - body_id: HirId, + body_id: LocalDefId, span: Span, param_env: ty::ParamEnv<'tcx>, ) -> InferOk<'tcx, T> { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 3d86279b03c..e3d95669171 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -112,7 +112,7 @@ fn compute_components<'tcx>( } // All regions are bound inside a witness - ty::GeneratorWitness(..) => (), + ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => (), // OutlivesTypeParameterEnv -- the actual checking that `X:'a` // is implied by the environment is done in regionck. diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index bd38b52ba34..51c34f0d55f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -191,12 +191,13 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { // from the "cause" field, we could perhaps give more tailored // error messages. let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); + // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) self.fields .infcx .inner .borrow_mut() .unwrap_region_constraints() - .make_subregion(origin, a, b); + .make_subregion(origin, b, a); Ok(a) } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index fcde00056cb..f75344f20b6 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -36,11 +36,19 @@ pub trait TraitEngine<'tcx>: 'tcx { obligation: PredicateObligation<'tcx>, ); - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>; + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; + + /// Among all pending obligations, collect those are stalled on a inference variable which has + /// changed since the last call to `select_where_possible`. Those obligations are marked as + /// successful and returned. + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>>; } pub trait TraitEngineExt<'tcx> { @@ -49,6 +57,8 @@ pub trait TraitEngineExt<'tcx> { infcx: &InferCtxt<'tcx>, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, ); + + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; } impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { @@ -61,4 +71,13 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { self.register_predicate_obligation(infcx, obligation); } } + + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { + let errors = self.select_where_possible(infcx); + if !errors.is_empty() { + return errors; + } + + self.collect_remaining_errors() + } } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 026713b6a28..3a82899660b 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -8,6 +8,7 @@ mod project; mod structural_impls; pub mod util; +use hir::def_id::LocalDefId; use rustc_hir as hir; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt}; @@ -146,7 +147,7 @@ impl<'tcx, O> Obligation<'tcx, O> { pub fn misc( tcx: TyCtxt<'tcx>, span: Span, - body_id: hir::HirId, + body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, trait_ref: impl ToPredicate<'tcx, O>, ) -> Obligation<'tcx, O> { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 379a76528f3..60b60edd2c8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -16,7 +16,7 @@ use rustc_data_structures::parallel; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; -use rustc_hir::def_id::StableCrateId; +use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; @@ -30,7 +30,7 @@ use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; -use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn, Untracked}; +use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn, Untracked}; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; @@ -47,7 +47,7 @@ use std::marker::PhantomPinned; use std::path::{Path, PathBuf}; use std::pin::Pin; use std::rc::Rc; -use std::sync::LazyLock; +use std::sync::{Arc, LazyLock}; use std::{env, fs, iter}; pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { @@ -548,7 +548,7 @@ fn escape_dep_env(symbol: Symbol) -> String { fn write_out_deps( sess: &Session, - boxed_resolver: &RefCell<BoxedResolver>, + cstore: &CrateStoreDyn, outputs: &OutputFilenames, out_filenames: &[PathBuf], ) { @@ -600,20 +600,19 @@ fn write_out_deps( } } - boxed_resolver.borrow_mut().access(|resolver| { - for cnum in resolver.cstore().crates_untracked() { - let source = resolver.cstore().crate_source_untracked(cnum); - if let Some((path, _)) = &source.dylib { - files.push(escape_dep_filename(&path.display().to_string())); - } - if let Some((path, _)) = &source.rlib { - files.push(escape_dep_filename(&path.display().to_string())); - } - if let Some((path, _)) = &source.rmeta { - files.push(escape_dep_filename(&path.display().to_string())); - } + let cstore = cstore.as_any().downcast_ref::<CStore>().unwrap(); + for cnum in cstore.crates_untracked() { + let source = cstore.crate_source_untracked(cnum); + if let Some((path, _)) = &source.dylib { + files.push(escape_dep_filename(&path.display().to_string())); } - }); + if let Some((path, _)) = &source.rlib { + files.push(escape_dep_filename(&path.display().to_string())); + } + if let Some((path, _)) = &source.rmeta { + files.push(escape_dep_filename(&path.display().to_string())); + } + } } let mut file = BufWriter::new(fs::File::create(&deps_filename)?); @@ -661,13 +660,11 @@ fn write_out_deps( } } -pub fn prepare_outputs( - sess: &Session, - krate: &ast::Crate, - boxed_resolver: &RefCell<BoxedResolver>, - crate_name: Symbol, -) -> Result<OutputFilenames> { +fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> { + let sess = tcx.sess; let _timer = sess.timer("prepare_outputs"); + let (_, krate) = &*tcx.resolver_for_lowering(()).borrow(); + let crate_name = tcx.crate_name(LOCAL_CRATE); // FIXME: rustdoc passes &[] instead of &krate.attrs here let outputs = util::build_output_filenames(&krate.attrs, sess); @@ -679,25 +676,21 @@ pub fn prepare_outputs( if let Some(ref input_path) = sess.io.input.opt_path() { if sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { - let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path }); - return Err(reported); + sess.emit_fatal(InputFileWouldBeOverWritten { path: input_path }); } if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) { - let reported = - sess.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path }); - return Err(reported); + sess.emit_fatal(GeneratedFileConflictsWithDirectory { input_path, dir_path }); } } } if let Some(ref dir) = sess.io.temps_dir { if fs::create_dir_all(dir).is_err() { - let reported = sess.emit_err(TempsDirError); - return Err(reported); + sess.emit_fatal(TempsDirError); } } - write_out_deps(sess, boxed_resolver, &outputs, &output_paths); + write_out_deps(sess, tcx.cstore_untracked(), &outputs, &output_paths); let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1; @@ -705,19 +698,19 @@ pub fn prepare_outputs( if !only_dep_info { if let Some(ref dir) = sess.io.output_dir { if fs::create_dir_all(dir).is_err() { - let reported = sess.emit_err(OutDirError); - return Err(reported); + sess.emit_fatal(OutDirError); } } } - Ok(outputs) + outputs.into() } pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; providers.hir_crate = rustc_ast_lowering::lower_to_hir; + providers.output_filenames = output_filenames; proc_macro_decls::provide(providers); rustc_const_eval::provide(providers); rustc_middle::hir::provide(providers); @@ -900,6 +893,15 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } }); + if tcx.sess.opts.unstable_opts.drop_tracking_mir { + tcx.hir().par_body_owners(|def_id| { + if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) { + tcx.ensure().mir_generator_witnesses(def_id); + tcx.ensure().check_generator_obligations(def_id); + } + }); + } + sess.time("layout_testing", || layout_test::test_layout(tcx)); // Avoid overwhelming user with errors if borrow checking failed. diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index d5a49dd75be..4b0180741c1 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -65,7 +65,7 @@ impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> { } impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> { - pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T { + pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T { (*self.0).get_mut().enter(f) } } @@ -212,8 +212,6 @@ impl<'tcx> Queries<'tcx> { let crate_name = *self.crate_name()?.borrow(); let (krate, resolver, lint_store) = self.expansion()?.steal(); - let outputs = passes::prepare_outputs(self.session(), &krate, &resolver, crate_name)?; - let ty::ResolverOutputs { untracked, global_ctxt: untracked_resolutions, @@ -237,7 +235,6 @@ impl<'tcx> Queries<'tcx> { 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(tcx.sess.features_untracked()); let feed = tcx.feed_local_crate(); feed.crate_name(crate_name); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index f94bc4d4c66..52a4e0e7418 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -802,6 +802,7 @@ fn test_unstable_options_tracking_hash() { tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(thir_unsafeck, true); + tracked!(tiny_const_eval_limit, true); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(trait_solver, TraitSolver::Chalk); tracked!(translate_remapped_path_to_local_path, false); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index fe188162cf8..8361c81f0ef 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -56,9 +56,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{ - Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin, -}; +use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin}; use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; @@ -583,12 +581,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { // If the method is an impl for a trait, don't doc. - if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl { + let context = method_context(cx, impl_item.owner_id.def_id); + if context == MethodLateContext::TraitImpl { return; } // If the method is an impl for an item with docs_hidden, don't doc. - if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl { + if context == MethodLateContext::PlainImpl { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); let impl_ty = cx.tcx.type_of(parent); let outerdef = match impl_ty.kind() { @@ -732,7 +731,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { cx.tcx, param_env, ty, - traits::ObligationCause::misc(item.span, item.hir_id()), + traits::ObligationCause::misc(item.span, item.owner_id.def_id), ) .is_ok() { @@ -1296,19 +1295,18 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { _: &'tcx FnDecl<'_>, _: &'tcx Body<'_>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller - && let attrs = cx.tcx.hir().attrs(hir_id) // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) - { - cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { - label: span, - parse_sess: &cx.tcx.sess.parse_sess, - }); - } + && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller) + { + cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }); + } } } @@ -2175,13 +2173,31 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { dropped_predicate_count += 1; } - if drop_predicate && !in_where_clause { - lint_spans.push(predicate_span); - } else if drop_predicate && i + 1 < num_predicates { - // If all the bounds on a predicate were inferable and there are - // further predicates, we want to eat the trailing comma. - let next_predicate_span = hir_generics.predicates[i + 1].span(); - where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo())); + if drop_predicate { + if !in_where_clause { + lint_spans.push(predicate_span); + } else if predicate_span.from_expansion() { + // Don't try to extend the span if it comes from a macro expansion. + where_lint_spans.push(predicate_span); + } else if i + 1 < num_predicates { + // If all the bounds on a predicate were inferable and there are + // further predicates, we want to eat the trailing comma. + let next_predicate_span = hir_generics.predicates[i + 1].span(); + if next_predicate_span.from_expansion() { + where_lint_spans.push(predicate_span); + } else { + where_lint_spans + .push(predicate_span.to(next_predicate_span.shrink_to_lo())); + } + } else { + // Eat the optional trailing comma after the last predicate. + let where_span = hir_generics.where_clause_span; + if where_span.from_expansion() { + where_lint_spans.push(predicate_span); + } else { + where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi())); + } + } } else { where_lint_spans.extend(self.consolidate_outlives_bound_spans( predicate_span.shrink_to_lo(), @@ -2225,6 +2241,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { Applicability::MaybeIncorrect }; + // Due to macros, there might be several predicates with the same span + // and we only want to suggest removing them once. + lint_spans.sort_unstable(); + lint_spans.dedup(); + cx.emit_spanned_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), @@ -2661,7 +2682,7 @@ pub struct ClashingExternDeclarations { /// the symbol should be reported as a clashing declaration. // FIXME: Technically, we could just store a &'tcx str here without issue; however, the // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime. - seen_decls: FxHashMap<Symbol, HirId>, + seen_decls: FxHashMap<Symbol, hir::OwnerId>, } /// Differentiate between whether the name for an extern decl came from the link_name attribute or @@ -2687,19 +2708,20 @@ impl ClashingExternDeclarations { pub(crate) fn new() -> Self { ClashingExternDeclarations { seen_decls: FxHashMap::default() } } + /// Insert a new foreign item into the seen set. If a symbol with the same name already exists /// for the item, return its HirId without updating the set. - fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> { + fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> { let did = fi.owner_id.to_def_id(); let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); let name = Symbol::intern(tcx.symbol_name(instance).name); - if let Some(&hir_id) = self.seen_decls.get(&name) { + if let Some(&existing_id) = self.seen_decls.get(&name) { // Avoid updating the map with the new entry when we do find a collision. We want to // make sure we're always pointing to the first definition as the previous declaration. // This lets us avoid emitting "knock-on" diagnostics. - Some(hir_id) + Some(existing_id) } else { - self.seen_decls.insert(name, fi.hir_id()) + self.seen_decls.insert(name, fi.owner_id) } } @@ -2926,16 +2948,16 @@ impl ClashingExternDeclarations { impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]); impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { + #[instrument(level = "trace", skip(self, cx))] fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) { - trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi); if let ForeignItemKind::Fn(..) = this_fi.kind { let tcx = cx.tcx; - if let Some(existing_hid) = self.insert(tcx, this_fi) { - let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); + if let Some(existing_did) = self.insert(tcx, this_fi) { + let existing_decl_ty = tcx.type_of(existing_did); let this_decl_ty = tcx.type_of(this_fi.owner_id); debug!( "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", - existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty + existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty ); // Check that the declarations match. if !Self::structurally_same_type( @@ -2944,7 +2966,7 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { this_decl_ty, CItemKind::Declaration, ) { - let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner()); + let orig_fi = tcx.hir().expect_foreign_item(existing_did); let orig = Self::name_of_extern_decl(tcx, orig_fi); // We want to ensure that we use spans for both decls that include where the diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 8046cc21cea..d1d4bb37528 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -882,6 +882,9 @@ pub trait LintContext: Sized { ); } } + BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => { + db.help("consider implementing the trait by hand, or remove the `packed` attribute"); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index 5219992ee94..1add352e0c4 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -139,9 +139,10 @@ fn suggest_question_mark<'tcx>( let ty = substs.type_at(0); let infcx = cx.tcx.infer_ctxt().build(); + let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); let cause = ObligationCause::new( span, - body_id.hir_id, + body_def_id, rustc_infer::traits::ObligationCauseCode::MiscObligation, ); let errors = rustc_trait_selection::traits::fully_solve_bound( diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b2a2656746e..b42878a02ee 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -66,13 +66,12 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { self.context.last_node_with_lint_attrs = prev; } - fn with_param_env<F>(&mut self, id: hir::HirId, f: F) + fn with_param_env<F>(&mut self, id: hir::OwnerId, f: F) where F: FnOnce(&mut Self), { let old_param_env = self.context.param_env; - self.context.param_env = - self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id)); + self.context.param_env = self.context.tcx.param_env(id); f(self); self.context.param_env = old_param_env; } @@ -132,7 +131,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let old_cached_typeck_results = self.context.cached_typeck_results.take(); let old_enclosing_body = self.context.enclosing_body.take(); self.with_lint_attrs(it.hir_id(), |cx| { - cx.with_param_env(it.hir_id(), |cx| { + cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_item, it); hir_visit::walk_item(cx, it); lint_callback!(cx, check_item_post, it); @@ -145,7 +144,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { self.with_lint_attrs(it.hir_id(), |cx| { - cx.with_param_env(it.hir_id(), |cx| { + cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_foreign_item, it); hir_visit::walk_foreign_item(cx, it); }); @@ -180,7 +179,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas decl: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, span: Span, - id: hir::HirId, + id: LocalDefId, ) { // Wrap in typeck results here, not just in visit_nested_body, // in order for `check_fn` to be able to use them. @@ -268,7 +267,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let generics = self.context.generics.take(); self.context.generics = Some(&trait_item.generics); self.with_lint_attrs(trait_item.hir_id(), |cx| { - cx.with_param_env(trait_item.hir_id(), |cx| { + cx.with_param_env(trait_item.owner_id, |cx| { lint_callback!(cx, check_trait_item, trait_item); hir_visit::walk_trait_item(cx, trait_item); }); @@ -280,7 +279,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let generics = self.context.generics.take(); self.context.generics = Some(&impl_item.generics); self.with_lint_attrs(impl_item.hir_id(), |cx| { - cx.with_param_env(impl_item.hir_id(), |cx| { + cx.with_param_env(impl_item.owner_id, |cx| { lint_callback!(cx, check_impl_item, impl_item); hir_visit::walk_impl_item(cx, impl_item); lint_callback!(cx, check_impl_item_post, impl_item); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d6be4da0328..ba15dbd86cf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -64,6 +64,7 @@ mod let_underscore; mod levels; mod lints; mod methods; +mod multiple_supertrait_upcastable; mod non_ascii_idents; mod non_fmt_panic; mod nonstandard_style; @@ -98,6 +99,7 @@ use hidden_unicode_codepoints::*; use internal::*; use let_underscore::*; use methods::*; +use multiple_supertrait_upcastable::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; @@ -232,6 +234,7 @@ late_lint_methods!( InvalidAtomicOrdering: InvalidAtomicOrdering, NamedAsmLabels: NamedAsmLabels, OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, + MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c997d8945d1..0c1019545f3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -917,6 +917,13 @@ pub struct CStringPtr { pub unwrap: Span, } +// multiple_supertrait_upcastable.rs +#[derive(LintDiagnostic)] +#[diag(lint_multple_supertrait_upcastable)] +pub struct MultipleSupertraitUpcastable { + pub ident: Ident, +} + // non_ascii_idents.rs #[derive(LintDiagnostic)] #[diag(lint_identifier_non_ascii_char)] diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs new file mode 100644 index 00000000000..c2ed0e19f40 --- /dev/null +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -0,0 +1,60 @@ +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_hir as hir; +use rustc_span::sym; + +declare_lint! { + /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple + /// supertraits. + /// + /// ### Example + /// + /// ```rust + /// trait A {} + /// trait B {} + /// + /// #[warn(multiple_supertrait_upcastable)] + /// trait C: A + B {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To support upcasting with multiple supertraits, we need to store multiple vtables and this + /// can result in extra space overhead, even if no code actually uses upcasting. + /// This lint allows users to identify when such scenarios occur and to decide whether the + /// additional overhead is justified. + pub MULTIPLE_SUPERTRAIT_UPCASTABLE, + Allow, + "detect when an object-safe trait has multiple supertraits", + @feature_gate = sym::multiple_supertrait_upcastable; +} + +declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]); + +impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + let def_id = item.owner_id.to_def_id(); + // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because + // the latter will report `where_clause_object_safety` lint. + if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind + && cx.tcx.object_safety_violations(def_id).is_empty() + { + let direct_super_traits_iter = cx.tcx + .super_predicates_of(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred()); + if direct_super_traits_iter.count() > 1 { + cx.emit_spanned_lint( + MULTIPLE_SUPERTRAIT_UPCASTABLE, + cx.tcx.def_span(def_id), + crate::lints::MultipleSupertraitUpcastable { + ident: item.ident + }, + ); + } + } + } +} diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 74d234fabea..71e2e66bdeb 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -10,8 +10,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; use rustc_hir::{GenericParamKind, PatKind}; use rustc_middle::ty; -use rustc_span::symbol::sym; -use rustc_span::{symbol::Ident, BytePos, Span}; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; #[derive(PartialEq)] @@ -21,9 +22,8 @@ pub enum MethodLateContext { PlainImpl, } -pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext { - let def_id = cx.tcx.hir().local_def_id(id); - let item = cx.tcx.associated_item(def_id); +pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext { + let item = cx.tcx.associated_item(id); match item.container { ty::TraitContainer => MethodLateContext::TraitAutoImpl, ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) { @@ -379,13 +379,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { _: &hir::FnDecl<'_>, _: &hir::Body<'_>, _: Span, - id: hir::HirId, + id: LocalDefId, ) { - let attrs = cx.tcx.hir().attrs(id); match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) + if sig.header.abi != Abi::Rust + && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { return; } @@ -398,7 +398,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) { + if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 0bf01c4e567..16964565b01 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -4,6 +4,7 @@ use rustc_ast as ast; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; use rustc_session::lint::LintPass; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -36,7 +37,7 @@ macro_rules! late_lint_methods { b: &'tcx hir::FnDecl<'tcx>, c: &'tcx hir::Body<'tcx>, d: Span, - e: hir::HirId); + e: LocalDefId); fn check_trait_item(a: &'tcx hir::TraitItem<'tcx>); fn check_impl_item(a: &'tcx hir::ImplItem<'tcx>); fn check_impl_item_post(a: &'tcx hir::ImplItem<'tcx>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index be47a3e238c..b0a5d3674ad 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -14,6 +14,7 @@ use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -1107,6 +1108,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Placeholder(..) | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), } @@ -1223,9 +1225,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) { - let def_id = self.cx.tcx.hir().local_def_id(id); - let sig = self.cx.tcx.fn_sig(def_id); + fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + let sig = self.cx.tcx.fn_sig(def_id).subst_identity(); let sig = self.cx.tcx.erase_late_bound_regions(sig); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { @@ -1238,9 +1239,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_static(&mut self, id: hir::HirId, span: Span) { - let def_id = self.cx.tcx.hir().local_def_id(id); - let ty = self.cx.tcx.type_of(def_id); + fn check_foreign_static(&mut self, id: hir::OwnerId, span: Span) { + let ty = self.cx.tcx.type_of(id); self.check_type_for_ffi_and_report_errors(span, ty, true, false); } @@ -1260,10 +1260,10 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { if !vis.is_internal_abi(abi) { match it.kind { hir::ForeignItemKind::Fn(ref decl, _, _) => { - vis.check_foreign_fn(it.hir_id(), decl); + vis.check_foreign_fn(it.owner_id.def_id, decl); } hir::ForeignItemKind::Static(ref ty, _) => { - vis.check_foreign_static(it.hir_id(), ty.span); + vis.check_foreign_static(it.owner_id, ty.span); } hir::ForeignItemKind::Type => (), } @@ -1279,7 +1279,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { decl: &'tcx hir::FnDecl<'_>, _: &'tcx hir::Body<'_>, _: Span, - hir_id: hir::HirId, + id: LocalDefId, ) { use hir::intravisit::FnKind; @@ -1291,7 +1291,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition }; if !vis.is_internal_abi(abi) { - vis.check_foreign_fn(hir_id, decl); + vis.check_foreign_fn(id, decl); } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b6481d70bc8..d731c10f46e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3381,6 +3381,7 @@ declare_lint_pass! { REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, NAMED_ARGUMENTS_USED_POSITIONALLY, IMPLIED_BOUNDS_ENTAILMENT, + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, ] } @@ -3531,9 +3532,15 @@ declare_lint! { /// /// ### Explanation /// - /// Previously, there were very like checks being performed on `#[doc(..)]` - /// unlike the other attributes. It'll now catch all the issues that it - /// silently ignored previously. + /// Previously, incorrect usage of the `#[doc(..)]` attribute was not + /// being validated. Usually these should be rejected as a hard error, + /// but this lint was introduced to avoid breaking any existing + /// crates which included them. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #82730] for more details. + /// + /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730 pub INVALID_DOC_ATTRIBUTES, Warn, "detects invalid `#[doc(...)]` attributes", @@ -4109,3 +4116,35 @@ declare_lint! { reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } + +declare_lint! { + /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field + /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits. + /// + /// ### Example + /// + /// ```rust + /// #[repr(packed)] + /// #[derive(Hash)] + /// struct FlexZeroSlice { + /// width: u8, + /// data: [u8], + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted but is being phased out, because fields in packed structs are + /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary + /// exception because certain crates depended on them. + pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + Warn, + "`[u8]` slice used in a packed struct with `derive`", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, + }; + report_in_external_macro +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7054d1e9f10..6efbf5ce9ee 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -521,6 +521,7 @@ pub enum BuiltinLintDiagnostics { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, + ByteSliceInPackedStructWithDerive, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 32338f9dfc5..08098c9bb2a 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -4,7 +4,10 @@ use annotate_snippets::{ }; use fluent_bundle::{FluentBundle, FluentError, FluentResource}; use fluent_syntax::{ - ast::{Attribute, Entry, Identifier, Message}, + ast::{ + Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, + PatternElement, + }, parser::ParserError, }; use proc_macro::{Diagnostic, Level, Span}; @@ -185,9 +188,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok }; let mut constants = TokenStream::new(); + let mut messagerefs = Vec::new(); for entry in resource.entries() { let span = res.krate.span(); - if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry { + if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) = + entry + { let _ = previous_defns.entry(name.to_string()).or_insert(path_span); if name.contains('-') { @@ -200,6 +206,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok .emit(); } + if let Some(Pattern { elements }) = value { + for elt in elements { + if let PatternElement::Placeable { + expression: + Expression::Inline(InlineExpression::MessageReference { id, .. }), + } = elt + { + messagerefs.push((id.name, *name)); + } + } + } + // Require that the message name starts with the crate name // `hir_typeck_foo_bar` (in `hir_typeck.ftl`) // `const_eval_baz` (in `const_eval.ftl`) @@ -258,6 +276,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok } } + for (mref, name) in messagerefs.into_iter() { + if !previous_defns.contains_key(mref) { + Diagnostic::spanned( + path_span, + Level::Error, + format!("referenced message `{mref}` does not exist (in message `{name}`)"), + ) + .help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)")) + .emit(); + } + } + if let Err(errs) = bundle.add_resource(resource) { for e in errs { match e { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 44da3fbe300..bb2dd290c6d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -985,7 +985,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let vis = self.get_visibility(id); let span = self.get_span(id, sess); let macro_rules = match kind { - DefKind::Macro(..) => self.root.tables.macro_rules.get(self, id).is_some(), + DefKind::Macro(..) => self.root.tables.is_macro_rules.get(self, id), _ => false, }; @@ -1283,7 +1283,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { match self.def_kind(id) { DefKind::Macro(_) => { - let macro_rules = self.root.tables.macro_rules.get(self, id).is_some(); + let macro_rules = self.root.tables.is_macro_rules.get(self, id); let body = self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); ast::MacroDef { macro_rules, body: ast::ptr::P(body) } @@ -1595,11 +1595,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_attr_flags(self, index: DefIndex) -> AttrFlags { - self.root.tables.attr_flags.get(self, index).unwrap_or(AttrFlags::empty()) + self.root.tables.attr_flags.get(self, index) } fn get_is_intrinsic(self, index: DefIndex) -> bool { - self.root.tables.is_intrinsic.get(self, index).is_some() + self.root.tables.is_intrinsic.get(self, index) } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2fa645cd9e3..9b1401f4a44 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -202,6 +202,7 @@ provide! { tcx, def_id, other, cdata, thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } + mir_generator_witnesses => { table } promoted_mir => { table } def_span => { table } def_ident_span => { table } @@ -226,12 +227,7 @@ provide! { tcx, def_id, other, cdata, deduced_param_attrs => { table } is_type_alias_impl_trait => { debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); - cdata - .root - .tables - .is_type_alias_impl_trait - .get(cdata, def_id.index) - .is_some() + cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata @@ -637,6 +633,12 @@ impl CStore { .get_attr_flags(def_id.index) .contains(AttrFlags::MAY_HAVE_DOC_LINKS) } + + pub fn is_doc_hidden_untracked(&self, def_id: DefId) -> bool { + self.get_crate_data(def_id.krate) + .get_attr_flags(def_id.index) + .contains(AttrFlags::IS_DOC_HIDDEN) + } } impl CrateStore for CStore { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2ecaa33d4d3..29507ff3a86 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::TableBuilder; use crate::rmeta::*; +use rustc_ast::util::comments; use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; @@ -38,7 +39,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{ self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, }; -use rustc_target::abi::VariantIdx; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; @@ -483,7 +483,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map())) } - fn encode_source_map(&mut self) -> LazyTable<u32, LazyValue<rustc_span::SourceFile>> { + fn encode_source_map(&mut self) -> LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -760,36 +760,54 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } +struct AnalyzeAttrState { + is_exported: bool, + may_have_doc_links: bool, + is_doc_hidden: bool, +} + /// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and /// useful in downstream crates. Local-only attributes are an obvious example, but some /// rustdoc-specific attributes can equally be of use while documenting the current crate only. /// /// Removing these superfluous attributes speeds up compilation by making the metadata smaller. /// -/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public +/// Note: the `is_exported` parameter is used to cache whether the given `DefId` has a public /// visibility: this is a piece of data that can be computed once per defid, and not once per /// attribute. Some attributes would only be usable downstream if they are public. #[inline] -fn should_encode_attr( - tcx: TyCtxt<'_>, - attr: &Attribute, - def_id: LocalDefId, - is_def_id_public: &mut Option<bool>, -) -> bool { +fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool { + let mut should_encode = false; if rustc_feature::is_builtin_only_local(attr.name_or_empty()) { // Attributes marked local-only don't need to be encoded for downstream crates. - false - } else if attr.doc_str().is_some() { - // We keep all public doc comments because they might be "imported" into downstream crates - // if they use `#[doc(inline)]` to copy an item's documentation into their own. - *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id)) + } else if let Some(s) = attr.doc_str() { + // We keep all doc comments reachable to rustdoc because they might be "imported" into + // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into + // their own. + if state.is_exported { + should_encode = true; + if comments::may_have_doc_links(s.as_str()) { + state.may_have_doc_links = true; + } + } } else if attr.has_name(sym::doc) { - // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can - // remove it. It won't be inlinable in downstream crates. - attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false) + // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in + // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates. + if let Some(item_list) = attr.meta_item_list() { + for item in item_list { + if !item.has_name(sym::inline) { + should_encode = true; + if item.has_name(sym::hidden) { + state.is_doc_hidden = true; + break; + } + } + } + } } else { - true + should_encode = true; } + should_encode } fn should_encode_visibility(def_kind: DefKind) -> bool { @@ -1094,7 +1112,7 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // of the trait fn to look for any RPITITs, but that's kinda doing a lot // of work. We can probably remove this when we refactor RPITITs to be // associated types. - tcx.fn_sig(trait_item_def_id).skip_binder().output().walk().any(|arg| { + tcx.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Alias(ty::Projection, data) = ty.kind() && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder @@ -1109,28 +1127,28 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool { impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let mut is_public: Option<bool> = None; - - let hir_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); - let mut attrs = hir_attrs + let mut state = AnalyzeAttrState { + is_exported: tcx.effective_visibilities(()).is_exported(def_id), + may_have_doc_links: false, + is_doc_hidden: false, + }; + let attr_iter = tcx + .hir() + .attrs(tcx.hir().local_def_id_to_hir_id(def_id)) .iter() - .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public)); + .filter(|attr| analyze_attr(attr, &mut state)); + + record_array!(self.tables.attributes[def_id.to_def_id()] <- attr_iter); - record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone()); let mut attr_flags = AttrFlags::empty(); - if attrs.any(|attr| attr.may_have_doc_links()) { + if state.may_have_doc_links { attr_flags |= AttrFlags::MAY_HAVE_DOC_LINKS; } - if hir_attrs - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .filter_map(|attr| attr.meta_item_list()) - .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) - { + if state.is_doc_hidden { attr_flags |= AttrFlags::IS_DOC_HIDDEN; } if !attr_flags.is_empty() { - self.tables.attr_flags.set(def_id.local_def_index, attr_flags); + self.tables.attr_flags.set_nullable(def_id.local_def_index, attr_flags); } } @@ -1189,8 +1207,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { - let params_in_repr = self.tcx.params_in_repr(def_id); - record!(self.tables.params_in_repr[def_id] <- params_in_repr); + self.encode_info_for_adt(def_id); } if should_encode_trait_impl_trait_tys(tcx, def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) @@ -1213,46 +1230,53 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) { + #[instrument(level = "trace", skip(self))] + fn encode_info_for_adt(&mut self, def_id: DefId) { let tcx = self.tcx; - let variant = &def.variant(index); - let def_id = variant.def_id; - debug!("EncodeContext::encode_enum_variant_info({:?})", def_id); - - let data = VariantData { - discr: variant.discr, - ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }; + let adt_def = tcx.adt_def(def_id); + record!(self.tables.repr_options[def_id] <- adt_def.repr()); + + let params_in_repr = self.tcx.params_in_repr(def_id); + record!(self.tables.params_in_repr[def_id] <- params_in_repr); - record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); - record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { - assert!(f.did.is_local()); - f.did.index - })); - if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { - // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id)); + if adt_def.is_enum() { + record_array!(self.tables.children[def_id] <- iter::from_generator(|| + for variant in tcx.adt_def(def_id).variants() { + yield variant.def_id.index; + // Encode constructors which take a separate slot in value namespace. + if let Some(ctor_def_id) = variant.ctor_def_id() { + yield ctor_def_id.index; + } + } + )); + } else { + // For non-enum, there is only one variant, and its def_id is the adt's. + debug_assert_eq!(adt_def.variants().len(), 1); + debug_assert_eq!(adt_def.non_enum_variant().def_id, def_id); + // Therefore, the loop over variants will encode its fields as the adt's children. } - } - fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) { - let variant = &def.variant(index); - let Some((ctor_kind, def_id)) = variant.ctor else { return }; - debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id); + for variant in adt_def.variants().iter() { + let data = VariantData { + discr: variant.discr, + ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), + is_non_exhaustive: variant.is_field_list_non_exhaustive(), + }; + record!(self.tables.variant_data[variant.def_id] <- data); - // FIXME(eddyb) encode only the `CtorKind` for constructors. - let data = VariantData { - discr: variant.discr, - ctor: Some((ctor_kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }; + self.tables.constness.set(variant.def_id.index, hir::Constness::Const); + record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| { + assert!(f.did.is_local()); + f.did.index + })); - record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); - if ctor_kind == CtorKind::Fn { - record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id)); + if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { + self.tables.constness.set(ctor_def_id.index, hir::Constness::Const); + let fn_sig = tcx.fn_sig(ctor_def_id); + record!(self.tables.fn_sig[ctor_def_id] <- fn_sig); + // FIXME only encode signature for ctor_def_id + record!(self.tables.fn_sig[variant.def_id] <- fn_sig); + } } } @@ -1286,8 +1310,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Struct(ref vdata, _) => { yield item_id.owner_id.def_id.local_def_index; // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_hir_id) = vdata.ctor_hir_id() { - yield tcx.hir().local_def_id(ctor_hir_id).local_def_index; + if let Some(ctor_def_id) = vdata.ctor_def_id() { + yield ctor_def_id.local_def_index; } } _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { @@ -1305,25 +1329,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>) { - let variant = adt_def.non_enum_variant(); - let Some((ctor_kind, def_id)) = variant.ctor else { return }; - debug!("EncodeContext::encode_struct_ctor({:?})", def_id); - - let data = VariantData { - discr: variant.discr, - ctor: Some((ctor_kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }; - - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); - if ctor_kind == CtorKind::Fn { - record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id)); - } - } - fn encode_explicit_item_bounds(&mut self, def_id: DefId) { debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id); let bounds = self.tcx.explicit_item_bounds(def_id); @@ -1387,7 +1392,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if impl_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); + self.tables.is_intrinsic.set_nullable(def_id.index, true); } } } @@ -1409,6 +1414,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); + + if let DefKind::Generator = self.tcx.def_kind(def_id) && tcx.sess.opts.unstable_opts.drop_tracking_mir { + record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id)); + } } if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); @@ -1519,7 +1528,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { - self.tables.macro_rules.set(def_id.index, ()); + self.tables.is_macro_rules.set_nullable(def_id.index, true); } record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } @@ -1529,36 +1538,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) { - self.tables.is_type_alias_impl_trait.set(def_id.index, ()); + self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true); } } - hir::ItemKind::Enum(..) => { - let adt_def = self.tcx.adt_def(def_id); - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - } - hir::ItemKind::Struct(..) => { - let adt_def = self.tcx.adt_def(def_id); - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - self.tables.constness.set(def_id.index, hir::Constness::Const); - - let variant = adt_def.non_enum_variant(); - record!(self.tables.variant_data[def_id] <- VariantData { - discr: variant.discr, - ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }); - } - hir::ItemKind::Union(..) => { - let adt_def = self.tcx.adt_def(def_id); - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - - let variant = adt_def.non_enum_variant(); - record!(self.tables.variant_data[def_id] <- VariantData { - discr: variant.discr, - ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }); - } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); self.tables.constness.set(def_id.index, *constness); @@ -1597,31 +1579,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Static(..) | hir::ItemKind::Const(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::TyAlias(..) => {} }; // FIXME(eddyb) there should be a nicer way to do this. match item.kind { - hir::ItemKind::Enum(..) => { - record_array!(self.tables.children[def_id] <- iter::from_generator(|| - for variant in tcx.adt_def(def_id).variants() { - yield variant.def_id.index; - // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_def_id) = variant.ctor_def_id() { - yield ctor_def_id.index; - } - } - )) - } - hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - record_array!(self.tables.children[def_id] <- - self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| { - assert!(f.did.is_local()); - f.did.index - }) - ) - } hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); record_array!(self.tables.children[def_id] <- @@ -1636,7 +1602,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let hir::ItemKind::Fn(..) = item.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); + self.tables.is_intrinsic.set_nullable(def_id.index, true); } } if let hir::ItemKind::Impl { .. } = item.kind { @@ -1649,17 +1615,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // so it's easier to do that here then to wait until we would encounter // normally in the visitor walk. match item.kind { - hir::ItemKind::Enum(..) => { - let def = self.tcx.adt_def(item.owner_id.to_def_id()); - for (i, _) in def.variants().iter_enumerated() { - self.encode_enum_variant_info(def, i); - self.encode_enum_variant_ctor(def, i); - } - } - hir::ItemKind::Struct(..) => { - let def = self.tcx.adt_def(item.owner_id.to_def_id()); - self.encode_struct_ctor(def); - } hir::ItemKind::Impl { .. } => { for &trait_item_def_id in self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter() @@ -1696,7 +1651,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Closure(_, substs) => { let constness = self.tcx.constness(def_id.to_def_id()); self.tables.constness.set(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig()); + record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig())); } _ => bug!("closure that is neither generator nor closure"), @@ -2038,7 +1993,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let hir::ForeignItemKind::Fn(..) = nitem.kind { if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); + self.tables.is_intrinsic.set_nullable(def_id.index, true); } } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 69690264ae4..37af9e64e9a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -185,9 +185,9 @@ enum LazyState { Previous(NonZeroUsize), } -type SyntaxContextTable = LazyTable<u32, LazyValue<SyntaxContextData>>; -type ExpnDataTable = LazyTable<ExpnIndex, LazyValue<ExpnData>>; -type ExpnHashTable = LazyTable<ExpnIndex, LazyValue<ExpnHash>>; +type SyntaxContextTable = LazyTable<u32, Option<LazyValue<SyntaxContextData>>>; +type ExpnDataTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnData>>>; +type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>; #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct ProcMacroData { @@ -253,7 +253,7 @@ pub(crate) struct CrateRoot { def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>, - source_map: LazyTable<u32, LazyValue<rustc_span::SourceFile>>, + source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>, compiler_builtins: bool, needs_allocator: bool, @@ -315,21 +315,27 @@ pub(crate) struct IncoherentImpls { /// Define `LazyTables` and `TableBuilders` at the same time. macro_rules! define_tables { - ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => { + ( + - nullable: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+ + - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+ + ) => { #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct LazyTables { - $($name: LazyTable<$IDX, $T>),+ + $($name1: LazyTable<$IDX1, $T1>,)+ + $($name2: LazyTable<$IDX2, Option<$T2>>,)+ } #[derive(Default)] struct TableBuilders { - $($name: TableBuilder<$IDX, $T>),+ + $($name1: TableBuilder<$IDX1, $T1>,)+ + $($name2: TableBuilder<$IDX2, Option<$T2>>,)+ } impl TableBuilders { fn encode(&self, buf: &mut FileEncoder) -> LazyTables { LazyTables { - $($name: self.$name.encode(buf)),+ + $($name1: self.$name1.encode(buf),)+ + $($name2: self.$name2.encode(buf),)+ } } } @@ -337,9 +343,15 @@ macro_rules! define_tables { } define_tables! { +- nullable: + is_intrinsic: Table<DefIndex, bool>, + is_macro_rules: Table<DefIndex, bool>, + is_type_alias_impl_trait: Table<DefIndex, bool>, + attr_flags: Table<DefIndex, AttrFlags>, + +- optional: attributes: Table<DefIndex, LazyArray<ast::Attribute>>, children: Table<DefIndex, LazyArray<DefIndex>>, - opt_def_kind: Table<DefIndex, DefKind>, visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>, def_span: Table<DefIndex, LazyValue<Span>>, @@ -357,20 +369,20 @@ define_tables! { super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, type_of: Table<DefIndex, LazyValue<Ty<'static>>>, variances_of: Table<DefIndex, LazyArray<ty::Variance>>, - fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>, + fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::PolyFnSig<'static>>>>, codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>, 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>>>, + mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, // FIXME(compiler-errors): Why isn't this a LazyArray? thir_abstract_const: Table<DefIndex, LazyValue<ty::Const<'static>>>, impl_parent: Table<DefIndex, RawDefId>, impl_polarity: Table<DefIndex, ty::ImplPolarity>, constness: Table<DefIndex, hir::Constness>, - is_intrinsic: Table<DefIndex, ()>, impl_defaultness: Table<DefIndex, hir::Defaultness>, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>, @@ -380,7 +392,6 @@ define_tables! { fn_arg_names: Table<DefIndex, LazyArray<Ident>>, generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>, trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, - trait_item_def_id: Table<DefIndex, RawDefId>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, @@ -395,18 +406,12 @@ define_tables! { def_path_hashes: Table<DefIndex, DefPathHash>, proc_macro_quoted_spans: Table<usize, LazyValue<Span>>, generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>, - attr_flags: Table<DefIndex, AttrFlags>, variant_data: Table<DefIndex, LazyValue<VariantData>>, assoc_container: Table<DefIndex, ty::AssocItemContainer>, - // Slot is full when macro is macro_rules. - macro_rules: Table<DefIndex, ()>, macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>, proc_macro: Table<DefIndex, MacroKind>, module_reexports: Table<DefIndex, LazyArray<ModChild>>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, - // Slot is full when opaque is TAIT. - is_type_alias_impl_trait: Table<DefIndex, ()>, - trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>, } @@ -419,6 +424,7 @@ struct VariantData { } bitflags::bitflags! { + #[derive(Default)] pub struct AttrFlags: u8 { const MAY_HAVE_DOC_LINKS = 1 << 0; const IS_DOC_HIDDEN = 1 << 1; diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index dc003227d40..70dbf6476e2 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -16,6 +16,7 @@ use std::num::NonZeroUsize; /// but this has no impact on safety. pub(super) trait FixedSizeEncoding: Default { /// This should be `[u8; BYTE_LEN]`; + /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations. type ByteArray; fn from_bytes(b: &Self::ByteArray) -> Self; @@ -199,31 +200,31 @@ impl FixedSizeEncoding for Option<RawDefId> { } } -impl FixedSizeEncoding for Option<AttrFlags> { +impl FixedSizeEncoding for AttrFlags { type ByteArray = [u8; 1]; #[inline] fn from_bytes(b: &[u8; 1]) -> Self { - (b[0] != 0).then(|| AttrFlags::from_bits_truncate(b[0])) + AttrFlags::from_bits_truncate(b[0]) } #[inline] fn write_to_bytes(self, b: &mut [u8; 1]) { - b[0] = self.map_or(0, |flags| flags.bits()) + b[0] = self.bits(); } } -impl FixedSizeEncoding for Option<()> { +impl FixedSizeEncoding for bool { type ByteArray = [u8; 1]; #[inline] fn from_bytes(b: &[u8; 1]) -> Self { - (b[0] != 0).then(|| ()) + b[0] != 0 } #[inline] fn write_to_bytes(self, b: &mut [u8; 1]) { - b[0] = self.is_some() as u8 + b[0] = self as u8 } } @@ -273,44 +274,38 @@ impl<T> FixedSizeEncoding for Option<LazyArray<T>> { } /// Helper for constructing a table's serialization (also see `Table`). -pub(super) struct TableBuilder<I: Idx, T> -where - Option<T>: FixedSizeEncoding, -{ - blocks: IndexVec<I, <Option<T> as FixedSizeEncoding>::ByteArray>, +pub(super) struct TableBuilder<I: Idx, T: FixedSizeEncoding> { + blocks: IndexVec<I, T::ByteArray>, _marker: PhantomData<T>, } -impl<I: Idx, T> Default for TableBuilder<I, T> -where - Option<T>: FixedSizeEncoding, -{ +impl<I: Idx, T: FixedSizeEncoding> Default for TableBuilder<I, T> { fn default() -> Self { TableBuilder { blocks: Default::default(), _marker: PhantomData } } } -impl<I: Idx, T> TableBuilder<I, T> +impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>> where - Option<T>: FixedSizeEncoding, + Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, { - pub(crate) fn set<const N: usize>(&mut self, i: I, value: T) - where - Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(crate) fn set(&mut self, i: I, value: T) { + self.set_nullable(i, Some(value)) + } +} + +impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> { + pub(crate) fn set_nullable(&mut self, i: I, value: T) { // FIXME(eddyb) investigate more compact encodings for sparse tables. // On the PR @michaelwoerister mentioned: // > Space requirements could perhaps be optimized by using the HAMT `popcnt` // > trick (i.e. divide things into buckets of 32 or 64 items and then // > store bit-masks of which item in each bucket is actually serialized). self.blocks.ensure_contains_elem(i, || [0; N]); - Some(value).write_to_bytes(&mut self.blocks[i]); + value.write_to_bytes(&mut self.blocks[i]); } - pub(crate) fn encode<const N: usize>(&self, buf: &mut FileEncoder) -> LazyTable<I, T> - where - Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> { let pos = buf.position(); for block in &self.blocks { buf.emit_raw_bytes(block); @@ -323,34 +318,27 @@ where } } -impl<I: Idx, T: ParameterizedOverTcx> LazyTable<I, T> +impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]> + ParameterizedOverTcx> + LazyTable<I, T> where - Option<T>: FixedSizeEncoding, + for<'tcx> T::Value<'tcx>: FixedSizeEncoding<ByteArray = [u8; N]>, { /// Given the metadata, extract out the value at a particular index (if any). #[inline(never)] - pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>, const N: usize>( - &self, - metadata: M, - i: I, - ) -> Option<T::Value<'tcx>> - where - Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> { debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size); let start = self.position.get(); let bytes = &metadata.blob()[start..start + self.encoded_size]; let (bytes, []) = bytes.as_chunks::<N>() else { panic!() }; - let bytes = bytes.get(i.index())?; - FixedSizeEncoding::from_bytes(bytes) + match bytes.get(i.index()) { + Some(bytes) => FixedSizeEncoding::from_bytes(bytes), + None => FixedSizeEncoding::from_bytes(&[0; N]), + } } /// Size of the table in entries, including possible gaps. - pub(super) fn size<const N: usize>(&self) -> usize - where - for<'tcx> Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(super) fn size(&self) -> usize { self.encoded_size / N } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f816d614500..72f4f6e649b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -105,7 +105,7 @@ macro_rules! arena_types { // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>, - [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>, + [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::ItemLocalId>, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 9e63c2bd221..5bd6b070442 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -18,24 +18,30 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; #[inline] -pub fn associated_body(node: Node<'_>) -> Option<BodyId> { +pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { match node { Node::Item(Item { + owner_id, kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), .. }) | Node::TraitItem(TraitItem { + owner_id, kind: TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) | Node::ImplItem(ImplItem { + owner_id, kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), .. - }) - | Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body), + }) => Some((owner_id.def_id, *body)), + + Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { + Some((*def_id, *body)) + } - Node::AnonConst(constant) => Some(constant.body), + Node::AnonConst(constant) => Some((constant.def_id, constant.body)), _ => None, } @@ -43,7 +49,7 @@ pub fn associated_body(node: Node<'_>) -> Option<BodyId> { fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool { match associated_body(node) { - Some(b) => b.hir_id == hir_id, + Some((_, b)) => b.hir_id == hir_id, None => false, } } @@ -154,10 +160,6 @@ impl<'hir> Map<'hir> { self.tcx.definitions_untracked().def_key(def_id) } - pub fn def_path_from_hir_id(self, id: HirId) -> Option<DefPath> { - self.opt_local_def_id(id).map(|def_id| self.def_path(def_id)) - } - pub fn def_path(self, def_id: LocalDefId) -> DefPath { // Accessing the DefPath is ok, since it is part of DefPathHash. self.tcx.definitions_untracked().def_path(def_id) @@ -170,32 +172,6 @@ impl<'hir> Map<'hir> { } #[inline] - #[track_caller] - pub fn local_def_id(self, hir_id: HirId) -> LocalDefId { - self.opt_local_def_id(hir_id).unwrap_or_else(|| { - bug!( - "local_def_id: no entry for `{:?}`, which has a map of `{:?}`", - hir_id, - self.find(hir_id) - ) - }) - } - - #[inline] - pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> { - if hir_id.local_id == ItemLocalId::new(0) { - Some(hir_id.owner.def_id) - } else { - self.tcx - .hir_owner_nodes(hir_id.owner) - .as_owner()? - .local_id_to_def_id - .get(&hir_id.local_id) - .copied() - } - } - - #[inline] pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId { self.tcx.local_def_id_to_hir_id(def_id) } @@ -410,8 +386,8 @@ impl<'hir> Map<'hir> { #[track_caller] pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { for (_, node) in self.parent_iter(hir_id) { - if let Some(body) = associated_body(node) { - return self.body_owner_def_id(body); + if let Some((def_id, _)) = associated_body(node) { + return def_id; } } @@ -427,14 +403,17 @@ impl<'hir> Map<'hir> { parent } - pub fn body_owner_def_id(self, id: BodyId) -> LocalDefId { - self.local_def_id(self.body_owner(id)) + pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { + let parent = self.parent_id(hir_id); + associated_body(self.get(parent)).unwrap().0 } /// Given a `LocalDefId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> { - self.find_by_def_id(id).and_then(associated_body) + let node = self.find_by_def_id(id)?; + let (_, body_id) = associated_body(node)?; + Some(body_id) } /// Given a body owner's id, returns the `BodyId` associated with it. diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 43583b5723e..6e130bbf7d8 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -25,10 +25,8 @@ use crate::infer::MemberConstraint; use crate::mir::ConstraintCategory; use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; -use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use smallvec::SmallVec; -use std::iter; use std::ops::Index; /// A "canonicalized" type `V` is one where all free inference @@ -62,23 +60,23 @@ impl<'tcx> ty::TypeFoldable<'tcx> for CanonicalVarInfos<'tcx> { /// vectors with the original values that were replaced by canonical /// variables. You will need to supply it later to instantiate the /// canonicalized query response. -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>, + pub var_values: ty::SubstsRef<'tcx>, } impl CanonicalVarValues<'_> { pub fn is_identity(&self) -> bool { - self.var_values.iter_enumerated().all(|(bv, arg)| match arg.unpack() { + self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { ty::GenericArgKind::Lifetime(r) => { - matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var == bv) + matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv) } ty::GenericArgKind::Type(ty) => { - matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var == bv) + matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) } ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc == bv) + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) } }) } @@ -339,57 +337,57 @@ TrivialTypeTraversalAndLiftImpls! { } impl<'tcx> CanonicalVarValues<'tcx> { + // Given a list of canonical variables, construct a set of values which are + // the identity response. + pub fn make_identity( + tcx: TyCtxt<'tcx>, + infos: CanonicalVarInfos<'tcx>, + ) -> CanonicalVarValues<'tcx> { + CanonicalVarValues { + var_values: tcx.mk_substs(infos.iter().enumerate().map( + |(i, info)| -> ty::GenericArg<'tcx> { + 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(), + } + }, + )), + } + } + /// Creates dummy var values which should not be used in a /// canonical response. pub fn dummy() -> CanonicalVarValues<'tcx> { - CanonicalVarValues { var_values: Default::default() } + CanonicalVarValues { var_values: ty::List::empty() } } #[inline] pub fn len(&self) -> usize { self.var_values.len() } - - /// Makes an identity substitution from this one: each bound var - /// is matched to the same bound var, preserving the original kinds. - /// For example, if we have: - /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]` - /// we'll return a substitution `subst` with: - /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`. - pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self { - use crate::ty::subst::GenericArgKind; - - CanonicalVarValues { - var_values: iter::zip(&self.var_values, 0..) - .map(|(kind, i)| match kind.unpack() { - GenericArgKind::Type(..) => { - tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() - } - GenericArgKind::Lifetime(..) => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(i), - kind: ty::BrAnon(i, None), - }; - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() - } - GenericArgKind::Const(ct) => tcx - .mk_const( - ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), - ct.ty(), - ) - .into(), - }) - .collect(), - } - } } impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { type Item = GenericArg<'tcx>; - type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>; + type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>; fn into_iter(self) -> Self::IntoIter { - self.var_values.iter().cloned() + self.var_values.iter() } } @@ -397,6 +395,6 @@ impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> { type Output = GenericArg<'tcx>; fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { - &self.var_values[value] + &self.var_values[value.as_usize()] } } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 7e4063c2ffd..95148de2518 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -43,6 +43,7 @@ #![feature(min_specialization)] #![feature(trusted_len)] #![feature(type_alias_impl_trait)] +#![feature(strict_provenance)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index b3354e6e9d2..b93871769b7 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -41,7 +41,6 @@ impl<'tcx> BasicBlocks<'tcx> { *self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self)) } - #[inline] pub fn dominators(&self) -> Dominators<BasicBlock> { dominators(&self) } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 5f425a28768..b0975616b61 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -110,7 +110,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; -use rustc_target::abi::Endian; +use rustc_target::abi::{AddressSpace, Endian, HasDataLayout}; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -438,6 +438,17 @@ impl<'tcx> GlobalAlloc<'tcx> { _ => bug!("expected vtable, got {:?}", self), } } + + /// The address space that this `GlobalAlloc` should be placed in. + #[inline] + pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { + match self { + GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, + GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { + AddressSpace::DATA + } + } + } } pub(crate) struct AllocMap<'tcx> { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d833286dc33..552af589bec 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -902,6 +902,8 @@ pub enum LocalInfo<'tcx> { AggregateTemp, /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, + /// A temporary created for borrow checking. + FakeBorrow, } impl<'tcx> LocalDecl<'tcx> { @@ -1461,6 +1463,7 @@ impl Debug for Statement<'_> { } Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind), Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), + ConstEvalCounter => write!(fmt, "ConstEvalCounter"), Nop => write!(fmt, "nop"), } } @@ -2504,7 +2507,7 @@ impl<'tcx> ConstantKind<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) { - if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) { + if let Some(parent_did) = parent_hir_id.as_owner() { InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) } else { tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter()) @@ -3046,7 +3049,7 @@ impl Location { if self.block == other.block { self.statement_index <= other.statement_index } else { - dominators.is_dominated_by(other.block, self.block) + dominators.dominates(self.block, other.block) } } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1e8d5f7eae8..7a05ee2ff37 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -318,16 +318,19 @@ impl<'tcx> CodegenUnit<'tcx> { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) { + pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { // Estimate the size of a codegen unit as (approximately) the number of MIR // statements it corresponds to. self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); } #[inline] + /// Should only be called if [`create_size_estimate`] has previously been called. + /// + /// [`create_size_estimate`]: Self::create_size_estimate pub fn size_estimate(&self) -> usize { - // Should only be called if `estimate_size` has previously been called. - self.size_estimate.expect("estimate_size must be called before getting a size_estimate") + self.size_estimate + .expect("create_size_estimate must be called before getting a size_estimate") } pub fn modify_size_estimate(&mut self, delta: usize) { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a8a4532223c..6155f2bb56c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -135,11 +135,20 @@ rustc_index::newtype_index! { pub struct GeneratorSavedLocal {} } +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub struct GeneratorSavedTy<'tcx> { + pub ty: Ty<'tcx>, + /// Source info corresponding to the local in the original MIR body. + pub source_info: SourceInfo, + /// Whether the local should be ignored for trait bound computations. + pub ignore_for_traits: bool, +} + /// The layout of generator state. #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. - pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>, + pub field_tys: IndexVec<GeneratorSavedLocal, GeneratorSavedTy<'tcx>>, /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 887ee571575..1610ae1ce14 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -250,6 +250,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { AscribeUserType(..) => "AscribeUserType", Coverage(..) => "Coverage", Intrinsic(..) => "Intrinsic", + ConstEvalCounter => "ConstEvalCounter", Nop => "Nop", } } @@ -670,7 +671,7 @@ fn fn_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { fn hir_body(tcx: TyCtxt<'_>, def_id: DefId) -> Option<&rustc_hir::Body<'_>> { let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id)) + hir::map::associated_body(hir_node).map(|(_, fn_body_id)| tcx.hir().body(fn_body_id)) } fn escape_html(s: &str) -> String { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 52c2b10cbbe..549bc65d6d7 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -355,6 +355,12 @@ pub enum StatementKind<'tcx> { /// This avoids adding a new block and a terminator for simple intrinsics. Intrinsic(Box<NonDivergingIntrinsic<'tcx>>), + /// Instructs the const eval interpreter to increment a counter; this counter is used to track + /// how many steps the interpreter has taken. It is used to prevent the user from writing const + /// code that runs for too long or infinitely. Other than in the const eval interpreter, this + /// is a no-op. + ConstEvalCounter, + /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 1a264d2d5af..3ddac5e11fb 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -427,6 +427,7 @@ macro_rules! make_mir_visitor { } } } + StatementKind::ConstEvalCounter => {} StatementKind::Nop => {} } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7db86c8d0d4..4cebe416354 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -183,6 +183,15 @@ rustc_queries! { separate_provide_extern } + query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet<u32> + { + arena_cache + desc { |tcx| + "determining what parameters of `{}` can participate in unsizing", + tcx.def_path_str(key), + } + } + query analysis(key: ()) -> Result<(), ErrorGuaranteed> { eval_always desc { "running analysis passes on this crate" } @@ -361,6 +370,13 @@ rustc_queries! { desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) } } + /// Create a list-like THIR representation for debugging. + query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String { + no_hash + arena_cache + desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) } + } + /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. @@ -471,6 +487,17 @@ rustc_queries! { } } + query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> { + arena_cache + desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + + query check_generator_obligations(key: LocalDefId) { + desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key.to_def_id()) } + } + /// MIR after our optimization passes have run. This is MIR that is ready /// for codegen. This is also the only query that can fetch non-local MIR, at present. query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { @@ -796,15 +823,6 @@ rustc_queries! { } } - /// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error. - /// - /// Unsafety checking is executed for each method separately, but we only want - /// to emit this error once per derive. As there are some impls with multiple - /// methods, we use a query for deduplication. - query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } - } - /// Returns the types assumed to be well formed while "inside" of the given item. /// /// Note that we've liberated the late bound regions of function signatures, so @@ -814,7 +832,7 @@ rustc_queries! { } /// Computes the signature of the function. - query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { + query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -1263,6 +1281,9 @@ rustc_queries! { query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } } + query check_is_object_safe(trait_id: DefId) -> bool { + desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) } + } /// Gets the ParameterEnvironment for a given item; this environment /// will be in "user-facing" mode, meaning that it is suitable for @@ -1629,7 +1650,7 @@ rustc_queries! { Option<&'tcx FxHashMap<ItemLocalId, Region>> { desc { "looking up a named region" } } - query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> { + query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> { desc { "testing if a region is late bound" } } /// For a given item's generic parameter, gets the default lifetimes to be used @@ -1863,9 +1884,10 @@ 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> { + query output_filenames(_: ()) -> Arc<OutputFilenames> { feedable desc { "getting output filenames" } + arena_cache } /// Do not call this query directly: invoke `normalize` instead. @@ -2116,12 +2138,12 @@ rustc_queries! { separate_provide_extern } - query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool { - desc { "checking to see if `{}` permits being left uninit", key.ty } + query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool { + desc { "checking to see if `{}` permits being left uninit", key.value.ty } } - query permits_zero_init(key: TyAndLayout<'tcx>) -> bool { - desc { "checking to see if `{}` permits being left zeroed", key.ty } + query permits_zero_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool { + desc { "checking to see if `{}` permits being left zeroed", key.value.ty } } query compare_impl_const( diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 5f320708c84..6f2dac46753 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -29,6 +29,7 @@ use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; +pub mod print; pub mod visit; macro_rules! thir_with_elements { diff --git a/compiler/rustc_middle/src/thir/print.rs b/compiler/rustc_middle/src/thir/print.rs new file mode 100644 index 00000000000..60b903e9906 --- /dev/null +++ b/compiler/rustc_middle/src/thir/print.rs @@ -0,0 +1,881 @@ +use crate::thir::*; +use crate::ty::{self, TyCtxt}; + +use std::fmt::{self, Write}; + +impl<'tcx> TyCtxt<'tcx> { + pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String { + let mut printer = ThirPrinter::new(thir); + printer.print(); + printer.into_buffer() + } +} + +struct ThirPrinter<'a, 'tcx> { + thir: &'a Thir<'tcx>, + fmt: String, +} + +const INDENT: &str = " "; + +macro_rules! print_indented { + ($writer:ident, $s:expr, $indent_lvl:expr) => { + let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat(); + writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter"); + }; +} + +impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.fmt.push_str(s); + Ok(()) + } +} + +impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { + fn new(thir: &'a Thir<'tcx>) -> Self { + Self { thir, fmt: String::new() } + } + + fn print(&mut self) { + print_indented!(self, "params: [", 0); + for param in self.thir.params.iter() { + self.print_param(param, 1); + } + print_indented!(self, "]", 0); + + print_indented!(self, "body:", 0); + let expr = ExprId::from_usize(self.thir.exprs.len() - 1); + self.print_expr(expr, 1); + } + + fn into_buffer(self) -> String { + self.fmt + } + + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { + let Param { pat, ty, ty_span, self_kind, hir_id } = param; + + print_indented!(self, "Param {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1); + print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1); + + if let Some(pat) = pat { + print_indented!(self, "param: Some( ", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "param: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) { + let Block { + targeted_by_break, + opt_destruction_scope, + span, + region_scope, + stmts, + expr, + safety_mode, + } = &self.thir.blocks[block_id]; + + print_indented!(self, "Block {", depth_lvl); + print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1); + + if stmts.len() > 0 { + print_indented!(self, "stmts: [", depth_lvl + 1); + for stmt in stmts.iter() { + self.print_stmt(*stmt, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "stmts: []", depth_lvl + 1); + } + + if let Some(expr_id) = expr { + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + } else { + print_indented!(self, "expr: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) { + let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id]; + + print_indented!(self, "Stmt {", depth_lvl); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + + match kind { + StmtKind::Expr { scope, expr } => { + print_indented!(self, "kind: Expr {", depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2); + print_indented!(self, "expr:", depth_lvl + 2); + self.print_expr(*expr, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + StmtKind::Let { + remainder_scope, + init_scope, + pattern, + initializer, + else_block, + lint_level, + } => { + print_indented!(self, "kind: Let {", depth_lvl + 1); + print_indented!( + self, + format!("remainder_scope: {:?}", remainder_scope), + depth_lvl + 2 + ); + print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2); + + print_indented!(self, "pattern: ", depth_lvl + 2); + self.print_pat(pattern, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + + if let Some(init) = initializer { + print_indented!(self, "initializer: Some(", depth_lvl + 2); + self.print_expr(*init, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "initializer: None", depth_lvl + 2); + } + + if let Some(else_block) = else_block { + print_indented!(self, "else_block: Some(", depth_lvl + 2); + self.print_block(*else_block, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "else_block: None", depth_lvl + 2); + } + + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) { + let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr]; + print_indented!(self, "Expr {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "kind: ", depth_lvl + 1); + self.print_expr_kind(kind, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + + fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) { + use rustc_middle::thir::ExprKind::*; + + match expr_kind { + Scope { region_scope, value, lint_level } => { + print_indented!(self, "Scope {", depth_lvl); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Box { value } => { + print_indented!(self, "Box {", depth_lvl); + self.print_expr(*value, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + If { if_then_scope, cond, then, else_opt } => { + print_indented!(self, "If {", depth_lvl); + print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1); + print_indented!(self, "cond:", depth_lvl + 1); + self.print_expr(*cond, depth_lvl + 2); + print_indented!(self, "then:", depth_lvl + 1); + self.print_expr(*then, depth_lvl + 2); + + if let Some(else_expr) = else_opt { + print_indented!(self, "else:", depth_lvl + 1); + self.print_expr(*else_expr, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + Call { fun, args, ty, from_hir_call, fn_span } => { + print_indented!(self, "Call {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1); + print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1); + print_indented!(self, "fun:", depth_lvl + 1); + self.print_expr(*fun, depth_lvl + 2); + + if args.len() > 0 { + print_indented!(self, "args: [", depth_lvl + 1); + for arg in args.iter() { + self.print_expr(*arg, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "args: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + Deref { arg } => { + print_indented!(self, "Deref {", depth_lvl); + self.print_expr(*arg, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Binary { op, lhs, rhs } => { + print_indented!(self, "Binary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + LogicalOp { op, lhs, rhs } => { + print_indented!(self, "LogicalOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Unary { op, arg } => { + print_indented!(self, "Unary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Cast { source } => { + print_indented!(self, "Cast {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Use { source } => { + print_indented!(self, "Use {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + NeverToAny { source } => { + print_indented!(self, "NeverToAny {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Pointer { cast, source } => { + print_indented!(self, "Pointer {", depth_lvl); + print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Loop { body } => { + print_indented!(self, "Loop (", depth_lvl); + print_indented!(self, "body:", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + Let { expr, pat } => { + print_indented!(self, "Let {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Match { scrutinee, arms } => { + print_indented!(self, "Match {", depth_lvl); + print_indented!(self, "scrutinee:", depth_lvl + 1); + self.print_expr(*scrutinee, depth_lvl + 2); + + print_indented!(self, "arms: [", depth_lvl + 1); + for arm_id in arms.iter() { + self.print_arm(*arm_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Block { block } => self.print_block(*block, depth_lvl), + Assign { lhs, rhs } => { + print_indented!(self, "Assign {", depth_lvl); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + AssignOp { op, lhs, rhs } => { + print_indented!(self, "AssignOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Field { lhs, variant_index, name } => { + print_indented!(self, "Field {", depth_lvl); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Index { lhs, index } => { + print_indented!(self, "Index {", depth_lvl); + print_indented!(self, format!("index: {:?}", index), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + VarRef { id } => { + print_indented!(self, "VarRef {", depth_lvl); + print_indented!(self, format!("id: {:?}", id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + UpvarRef { closure_def_id, var_hir_id } => { + print_indented!(self, "UpvarRef {", depth_lvl); + print_indented!( + self, + format!("closure_def_id: {:?}", closure_def_id), + depth_lvl + 1 + ); + print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Borrow { borrow_kind, arg } => { + print_indented!(self, "Borrow (", depth_lvl); + print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + AddressOf { mutability, arg } => { + print_indented!(self, "AddressOf {", depth_lvl); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Break { label, value } => { + print_indented!(self, "Break (", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + + if let Some(value) = value { + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, ")", depth_lvl); + } + Continue { label } => { + print_indented!(self, "Continue {", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Return { value } => { + print_indented!(self, "Return {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + + if let Some(value) = value { + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + ConstBlock { did, substs } => { + print_indented!(self, "ConstBlock {", depth_lvl); + print_indented!(self, format!("did: {:?}", did), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Repeat { value, count } => { + print_indented!(self, "Repeat {", depth_lvl); + print_indented!(self, format!("count: {:?}", count), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Array { fields } => { + print_indented!(self, "Array {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Tuple { fields } => { + print_indented!(self, "Tuple {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Adt(adt_expr) => { + print_indented!(self, "Adt {", depth_lvl); + self.print_adt_expr(&**adt_expr, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + PlaceTypeAscription { source, user_ty } => { + print_indented!(self, "PlaceTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ValueTypeAscription { source, user_ty } => { + print_indented!(self, "ValueTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Closure(closure_expr) => { + print_indented!(self, "Closure {", depth_lvl); + print_indented!(self, "closure_expr:", depth_lvl + 1); + self.print_closure_expr(&**closure_expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Literal { lit, neg } => { + print_indented!( + self, + format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg), + depth_lvl + ); + } + NonHirLiteral { lit, user_ty } => { + print_indented!(self, "NonHirLiteral {", depth_lvl); + print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ZstLiteral { user_ty } => { + print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl); + } + NamedConst { def_id, substs, user_ty } => { + print_indented!(self, "NamedConst {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ConstParam { param, def_id } => { + print_indented!(self, "ConstParam {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("param: {:?}", param), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + StaticRef { alloc_id, ty, def_id } => { + print_indented!(self, "StaticRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + InlineAsm(expr) => { + print_indented!(self, "InlineAsm {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_inline_asm_expr(&**expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ThreadLocalRef(def_id) => { + print_indented!(self, "ThreadLocalRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Yield { value } => { + print_indented!(self, "Yield {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + } + } + + fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) { + print_indented!(self, "adt_def:", depth_lvl); + self.print_adt_def(adt_expr.adt_def, depth_lvl + 1); + print_indented!( + self, + format!("variant_index: {:?}", adt_expr.variant_index), + depth_lvl + 1 + ); + print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1); + + for (i, field_expr) in adt_expr.fields.iter().enumerate() { + print_indented!(self, format!("field {}:", i), depth_lvl + 1); + self.print_expr(field_expr.expr, depth_lvl + 2); + } + + if let Some(ref base) = adt_expr.base { + print_indented!(self, "base:", depth_lvl + 1); + self.print_fru_info(base, depth_lvl + 2); + } else { + print_indented!(self, "base: None", depth_lvl + 1); + } + } + + fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) { + print_indented!(self, "AdtDef {", depth_lvl); + print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1); + print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1); + print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1); + print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1); + } + + fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) { + print_indented!(self, "FruInfo {", depth_lvl); + print_indented!(self, "base: ", depth_lvl + 1); + self.print_expr(fru_info.base, depth_lvl + 2); + print_indented!(self, "field_types: [", depth_lvl + 1); + for ty in fru_info.field_types.iter() { + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + } + print_indented!(self, "}", depth_lvl); + } + + fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) { + print_indented!(self, "Arm {", depth_lvl); + + let arm = &self.thir.arms[arm_id]; + let Arm { pattern, guard, body, lint_level, scope, span } = arm; + + print_indented!(self, "pattern: ", depth_lvl + 1); + self.print_pat(pattern, depth_lvl + 2); + + if let Some(guard) = guard { + print_indented!(self, "guard: ", depth_lvl + 1); + self.print_guard(guard, depth_lvl + 2); + } else { + print_indented!(self, "guard: None", depth_lvl + 1); + } + + print_indented!(self, "body: ", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) { + let Pat { ty, span, kind } = &**pat; + + print_indented!(self, "Pat: {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_kind(kind, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { + print_indented!(self, "kind: PatKind {", depth_lvl); + + match pat_kind { + PatKind::Wild => { + print_indented!(self, "Wild", depth_lvl + 1); + } + PatKind::AscribeUserType { ascription, subpattern } => { + print_indented!(self, "AscribeUserType: {", depth_lvl + 1); + print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => { + print_indented!(self, "Binding {", depth_lvl + 1); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); + print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); + print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2); + + if let Some(subpattern) = subpattern { + print_indented!(self, "subpattern: Some( ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "subpattern: None", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Variant { adt_def, substs, variant_index, subpatterns } => { + print_indented!(self, "Variant {", depth_lvl + 1); + print_indented!(self, "adt_def: ", depth_lvl + 2); + self.print_adt_def(*adt_def, depth_lvl + 3); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2); + + if subpatterns.len() > 0 { + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + } else { + print_indented!(self, "subpatterns: []", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Leaf { subpatterns } => { + print_indented!(self, "Leaf { ", depth_lvl + 1); + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Deref { subpattern } => { + print_indented!(self, "Deref { ", depth_lvl + 1); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Constant { value } => { + print_indented!(self, "Constant {", depth_lvl + 1); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Range(pat_range) => { + print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); + } + PatKind::Slice { prefix, slice, suffix } => { + print_indented!(self, "Slice {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Array { prefix, slice, suffix } => { + print_indented!(self, "Array {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Or { pats } => { + print_indented!(self, "Or {", depth_lvl + 1); + print_indented!(self, "pats: [", depth_lvl + 2); + for pat in pats.iter() { + self.print_pat(pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) { + print_indented!(self, "Guard {", depth_lvl); + + match guard { + Guard::If(expr_id) => { + print_indented!(self, "If (", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + Guard::IfLet(pat, expr_id) => { + print_indented!(self, "IfLet (", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) { + let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr; + + print_indented!(self, "ClosureExpr {", depth_lvl); + print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + + if upvars.len() > 0 { + print_indented!(self, "upvars: [", depth_lvl + 1); + for upvar in upvars.iter() { + self.print_expr(*upvar, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "upvars: []", depth_lvl + 1); + } + + print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1); + + if fake_reads.len() > 0 { + print_indented!(self, "fake_reads: [", depth_lvl + 1); + for (fake_read_expr, cause, hir_id) in fake_reads.iter() { + print_indented!(self, "(", depth_lvl + 2); + self.print_expr(*fake_read_expr, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3); + print_indented!(self, "),", depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "fake_reads: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { + let InlineAsmExpr { template, operands, options, line_spans } = expr; + + print_indented!(self, "InlineAsmExpr {", depth_lvl); + + print_indented!(self, "template: [", depth_lvl + 1); + for template_piece in template.iter() { + print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, "operands: [", depth_lvl + 1); + for operand in operands.iter() { + self.print_inline_operand(operand, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, format!("options: {:?}", options), depth_lvl + 1); + print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1); + } + + fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) { + match operand { + InlineAsmOperand::In { reg, expr } => { + print_indented!(self, "InlineAsmOperand::In {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Out { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::Out {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + + if let Some(out) = expr { + print_indented!(self, "place: Some( ", depth_lvl + 1); + self.print_expr(*out, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "place: None", depth_lvl + 1); + } + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::InOut { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "in_expr: ", depth_lvl + 1); + self.print_expr(*in_expr, depth_lvl + 2); + + if let Some(out_expr) = out_expr { + print_indented!(self, "out_expr: Some( ", depth_lvl + 1); + self.print_expr(*out_expr, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "out_expr: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Const { value, span } => { + print_indented!(self, "InlineAsmOperand::Const {", depth_lvl); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymFn { value, span } => { + print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); + print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymStatic { def_id } => { + print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + } + } +} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d00b26a5a3d..cf3dce48064 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -18,7 +18,8 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; +use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use smallvec::SmallVec; @@ -36,7 +37,7 @@ pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner /// Depending on the stage of compilation, we want projection to be /// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] pub enum Reveal { /// At type-checking time, we refuse to project any associated /// type that is marked `default`. Non-`default` ("final") types @@ -89,7 +90,8 @@ pub enum Reveal { /// /// We do not want to intern this as there are a lot of obligation causes which /// only live for a short period of time. -#[derive(Clone, Debug, PartialEq, Eq, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -99,7 +101,7 @@ pub struct ObligationCause<'tcx> { /// (in particular, closures can add new assumptions). See the /// field `region_obligations` of the `FulfillmentContext` for more /// information. - pub body_id: hir::HirId, + pub body_id: LocalDefId, code: InternedObligationCauseCode<'tcx>, } @@ -120,13 +122,13 @@ impl<'tcx> ObligationCause<'tcx> { #[inline] pub fn new( span: Span, - body_id: hir::HirId, + body_id: LocalDefId, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { ObligationCause { span, body_id, code: code.into() } } - pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { + pub fn misc(span: Span, body_id: LocalDefId) -> ObligationCause<'tcx> { ObligationCause::new(span, body_id, MiscObligation) } @@ -137,7 +139,7 @@ impl<'tcx> ObligationCause<'tcx> { #[inline(always)] pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> { - ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() } + ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() } } pub fn span(&self) -> Span { @@ -196,14 +198,16 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct UnifyReceiverContext<'tcx> { pub assoc_item: ty::AssocItem, pub param_env: ty::ParamEnv<'tcx>, pub substs: SubstsRef<'tcx>, } -#[derive(Clone, PartialEq, Eq, Hash, Lift, Default)] +#[derive(Clone, PartialEq, Eq, Hash, Lift, Default, HashStable)] +#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] pub struct InternedObligationCauseCode<'tcx> { /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of /// the time). `Some` otherwise. @@ -238,7 +242,8 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. MiscObligation, @@ -446,7 +451,8 @@ pub enum ObligationCauseCode<'tcx> { /// This information is used to obtain an `hir::Ty`, which /// we can walk in order to obtain precise spans for any /// 'nested' types (e.g. `Foo` in `Option<Foo>`). -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] +#[derive(TypeVisitable, TypeFoldable)] pub enum WellFormedLoc { /// Use the type of the provided definition. Ty(LocalDefId), @@ -463,7 +469,8 @@ pub enum WellFormedLoc { }, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct ImplDerivedObligationCause<'tcx> { pub derived: DerivedObligationCause<'tcx>, pub impl_def_id: DefId, @@ -517,7 +524,8 @@ impl<'tcx> ty::Lift<'tcx> for StatementAsExpression { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct MatchExpressionArmCause<'tcx> { pub arm_block_id: Option<hir::HirId>, pub arm_ty: Ty<'tcx>, @@ -533,7 +541,7 @@ pub struct MatchExpressionArmCause<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(Lift, TypeFoldable, TypeVisitable)] +#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct IfExpressionCause<'tcx> { pub then_id: hir::HirId, pub else_id: hir::HirId, @@ -543,7 +551,8 @@ pub struct IfExpressionCause<'tcx> { pub opt_suggest_box_span: Option<Span>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct DerivedObligationCause<'tcx> { /// The trait predicate of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index d3d667f6840..099a7845118 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -188,7 +188,7 @@ impl<'tcx> AdtDef<'tcx> { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable, TyEncodable, TyDecodable)] pub enum AdtKind { Struct, Union, diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index bb7fba3ee71..71cecfb558f 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -79,7 +79,7 @@ impl AssocItem { // late-bound regions, and we don't want method signatures to show up // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound // regions just fine, showing `fn(&MyType)`. - tcx.fn_sig(self.def_id).skip_binder().to_string() + tcx.fn_sig(self.def_id).subst_identity().skip_binder().to_string() } ty::AssocKind::Type => format!("type {};", self.name), ty::AssocKind::Const => { @@ -130,7 +130,7 @@ impl std::fmt::Display for AssocKind { /// done only on items with the same name. #[derive(Debug, Clone, PartialEq, HashStable)] pub struct AssocItems<'tcx> { - pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>, + items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>, } impl<'tcx> AssocItems<'tcx> { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8cc8286c1db..b9a1e23879c 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -157,6 +157,14 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId { } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> { + fn encode(&self, e: &mut E) { + self.caller_bounds().encode(e); + self.reveal().encode(e); + self.constness().encode(e); + } +} + #[inline] fn decode_arena_allocable< 'tcx, @@ -280,8 +288,17 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::ParamEnv<'tcx> { + fn decode(d: &mut D) -> Self { + let caller_bounds = Decodable::decode(d); + let reveal = Decodable::decode(d); + let constness = Decodable::decode(d); + ty::ParamEnv::new(caller_bounds, reveal, constness) + } +} + macro_rules! impl_decodable_via_ref { - ($($t:ty),+) => { + ($($t:ty,)+) => { $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for $t { fn decode(decoder: &mut D) -> Self { RefDecodable::decode(decoder) @@ -373,6 +390,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> { + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + let predicates: Vec<_> = + (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)).collect(); + decoder.interner().intern_predicates(&predicates) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List<Ty<'tcx>>, @@ -382,7 +408,8 @@ impl_decodable_via_ref! { &'tcx mir::UnsafetyCheckResult, &'tcx mir::BorrowCheckResult<'tcx>, &'tcx mir::coverage::CodeRegion, - &'tcx ty::List<ty::BoundVariableKind> + &'tcx ty::List<ty::BoundVariableKind>, + &'tcx ty::List<ty::Predicate<'tcx>>, } #[macro_export] @@ -519,6 +546,8 @@ macro_rules! impl_binder_encode_decode { impl_binder_encode_decode! { &'tcx ty::List<Ty<'tcx>>, ty::FnSig<'tcx>, + ty::Predicate<'tcx>, + ty::TraitPredicate<'tcx>, ty::ExistentialPredicate<'tcx>, ty::TraitRef<'tcx>, Vec<ty::GeneratorInteriorTypeCause<'tcx>>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ce04d8d21f4..b63b9e754cf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2,6 +2,8 @@ #![allow(rustc::usage_of_ty_tykind)] +pub mod tls; + use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; @@ -75,6 +77,8 @@ use std::iter; use std::mem; use std::ops::{Bound, Deref}; +const TINY_CONST_EVAL_LIMIT: Limit = Limit(20); + pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self @@ -997,6 +1001,30 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } + /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type and associated alias span when type alias is used + pub fn return_type_impl_or_dyn_traits_with_type_alias( + self, + scope_def_id: LocalDefId, + ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span)> { + let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); + let mut v = TraitObjectVisitor(vec![], self.hir()); + // when the return type is a type alias + if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) + && let hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind + && let Some(local_id) = def_id.as_local() + && let Some(alias_ty) = self.hir().get_by_def_id(local_id).alias_ty() // it is type alias + && let Some(alias_generics) = self.hir().get_by_def_id(local_id).generics() + { + v.visit_ty(alias_ty); + if !v.0.is_empty() { + return Some((v.0, alias_generics.span)); + } + } + return None; + } + pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // `type_of()` will fail on these (#55796, #86483), so only allow `fn`s or closures. match self.hir().get_by_def_id(scope_def_id) { @@ -1078,7 +1106,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn const_eval_limit(self) -> Limit { - self.limits(()).const_eval_limit + if self.sess.opts.unstable_opts.tiny_const_eval_limit { + TINY_CONST_EVAL_LIMIT + } else { + self.limits(()).const_eval_limit + } } pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { @@ -1188,178 +1220,6 @@ CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint, } } -pub mod tls { - use super::{ptr_eq, GlobalCtxt, TyCtxt}; - - use crate::dep_graph::TaskDepsRef; - use crate::ty::query; - use rustc_data_structures::sync::{self, Lock}; - use rustc_errors::Diagnostic; - use std::mem; - use thin_vec::ThinVec; - - #[cfg(not(parallel_compiler))] - use std::cell::Cell; - - #[cfg(parallel_compiler)] - use rustc_rayon_core as rayon_core; - - /// This is the implicit state of rustc. It contains the current - /// `TyCtxt` and query. It is updated when creating a local interner or - /// executing a new query. Whenever there's a `TyCtxt` value available - /// you should also have access to an `ImplicitCtxt` through the functions - /// in this module. - #[derive(Clone)] - pub struct ImplicitCtxt<'a, 'tcx> { - /// The current `TyCtxt`. - pub tcx: TyCtxt<'tcx>, - - /// The current query job, if any. This is updated by `JobOwner::start` in - /// `ty::query::plumbing` when executing a query. - pub query: Option<query::QueryJobId>, - - /// Where to store diagnostics for the current query job, if any. - /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. - pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>, - - /// Used to prevent queries from calling too deeply. - pub query_depth: usize, - - /// The current dep graph task. This is used to add dependencies to queries - /// when executing them. - pub task_deps: TaskDepsRef<'a>, - } - - impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { - pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { - let tcx = TyCtxt { gcx }; - ImplicitCtxt { - tcx, - query: None, - diagnostics: None, - query_depth: 0, - task_deps: TaskDepsRef::Ignore, - } - } - } - - /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs - /// to `value` during the call to `f`. It is restored to its previous value after. - /// This is used to set the pointer to the new `ImplicitCtxt`. - #[cfg(parallel_compiler)] - #[inline] - fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R { - rayon_core::tlv::with(value, f) - } - - /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. - /// This is used to get the pointer to the current `ImplicitCtxt`. - #[cfg(parallel_compiler)] - #[inline] - pub fn get_tlv() -> usize { - rayon_core::tlv::get() - } - - #[cfg(not(parallel_compiler))] - thread_local! { - /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. - static TLV: Cell<usize> = const { Cell::new(0) }; - } - - /// Sets TLV to `value` during the call to `f`. - /// It is restored to its previous value after. - /// This is used to set the pointer to the new `ImplicitCtxt`. - #[cfg(not(parallel_compiler))] - #[inline] - fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R { - let old = get_tlv(); - let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old))); - TLV.with(|tlv| tlv.set(value)); - f() - } - - /// Gets the pointer to the current `ImplicitCtxt`. - #[cfg(not(parallel_compiler))] - #[inline] - fn get_tlv() -> usize { - TLV.with(|tlv| tlv.get()) - } - - /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. - #[inline] - pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R - where - F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, - { - set_tlv(context as *const _ as usize, || f(&context)) - } - - /// Allows access to the current `ImplicitCtxt` in a closure if one is available. - #[inline] - pub fn with_context_opt<F, R>(f: F) -> R - where - F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, - { - let context = get_tlv(); - if context == 0 { - f(None) - } else { - // We could get an `ImplicitCtxt` pointer from another thread. - // Ensure that `ImplicitCtxt` is `Sync`. - sync::assert_sync::<ImplicitCtxt<'_, '_>>(); - - unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) } - } - } - - /// Allows access to the current `ImplicitCtxt`. - /// Panics if there is no `ImplicitCtxt` available. - #[inline] - pub fn with_context<F, R>(f: F) -> R - where - F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, - { - with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) - } - - /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument - /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime - /// as the `TyCtxt` passed in. - /// This will panic if you pass it a `TyCtxt` which is different from the current - /// `ImplicitCtxt`'s `tcx` field. - #[inline] - pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R - where - F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R, - { - with_context(|context| unsafe { - assert!(ptr_eq(context.tcx.gcx, tcx.gcx)); - let context: &ImplicitCtxt<'_, '_> = mem::transmute(context); - f(context) - }) - } - - /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. - /// Panics if there is no `ImplicitCtxt` available. - #[inline] - pub fn with<F, R>(f: F) -> R - where - F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, - { - with_context(|context| f(context.tcx)) - } - - /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. - /// The closure is passed None if there is no `ImplicitCtxt` available. - #[inline] - pub fn with_opt<F, R>(f: F) -> R - where - F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R, - { - with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) - } -} - macro_rules! sty_debug_print { ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{ // Curious inner module to allow variant names to be used as @@ -1452,6 +1312,7 @@ impl<'tcx> TyCtxt<'tcx> { Placeholder, Generator, GeneratorWitness, + GeneratorWitnessMIR, Dynamic, Closure, Tuple, @@ -1962,6 +1823,11 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] + pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { + self.mk_ty(GeneratorWitnessMIR(id, substs)) + } + + #[inline] pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { self.mk_ty_infer(TyVar(v)) } @@ -2297,10 +2163,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner.def_id).map_or(false, |set| { - let def_id = self.hir().local_def_id(id); - set.contains(&def_id) - }) + self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id)) } pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> { @@ -2392,12 +2255,6 @@ pub struct DeducedParamAttrs { pub read_only: bool, } -// We are comparing types with different invariant lifetimes, so `ptr::eq` -// won't work for us. -fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { - t as *const () == u as *const () -} - pub fn provide(providers: &mut ty::query::Providers) { providers.module_reexports = |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]); diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs new file mode 100644 index 00000000000..71b025dc1be --- /dev/null +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -0,0 +1,187 @@ +use super::{GlobalCtxt, TyCtxt}; + +use crate::dep_graph::TaskDepsRef; +use crate::ty::query; +use rustc_data_structures::sync::{self, Lock}; +use rustc_errors::Diagnostic; +use std::mem; +use std::ptr; +use thin_vec::ThinVec; + +/// This is the implicit state of rustc. It contains the current +/// `TyCtxt` and query. It is updated when creating a local interner or +/// executing a new query. Whenever there's a `TyCtxt` value available +/// you should also have access to an `ImplicitCtxt` through the functions +/// in this module. +#[derive(Clone)] +pub struct ImplicitCtxt<'a, 'tcx> { + /// The current `TyCtxt`. + pub tcx: TyCtxt<'tcx>, + + /// The current query job, if any. This is updated by `JobOwner::start` in + /// `ty::query::plumbing` when executing a query. + pub query: Option<query::QueryJobId>, + + /// Where to store diagnostics for the current query job, if any. + /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. + pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>, + + /// Used to prevent queries from calling too deeply. + pub query_depth: usize, + + /// The current dep graph task. This is used to add dependencies to queries + /// when executing them. + pub task_deps: TaskDepsRef<'a>, +} + +impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { + pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { + let tcx = TyCtxt { gcx }; + ImplicitCtxt { + tcx, + query: None, + diagnostics: None, + query_depth: 0, + task_deps: TaskDepsRef::Ignore, + } + } +} + +#[cfg(parallel_compiler)] +mod tlv { + use rustc_rayon_core as rayon_core; + use std::ptr; + + /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. + /// This is used to get the pointer to the current `ImplicitCtxt`. + #[inline] + pub(super) fn get_tlv() -> *const () { + ptr::from_exposed_addr(rayon_core::tlv::get()) + } + + /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs + /// to `value` during the call to `f`. It is restored to its previous value after. + /// This is used to set the pointer to the new `ImplicitCtxt`. + #[inline] + pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R { + rayon_core::tlv::with(value.expose_addr(), f) + } +} + +#[cfg(not(parallel_compiler))] +mod tlv { + use std::cell::Cell; + use std::ptr; + + thread_local! { + /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. + static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) }; + } + + /// Gets the pointer to the current `ImplicitCtxt`. + #[inline] + pub(super) fn get_tlv() -> *const () { + TLV.with(|tlv| tlv.get()) + } + + /// Sets TLV to `value` during the call to `f`. + /// It is restored to its previous value after. + /// This is used to set the pointer to the new `ImplicitCtxt`. + #[inline] + pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R { + let old = get_tlv(); + let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old))); + TLV.with(|tlv| tlv.set(value)); + f() + } +} + +#[inline] +fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () { + context as *const _ as *const () +} + +#[inline] +unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> { + &*(context as *const ImplicitCtxt<'a, 'tcx>) +} + +/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. +#[inline] +pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R +where + F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, +{ + tlv::with_tlv(erase(context), || f(&context)) +} + +/// Allows access to the current `ImplicitCtxt` in a closure if one is available. +#[inline] +pub fn with_context_opt<F, R>(f: F) -> R +where + F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, +{ + let context = tlv::get_tlv(); + if context.is_null() { + f(None) + } else { + // We could get an `ImplicitCtxt` pointer from another thread. + // Ensure that `ImplicitCtxt` is `Sync`. + sync::assert_sync::<ImplicitCtxt<'_, '_>>(); + + unsafe { f(Some(downcast(context))) } + } +} + +/// Allows access to the current `ImplicitCtxt`. +/// Panics if there is no `ImplicitCtxt` available. +#[inline] +pub fn with_context<F, R>(f: F) -> R +where + F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, +{ + with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) +} + +/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument +/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime +/// as the `TyCtxt` passed in. +/// This will panic if you pass it a `TyCtxt` which is different from the current +/// `ImplicitCtxt`'s `tcx` field. +#[inline] +pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R +where + F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R, +{ + with_context(|context| { + // The two gcx have different invariant lifetimes, so we need to erase them for the comparison. + assert!(ptr::eq( + context.tcx.gcx as *const _ as *const (), + tcx.gcx as *const _ as *const () + )); + + let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) }; + + f(context) + }) +} + +/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. +/// Panics if there is no `ImplicitCtxt` available. +#[inline] +pub fn with<F, R>(f: F) -> R +where + F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, +{ + with_context(|context| f(context.tcx)) +} + +/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. +/// The closure is passed None if there is no `ImplicitCtxt` available. +#[inline] +pub fn with_opt<F, R>(f: F) -> R +where + F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R, +{ + with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) +} diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5d394f71f0d..d83fc95ac4e 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,24 +1,18 @@ -use crate::traits::{ObligationCause, ObligationCauseCode}; -use crate::ty::diagnostics::suggest_constraining_type_param; -use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer}; +use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter}; use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; -use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; -use rustc_errors::{pluralize, Diagnostic, MultiSpan}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::def_id::DefId; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::symbol::Symbol; use rustc_target::spec::abi; - use std::borrow::Cow; use std::collections::hash_map::DefaultHasher; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; +use std::hash::Hasher; use std::path::PathBuf; -use super::print::PrettyPrinter; - #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)] pub struct ExpectedFound<T> { pub expected: T, @@ -331,7 +325,8 @@ impl<'tcx> Ty<'tcx> { ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), - ty::GeneratorWitness(..) => "generator witness".into(), + ty::GeneratorWitness(..) | + ty::GeneratorWitnessMIR(..) => "generator witness".into(), ty::Tuple(..) => "tuple".into(), ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::IntVar(_)) => "integer".into(), @@ -379,7 +374,7 @@ impl<'tcx> Ty<'tcx> { ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), - ty::GeneratorWitness(..) => "generator witness".into(), + ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(), ty::Tuple(..) => "tuple".into(), ty::Placeholder(..) => "higher-ranked type".into(), ty::Bound(..) => "bound type variable".into(), @@ -391,620 +386,6 @@ impl<'tcx> Ty<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_type_err( - self, - diag: &mut Diagnostic, - err: TypeError<'tcx>, - cause: &ObligationCause<'tcx>, - sp: Span, - body_owner_def_id: DefId, - ) { - use self::TypeError::*; - debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); - match err { - ArgumentSorts(values, _) | Sorts(values) => { - match (values.expected.kind(), values.found.kind()) { - (ty::Closure(..), ty::Closure(..)) => { - diag.note("no two closures, even if identical, have the same type"); - diag.help("consider boxing your closure and/or using it as a trait object"); - } - (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => { - // Issue #63167 - diag.note("distinct uses of `impl Trait` result in different opaque types"); - } - (ty::Float(_), ty::Infer(ty::IntVar(_))) - if let Ok( - // Issue #53280 - snippet, - ) = self.sess.source_map().span_to_snippet(sp) => - { - if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { - diag.span_suggestion( - sp, - "use a float literal", - format!("{}.0", snippet), - MachineApplicable, - ); - } - } - (ty::Param(expected), ty::Param(found)) => { - let generics = self.generics_of(body_owner_def_id); - let e_span = self.def_span(generics.type_param(expected, self).def_id); - if !sp.contains(e_span) { - diag.span_label(e_span, "expected type parameter"); - } - let f_span = self.def_span(generics.type_param(found, self).def_id); - if !sp.contains(f_span) { - diag.span_label(f_span, "found type parameter"); - } - diag.note( - "a type parameter was expected, but a different one was found; \ - you might be missing a type parameter or trait bound", - ); - diag.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch10-02-traits.html\ - #traits-as-parameters", - ); - } - (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => { - diag.note("an associated type was expected, but a different one was found"); - } - (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) - if self.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder => - { - let generics = self.generics_of(body_owner_def_id); - let p_span = self.def_span(generics.type_param(p, self).def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "this type parameter"); - } - let hir = self.hir(); - let mut note = true; - if let Some(generics) = generics - .type_param(p, self) - .def_id - .as_local() - .map(|id| hir.local_def_id_to_hir_id(id)) - .and_then(|id| self.hir().find_parent(id)) - .as_ref() - .and_then(|node| node.generics()) - { - // Synthesize the associated type restriction `Add<Output = Expected>`. - // FIXME: extract this logic for use in other diagnostics. - let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self); - let path = - self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); - let item_name = self.item_name(proj.def_id); - let item_args = self.format_generic_args(assoc_substs); - - let path = if path.ends_with('>') { - format!( - "{}, {}{} = {}>", - &path[..path.len() - 1], - item_name, - item_args, - p - ) - } else { - format!("{}<{}{} = {}>", path, item_name, item_args, p) - }; - note = !suggest_constraining_type_param( - self, - generics, - diag, - &format!("{}", proj.self_ty()), - &path, - None, - ); - } - if note { - diag.note("you might be missing a type parameter or trait bound"); - } - } - (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..)) - | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => { - let generics = self.generics_of(body_owner_def_id); - let p_span = self.def_span(generics.type_param(p, self).def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "this type parameter"); - } - diag.help("type parameters must be constrained to match other types"); - if self.sess.teach(&diag.get_code().unwrap()) { - diag.help( - "given a type parameter `T` and a method `foo`: -``` -trait Trait<T> { fn foo(&self) -> T; } -``` -the only ways to implement method `foo` are: -- constrain `T` with an explicit type: -``` -impl Trait<String> for X { - fn foo(&self) -> String { String::new() } -} -``` -- add a trait bound to `T` and call a method on that trait that returns `Self`: -``` -impl<T: std::default::Default> Trait<T> for X { - fn foo(&self) -> T { <T as std::default::Default>::default() } -} -``` -- change `foo` to return an argument of type `T`: -``` -impl<T> Trait<T> for X { - fn foo(&self, x: T) -> T { x } -} -```", - ); - } - diag.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch10-02-traits.html\ - #traits-as-parameters", - ); - } - (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => { - let generics = self.generics_of(body_owner_def_id); - let p_span = self.def_span(generics.type_param(p, self).def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "this type parameter"); - } - diag.help(&format!( - "every closure has a distinct type and so could not always match the \ - caller-chosen type of parameter `{}`", - p - )); - } - (ty::Param(p), _) | (_, ty::Param(p)) => { - let generics = self.generics_of(body_owner_def_id); - let p_span = self.def_span(generics.type_param(p, self).def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "this type parameter"); - } - } - (ty::Alias(ty::Projection, proj_ty), _) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { - self.expected_projection( - diag, - proj_ty, - values, - body_owner_def_id, - cause.code(), - ); - } - (_, ty::Alias(ty::Projection, proj_ty)) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => { - let msg = format!( - "consider constraining the associated type `{}` to `{}`", - values.found, values.expected, - ); - if !(self.suggest_constraining_opaque_associated_type( - diag, - &msg, - proj_ty, - values.expected, - ) || self.suggest_constraint( - diag, - &msg, - body_owner_def_id, - proj_ty, - values.expected, - )) { - diag.help(&msg); - diag.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", - ); - } - } - _ => {} - } - debug!( - "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", - values.expected, - values.expected.kind(), - values.found, - values.found.kind(), - ); - } - CyclicTy(ty) => { - // Watch out for various cases of cyclic types and try to explain. - if ty.is_closure() || ty.is_generator() { - diag.note( - "closures cannot capture themselves or take themselves as argument;\n\ - this error may be the result of a recent compiler bug-fix,\n\ - see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\ - for more information", - ); - } - } - TargetFeatureCast(def_id) => { - let target_spans = - self.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); - diag.note( - "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" - ); - diag.span_labels(target_spans, "`#[target_feature]` added here"); - } - _ => {} - } - } - - fn suggest_constraint( - self, - diag: &mut Diagnostic, - msg: &str, - body_owner_def_id: DefId, - proj_ty: &ty::AliasTy<'tcx>, - ty: Ty<'tcx>, - ) -> bool { - let assoc = self.associated_item(proj_ty.def_id); - let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); - if let Some(item) = self.hir().get_if_local(body_owner_def_id) { - if let Some(hir_generics) = item.generics() { - // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. - // This will also work for `impl Trait`. - let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { - let generics = self.generics_of(body_owner_def_id); - generics.type_param(param_ty, self).def_id - } else { - return false; - }; - let Some(def_id) = def_id.as_local() else { - return false; - }; - - // First look in the `where` clause, as this might be - // `fn foo<T>(x: T) where T: Trait`. - for pred in hir_generics.bounds_for_param(def_id) { - if self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - pred.bounds, - &assoc, - assoc_substs, - ty, - msg, - false, - ) { - return true; - } - } - } - } - false - } - - /// An associated type was expected and a different type was found. - /// - /// We perform a few different checks to see what we can suggest: - /// - /// - In the current item, look for associated functions that return the expected type and - /// suggest calling them. (Not a structured suggestion.) - /// - If any of the item's generic bounds can be constrained, we suggest constraining the - /// associated type to the found type. - /// - If the associated type has a default type and was expected inside of a `trait`, we - /// mention that this is disallowed. - /// - If all other things fail, and the error is not because of a mismatch between the `trait` - /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc - /// fn that returns the type. - fn expected_projection( - self, - diag: &mut Diagnostic, - proj_ty: &ty::AliasTy<'tcx>, - values: ExpectedFound<Ty<'tcx>>, - body_owner_def_id: DefId, - cause_code: &ObligationCauseCode<'_>, - ) { - let msg = format!( - "consider constraining the associated type `{}` to `{}`", - values.expected, values.found - ); - let body_owner = self.hir().get_if_local(body_owner_def_id); - let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); - - // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. - let callable_scope = matches!( - body_owner, - Some( - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) - | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), - ) - ); - let impl_comparison = - matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); - let assoc = self.associated_item(proj_ty.def_id); - if !callable_scope || impl_comparison { - // We do not want to suggest calling functions when the reason of the - // type error is a comparison of an `impl` with its `trait` or when the - // scope is outside of a `Body`. - } else { - // If we find a suitable associated function that returns the expected type, we don't - // want the more general suggestion later in this method about "consider constraining - // the associated type or calling a method that returns the associated type". - let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( - diag, - assoc.container_id(self), - current_method_ident, - proj_ty.def_id, - values.expected, - ); - // Possibly suggest constraining the associated type to conform to the - // found type. - if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found) - || point_at_assoc_fn - { - return; - } - } - - self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found); - - if self.point_at_associated_type(diag, body_owner_def_id, values.found) { - return; - } - - if !impl_comparison { - // Generic suggestion when we can't be more specific. - if callable_scope { - diag.help(&format!( - "{} or calling a method that returns `{}`", - msg, values.expected - )); - } else { - diag.help(&msg); - } - diag.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", - ); - } - if self.sess.teach(&diag.get_code().unwrap()) { - diag.help( - "given an associated type `T` and a method `foo`: -``` -trait Trait { -type T; -fn foo(&self) -> Self::T; -} -``` -the only way of implementing method `foo` is to constrain `T` with an explicit associated type: -``` -impl Trait for X { -type T = String; -fn foo(&self) -> Self::T { String::new() } -} -```", - ); - } - } - - /// When the expected `impl Trait` is not defined in the current item, it will come from - /// a return type. This can occur when dealing with `TryStream` (#71035). - fn suggest_constraining_opaque_associated_type( - self, - diag: &mut Diagnostic, - msg: &str, - proj_ty: &ty::AliasTy<'tcx>, - ty: Ty<'tcx>, - ) -> bool { - let assoc = self.associated_item(proj_ty.def_id); - if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { - let opaque_local_def_id = def_id.as_local(); - let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { - match &self.hir().expect_item(opaque_local_def_id).kind { - hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, - _ => bug!("The HirId comes from a `ty::Opaque`"), - } - } else { - return false; - }; - - let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); - - self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - opaque_hir_ty.bounds, - assoc, - assoc_substs, - ty, - msg, - true, - ) - } else { - false - } - } - - fn point_at_methods_that_satisfy_associated_type( - self, - diag: &mut Diagnostic, - assoc_container_id: DefId, - current_method_ident: Option<Symbol>, - proj_ty_item_def_id: DefId, - expected: Ty<'tcx>, - ) -> bool { - let items = self.associated_items(assoc_container_id); - // Find all the methods in the trait that could be called to construct the - // expected associated type. - // FIXME: consider suggesting the use of associated `const`s. - let methods: Vec<(Span, String)> = items - .items - .iter() - .filter(|(name, item)| { - ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident - }) - .filter_map(|(_, item)| { - let method = self.fn_sig(item.def_id); - match *method.output().skip_binder().kind() { - ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. }) - if item_def_id == proj_ty_item_def_id => - { - Some(( - self.def_span(item.def_id), - format!("consider calling `{}`", self.def_path_str(item.def_id)), - )) - } - _ => None, - } - }) - .collect(); - if !methods.is_empty() { - // Use a single `help:` to show all the methods in the trait that can - // be used to construct the expected associated type. - let mut span: MultiSpan = - methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into(); - let msg = format!( - "{some} method{s} {are} available that return{r} `{ty}`", - some = if methods.len() == 1 { "a" } else { "some" }, - s = pluralize!(methods.len()), - are = pluralize!("is", methods.len()), - r = if methods.len() == 1 { "s" } else { "" }, - ty = expected - ); - for (sp, label) in methods.into_iter() { - span.push_span_label(sp, label); - } - diag.span_help(span, &msg); - return true; - } - false - } - - fn point_at_associated_type( - self, - diag: &mut Diagnostic, - body_owner_def_id: DefId, - found: Ty<'tcx>, - ) -> bool { - let Some(hir_id) = body_owner_def_id.as_local() else { - return false; - }; - let hir_id = self.hir().local_def_id_to_hir_id(hir_id); - // When `body_owner` is an `impl` or `trait` item, look in its associated types for - // `expected` and point at it. - let parent_id = self.hir().get_parent_item(hir_id); - let item = self.hir().find_by_def_id(parent_id.def_id); - debug!("expected_projection parent item {:?}", item); - match item { - Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => { - // FIXME: account for `#![feature(specialization)]` - for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - // FIXME: account for returning some type in a trait fn impl that has - // an assoc type as a return type (#72076). - if let hir::Defaultness::Default { has_value: true } = - self.impl_defaultness(item.id.owner_id) - { - if self.type_of(item.id.owner_id) == found { - diag.span_label( - item.span, - "associated type defaults can't be assumed inside the \ - trait defining them", - ); - return true; - } - } - } - _ => {} - } - } - } - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { items, .. }), - .. - })) => { - for item in &items[..] { - if let hir::AssocItemKind::Type = item.kind { - if self.type_of(item.id.owner_id) == found { - diag.span_label(item.span, "expected this associated type"); - return true; - } - } - } - } - _ => {} - } - false - } - - /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` - /// requirement, provide a structured suggestion to constrain it to a given type `ty`. - /// - /// `is_bound_surely_present` indicates whether we know the bound we're looking for is - /// inside `bounds`. If that's the case then we can consider `bounds` containing only one - /// trait bound as the one we're looking for. This can help in cases where the associated - /// type is defined on a supertrait of the one present in the bounds. - fn constrain_generic_bound_associated_type_structured_suggestion( - self, - diag: &mut Diagnostic, - trait_ref: &ty::TraitRef<'tcx>, - bounds: hir::GenericBounds<'_>, - assoc: &ty::AssocItem, - assoc_substs: &[ty::GenericArg<'tcx>], - ty: Ty<'tcx>, - msg: &str, - is_bound_surely_present: bool, - ) -> bool { - // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. - - let trait_bounds = bounds.iter().filter_map(|bound| match bound { - hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr), - _ => None, - }); - - let matching_trait_bounds = trait_bounds - .clone() - .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)) - .collect::<Vec<_>>(); - - let span = match &matching_trait_bounds[..] { - &[ptr] => ptr.span, - &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] { - &[ptr] => ptr.span, - _ => return false, - }, - _ => return false, - }; - - self.constrain_associated_type_structured_suggestion( - diag, - span, - assoc, - assoc_substs, - ty, - msg, - ) - } - - /// Given a span corresponding to a bound, provide a structured suggestion to set an - /// associated type to a given type `ty`. - fn constrain_associated_type_structured_suggestion( - self, - diag: &mut Diagnostic, - span: Span, - assoc: &ty::AssocItem, - assoc_substs: &[ty::GenericArg<'tcx>], - ty: Ty<'tcx>, - msg: &str, - ) -> bool { - if let Ok(has_params) = - self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>')) - { - let (span, sugg) = if has_params { - let pos = span.hi() - BytePos(1); - let span = Span::new(pos, pos, span.ctxt(), span.parent()); - (span, format!(", {} = {}", assoc.ident(self), ty)) - } else { - let item_args = self.format_generic_args(assoc_substs); - (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty)) - }; - diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); - return true; - } - false - } - pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) { let width = self.sess.diagnostic_width(); let length_limit = width.saturating_sub(30); @@ -1047,11 +428,4 @@ fn foo(&self) -> Self::T { String::new() } Err(_) => (regular, None), } } - - fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String { - FmtPrinter::new(self, hir::def::Namespace::TypeNS) - .path_generic_args(Ok, args) - .expect("could not write to `String`.") - .into_buffer() - } } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index f785fb5c4b9..9afa37e9ef3 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -32,6 +32,7 @@ pub enum SimplifiedType { ClosureSimplifiedType(DefId), GeneratorSimplifiedType(DefId), GeneratorWitnessSimplifiedType(usize), + GeneratorWitnessMIRSimplifiedType(DefId), FunctionSimplifiedType(usize), PlaceholderSimplifiedType, } @@ -108,6 +109,7 @@ pub fn simplify_type<'tcx>( ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())), + ty::GeneratorWitnessMIR(def_id, _) => Some(GeneratorWitnessMIRSimplifiedType(def_id)), ty::Never => Some(NeverSimplifiedType), ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())), ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), @@ -139,7 +141,8 @@ impl SimplifiedType { | ForeignSimplifiedType(d) | TraitSimplifiedType(d) | ClosureSimplifiedType(d) - | GeneratorSimplifiedType(d) => Some(d), + | GeneratorSimplifiedType(d) + | GeneratorWitnessMIRSimplifiedType(d) => Some(d), _ => None, } } @@ -208,6 +211,7 @@ impl DeepRejectCtxt { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), @@ -306,7 +310,7 @@ impl DeepRejectCtxt { ty::Error(_) => true, - ty::GeneratorWitness(..) | ty::Bound(..) => { + ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Bound(..) => { bug!("unexpected obligation type: {:?}", obligation_ty) } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index b7eafc4b437..dc6f5851b7d 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -125,6 +125,16 @@ impl FlagComputation { self.bound_computation(ts, |flags, ts| flags.add_tys(ts)); } + &ty::GeneratorWitnessMIR(_, ref substs) => { + let should_remove_further_specializable = + !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_substs(substs); + if should_remove_further_specializable { + self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; + } + self.add_flags(TypeFlags::HAS_TY_GENERATOR); + } + &ty::Closure(_, substs) => { let substs = substs.as_closure(); let should_remove_further_specializable = diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 6ac00d16c53..8b4fccc58bd 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -459,7 +459,7 @@ impl<'tcx> Instance<'tcx> { substs: SubstsRef<'tcx>, ) -> Option<Instance<'tcx>> { debug!("resolve_for_vtable(def_id={:?}, substs={:?})", def_id, substs); - let fn_sig = tcx.fn_sig(def_id); + let fn_sig = tcx.fn_sig(def_id).subst_identity(); let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty() && fn_sig.input(0).skip_binder().is_param(0) && tcx.generics_of(def_id).has_self; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index dfd016569c2..cdcd6281f20 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -128,7 +128,8 @@ impl PrimitiveExt for Primitive { Int(i, signed) => i.to_ty(tcx, signed), F32 => tcx.types.f32, F64 => tcx.types.f64, - Pointer => tcx.mk_mut_ptr(tcx.mk_unit()), + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()), } } @@ -138,7 +139,11 @@ impl PrimitiveExt for Primitive { fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { Int(i, signed) => i.to_ty(tcx, signed), - Pointer => tcx.types.usize, + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Pointer(_) => { + let signed = false; + tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed) + } F32 | F64 => bug!("floats do not have an int type"), } } @@ -640,6 +645,7 @@ where | ty::Never | ty::FnDef(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Foreign(..) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) @@ -812,132 +818,125 @@ where let tcx = cx.tcx(); let param_env = cx.param_env(); - let addr_space_of_ty = |ty: Ty<'tcx>| { - if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA } - }; - - let pointee_info = match *this.ty.kind() { - ty::RawPtr(mt) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, - address_space: addr_space_of_ty(mt.ty), - }) - } - ty::FnPtr(fn_sig) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, - address_space: cx.data_layout().instruction_address_space, - }) - } - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let address_space = addr_space_of_ty(ty); - let kind = if tcx.sess.opts.optimize == OptLevel::No { - // Use conservative pointer kind if not optimizing. This saves us the - // Freeze/Unpin queries, and can save time in the codegen backend (noalias - // attributes in LLVM have compile-time cost even in unoptimized builds). - PointerKind::SharedMutable - } else { - match mt { - hir::Mutability::Not => { - if ty.is_freeze(tcx, cx.param_env()) { - PointerKind::Frozen - } else { - PointerKind::SharedMutable + let pointee_info = + match *this.ty.kind() { + ty::RawPtr(mt) if offset.bytes() == 0 => { + tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: None, + }) + } + ty::FnPtr(fn_sig) if offset.bytes() == 0 => { + tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| { + PointeeInfo { size: layout.size, align: layout.align.abi, safe: None } + }) + } + ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + let kind = if tcx.sess.opts.optimize == OptLevel::No { + // Use conservative pointer kind if not optimizing. This saves us the + // Freeze/Unpin queries, and can save time in the codegen backend (noalias + // attributes in LLVM have compile-time cost even in unoptimized builds). + PointerKind::SharedMutable + } else { + match mt { + hir::Mutability::Not => { + if ty.is_freeze(tcx, cx.param_env()) { + PointerKind::Frozen + } else { + PointerKind::SharedMutable + } } - } - hir::Mutability::Mut => { - // References to self-referential structures should not be considered - // noalias, as another pointer to the structure can be obtained, that - // is not based-on the original reference. We consider all !Unpin - // types to be potentially self-referential here. - if ty.is_unpin(tcx, cx.param_env()) { - PointerKind::UniqueBorrowed - } else { - PointerKind::UniqueBorrowedPinned + hir::Mutability::Mut => { + // References to self-referential structures should not be considered + // noalias, as another pointer to the structure can be obtained, that + // is not based-on the original reference. We consider all !Unpin + // types to be potentially self-referential here. + if ty.is_unpin(tcx, cx.param_env()) { + PointerKind::UniqueBorrowed + } else { + PointerKind::UniqueBorrowedPinned + } } } - } - }; + }; - tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: Some(kind), - address_space, - }) - } + tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: Some(kind), + }) + } - _ => { - let mut data_variant = match this.variants { - // Within the discriminant field, only the niche itself is - // always initialized, so we only check for a pointer at its - // offset. - // - // If the niche is a pointer, it's either valid (according - // to its type), or null (which the niche field's scalar - // validity range encodes). This allows using - // `dereferenceable_or_null` for e.g., `Option<&T>`, and - // this will continue to work as long as we don't start - // using more niches than just null (e.g., the first page of - // the address space, or unaligned pointers). - Variants::Multiple { - tag_encoding: TagEncoding::Niche { untagged_variant, .. }, - tag_field, - .. - } if this.fields.offset(tag_field) == offset => { - Some(this.for_variant(cx, untagged_variant)) - } - _ => Some(this), - }; + _ => { + let mut data_variant = match this.variants { + // Within the discriminant field, only the niche itself is + // always initialized, so we only check for a pointer at its + // offset. + // + // If the niche is a pointer, it's either valid (according + // to its type), or null (which the niche field's scalar + // validity range encodes). This allows using + // `dereferenceable_or_null` for e.g., `Option<&T>`, and + // this will continue to work as long as we don't start + // using more niches than just null (e.g., the first page of + // the address space, or unaligned pointers). + Variants::Multiple { + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, + tag_field, + .. + } if this.fields.offset(tag_field) == offset => { + Some(this.for_variant(cx, untagged_variant)) + } + _ => Some(this), + }; - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let FieldsShape::Union(_) = variant.fields { - data_variant = None; + if let Some(variant) = data_variant { + // We're not interested in any unions. + if let FieldsShape::Union(_) = variant.fields { + data_variant = None; + } } - } - let mut result = None; - - if let Some(variant) = data_variant { - let ptr_end = offset + Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - result = field.to_result().ok().and_then(|field| { - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - let field_info = - field.pointee_info_at(cx, offset - field_start); - field_info - } else { - None + let mut result = None; + + if let Some(variant) = data_variant { + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + // (requires passing in the expected address space from the caller) + let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx); + for i in 0..variant.fields.count() { + let field_start = variant.fields.offset(i); + if field_start <= offset { + let field = variant.field(cx, i); + result = field.to_result().ok().and_then(|field| { + if ptr_end <= field_start + field.size { + // We found the right field, look inside it. + let field_info = + field.pointee_info_at(cx, offset - field_start); + field_info + } else { + None + } + }); + if result.is_some() { + break; } - }); - if result.is_some() { - break; } } } - } - // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`. - if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.kind() { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); + // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`. + if let Some(ref mut pointee) = result { + if let ty::Adt(def, _) = this.ty.kind() { + if def.is_box() && offset.bytes() == 0 { + pointee.safe = Some(PointerKind::UniqueOwned); + } } } - } - result - } - }; + result + } + }; debug!( "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}", diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f83bceca3b5..25c6777a14c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -31,7 +31,6 @@ pub use generics::*; use rustc_ast as ast; use rustc_ast::node_id::NodeMap; use rustc_attr as attr; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -453,18 +452,6 @@ pub struct CReaderCacheKey { #[rustc_pass_by_value] pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>); -impl<'tcx> TyCtxt<'tcx> { - /// A "bool" type used in rustc_mir_transform unit tests when we - /// have not spun up a TyCtxt. - pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = - Ty(Interned::new_unchecked(&WithCachedTypeInfo { - internee: ty::Bool, - stable_hash: Fingerprint::ZERO, - flags: TypeFlags::empty(), - outer_exclusive_binder: DebruijnIndex::from_usize(0), - })); -} - impl ty::EarlyBoundRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). @@ -2437,6 +2424,7 @@ impl<'tcx> TyCtxt<'tcx> { ident } + // FIXME(vincenzoapalzzo): move the HirId to a LocalDefId pub fn adjust_ident_and_get_scope( self, mut ident: Ident, @@ -2470,10 +2458,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn is_object_safe(self, key: DefId) -> bool { - self.object_safety_violations(key).is_empty() - } - #[inline] pub fn is_const_fn_raw(self, def_id: DefId) -> bool { matches!( diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 98cd92007c2..7ff58f02623 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -3,6 +3,7 @@ use crate::ty::fold::{TypeFolder, TypeSuperFoldable}; use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; +use rustc_span::def_id::DefId; use rustc_span::Span; /// Converts generic params of a TypeFoldable from one @@ -47,6 +48,47 @@ impl<'tcx> ReverseMapper<'tcx> { assert!(!self.do_not_error); kind.fold_with(self) } + + fn fold_closure_substs( + &mut self, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, + ) -> ty::SubstsRef<'tcx> { + // I am a horrible monster and I pray for death. When + // we encounter a closure here, it is always a closure + // from within the function that we are currently + // type-checking -- one that is now being encapsulated + // in an opaque type. Ideally, we would + // go through the types/lifetimes that it references + // and treat them just like we would any other type, + // which means we would error out if we find any + // reference to a type/region that is not in the + // "reverse map". + // + // **However,** in the case of closures, there is a + // somewhat subtle (read: hacky) consideration. The + // problem is that our closure types currently include + // all the lifetime parameters declared on the + // enclosing function, even if they are unused by the + // closure itself. We can't readily filter them out, + // so here we replace those values with `'empty`. This + // can't really make a difference to the rest of the + // compiler; those regions are ignored for the + // outlives relation, and hence don't affect trait + // selection or auto traits, and they are erased + // during codegen. + + let generics = self.tcx.generics_of(def_id); + self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_no_missing_regions_error(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })) + } } impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { @@ -104,59 +146,20 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { match *ty.kind() { ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - + let substs = self.fold_closure_substs(def_id, substs); self.tcx.mk_closure(def_id, substs) } ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - + let substs = self.fold_closure_substs(def_id, substs); self.tcx.mk_generator(def_id, substs, movability) } + ty::GeneratorWitnessMIR(def_id, substs) => { + let substs = self.fold_closure_substs(def_id, substs); + self.tcx.mk_generator_witness_mir(def_id, substs) + } + ty::Param(param) => { // Look it up in the substitution list. match self.map.get(&ty.into()).map(|k| k.unpack()) { diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 24f3d1acff1..84edb5f2a42 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -117,6 +117,7 @@ macro_rules! parameterized_over_tcx { parameterized_over_tcx! { crate::middle::exported_symbols::ExportedSymbol, crate::mir::Body, + crate::mir::GeneratorLayout, ty::Ty, ty::FnSig, ty::GenericPredicates, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index c302c461195..90bf3288ccf 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -265,6 +265,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::Generator(def_id, _, _) + | ty::GeneratorWitnessMIR(def_id, _) | ty::Foreign(def_id) => Some(def_id), ty::Bool diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ae7c20fff0c..f2abec216b7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -675,7 +675,7 @@ pub trait PrettyPrinter<'tcx>: p!(")") } ty::FnDef(def_id, substs) => { - let sig = self.tcx().bound_fn_sig(def_id).subst(self.tcx(), substs); + let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs); p!(print(sig), " {{", print_value_path(def_id, substs), "}}"); } ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), @@ -811,6 +811,28 @@ pub trait PrettyPrinter<'tcx>: ty::GeneratorWitness(types) => { p!(in_binder(&types)); } + ty::GeneratorWitnessMIR(did, substs) => { + p!(write("[")); + if !self.tcx().sess.verbose() { + p!("generator witness"); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + let span = self.tcx().def_span(did); + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_embeddable_string(span) + )); + } else { + p!(write("@"), print_def_path(did, substs)); + } + } else { + p!(print_def_path(did, substs)); + } + + p!("]") + } ty::Closure(did, substs) => { p!(write("[")); if !self.should_print_verbose() { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 9d4ee22a727..1be819ca610 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -118,6 +118,7 @@ fn copy<T: Copy>(x: &T) -> T { macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam<DefId> }; + (LocalDefId) => { impl IntoQueryParam<LocalDefId> }; ($K:ty) => { $K }; } @@ -418,6 +419,13 @@ mod sealed { } } + impl IntoQueryParam<LocalDefId> for OwnerId { + #[inline(always)] + fn into_query_param(self) -> LocalDefId { + self.def_id + } + } + impl IntoQueryParam<DefId> for LocalDefId { #[inline(always)] fn into_query_param(self) -> DefId { @@ -441,6 +449,10 @@ impl<'tcx> TyCtxt<'tcx> { self.opt_def_kind(def_id) .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) } + + pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> { + ty::EarlyBinder(self.type_of(def_id)) + } } impl<'tcx> TyCtxtAt<'tcx> { @@ -449,4 +461,8 @@ impl<'tcx> TyCtxtAt<'tcx> { self.opt_def_kind(def_id) .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) } + + pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> { + ty::EarlyBinder(self.type_of(def_id)) + } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 65fd8d9753d..fa87301df7e 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( if a_repr == b_repr => { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { - relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a_region, - b_region, - ) + relation.relate(a_region, b_region) })?; Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } @@ -473,6 +468,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(tcx.mk_generator_witness(types)) } + (&ty::GeneratorWitnessMIR(a_id, a_substs), &ty::GeneratorWitnessMIR(b_id, b_substs)) + if a_id == b_id => + { + // All GeneratorWitness types with the same id represent + // the (anonymous) type of the same generator expression. So + // all of their regions should be equated. + let substs = relation.relate(a_substs, b_substs)?; + Ok(tcx.mk_generator_witness_mir(a_id, substs)) + } + (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => { // All Closure types with the same id represent // the (anonymous) type of the same closure expression. So @@ -487,12 +492,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( } (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - let r = relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a_r, - b_r, - )?; + let r = relation.relate(a_r, b_r)?; let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7d4d35b7fdf..034aab0c38e 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,6 +11,7 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; use rustc_hir::def::Namespace; use rustc_index::vec::{Idx, IndexVec}; +use rustc_target::abi::TyAndLayout; use std::fmt; use std::mem::ManuallyDrop; @@ -200,6 +201,7 @@ TrivialTypeTraversalAndLiftImpls! { bool, usize, ::rustc_target::abi::VariantIdx, + u16, u32, u64, String, @@ -654,6 +656,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { ty::Generator(did, substs.try_fold_with(folder)?, movability) } ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?), + ty::GeneratorWitnessMIR(did, substs) => { + ty::GeneratorWitnessMIR(did, substs.try_fold_with(folder)?) + } ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?), ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), @@ -699,6 +704,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { } ty::Generator(_did, ref substs, _) => substs.visit_with(visitor), ty::GeneratorWitness(ref types) => types.visit_with(visitor), + ty::GeneratorWitnessMIR(_did, ref substs) => substs.visit_with(visitor), ty::Closure(_did, ref substs) => substs.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor), @@ -853,3 +859,9 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> { self.substs.visit_with(visitor) } } + +impl<'tcx> TypeVisitable<'tcx> for TyAndLayout<'tcx, Ty<'tcx>> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + visitor.visit_ty(self.ty) + } +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 6a7b23e40a7..f97d2e753a3 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -571,9 +571,9 @@ impl<'tcx> GeneratorSubsts<'tcx> { ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { - variant - .iter() - .map(move |field| ty::EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs)) + variant.iter().map(move |field| { + ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs) + }) }) } @@ -2059,7 +2059,7 @@ impl<'tcx> Ty<'tcx> { pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { - FnDef(def_id, substs) => tcx.bound_fn_sig(*def_id).subst(tcx, substs), + FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) @@ -2175,6 +2175,7 @@ impl<'tcx> Ty<'tcx> { | ty::Dynamic(..) | ty::Closure(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Error(_) @@ -2210,6 +2211,7 @@ impl<'tcx> Ty<'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2296,6 +2298,7 @@ impl<'tcx> Ty<'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2360,7 +2363,7 @@ impl<'tcx> Ty<'tcx> { // anything with custom metadata it might be more complicated. ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, - ty::Generator(..) | ty::GeneratorWitness(..) => false, + ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => false, // Might be, but not "trivial" so just giving the safe answer. ty::Adt(..) | ty::Closure(..) => false, diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index a07582fc8ff..cf1bb5f8ac8 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -758,6 +758,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder<T> { pub fn subst_identity(self) -> T { self.0 } + + /// Returns the inner value, but only if it contains no bound vars. + pub fn no_bound_vars(self) -> Option<T> { + if !self.0.needs_subst() { Some(self.0) } else { None } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 2902c6dc556..79a6c730d71 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -1,6 +1,7 @@ use crate::{ hir::place::Place as HirPlace, infer::canonical::Canonical, + traits::ObligationCause, ty::{ self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts, @@ -193,6 +194,11 @@ pub struct TypeckResults<'tcx> { /// that are live across the yield of this generator (if a generator). pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>, + /// Stores the predicates that apply on generator witness types. + /// formatting modified file tests/ui/generator/retain-resume-ref.rs + pub generator_interior_predicates: + FxHashMap<LocalDefId, Vec<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>>, + /// We sometimes treat byte string literals (which are of type `&[u8; N]`) /// as `&[u8]`, depending on the pattern in which they are used. /// This hashset records all instances where we behave @@ -271,6 +277,7 @@ impl<'tcx> TypeckResults<'tcx> { closure_fake_reads: Default::default(), rvalue_scopes: Default::default(), generator_interior_types: ty::Binder::dummy(Default::default()), + generator_interior_predicates: Default::default(), treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 60076c8cb5f..796164b0d6a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -3,7 +3,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir; use crate::ty::layout::IntegerExt; -use crate::ty::query::TyCtxtAt; use crate::ty::{ self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, @@ -616,6 +615,36 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Return the set of types that should be taken into accound when checking + /// trait bounds on a generator's internal state. + pub fn generator_hidden_types( + self, + def_id: DefId, + ) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> { + let generator_layout = &self.mir_generator_witnesses(def_id); + generator_layout + .field_tys + .iter() + .filter(|decl| !decl.ignore_for_traits) + .map(|decl| ty::EarlyBinder(decl.ty)) + } + + /// Normalizes all opaque types in the given value, replacing them + /// with their underlying types. + pub fn expand_opaque_types(self, val: Ty<'tcx>) -> Ty<'tcx> { + let mut visitor = OpaqueTypeExpander { + seen_opaque_tys: FxHashSet::default(), + expanded_cache: FxHashMap::default(), + primary_def_id: None, + found_recursion: false, + found_any_recursion: false, + check_recursion: false, + expand_generators: false, + tcx: self, + }; + val.fold_with(&mut visitor) + } + /// Expands the given impl trait type, stopping if the type is recursive. #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( @@ -630,6 +659,7 @@ impl<'tcx> TyCtxt<'tcx> { found_recursion: false, found_any_recursion: false, check_recursion: true, + expand_generators: true, tcx: self, }; @@ -637,10 +667,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> { - ty::EarlyBinder(self.type_of(def_id)) - } - pub fn bound_return_position_impl_trait_in_trait_tys( self, def_id: DefId, @@ -648,10 +674,6 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id)) } - pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> { - ty::EarlyBinder(self.fn_sig(def_id)) - } - pub fn bound_explicit_item_bounds( self, def_id: DefId, @@ -738,12 +760,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -impl<'tcx> TyCtxtAt<'tcx> { - pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> { - ty::EarlyBinder(self.type_of(def_id)) - } -} - struct OpaqueTypeExpander<'tcx> { // Contains the DefIds of the opaque types that are currently being // expanded. When we expand an opaque type we insert the DefId of @@ -756,6 +772,7 @@ struct OpaqueTypeExpander<'tcx> { primary_def_id: Option<DefId>, found_recursion: bool, found_any_recursion: bool, + expand_generators: bool, /// Whether or not to check for recursive opaque types. /// This is `true` when we're explicitly checking for opaque type /// recursion, and 'false' otherwise to avoid unnecessary work. @@ -792,6 +809,37 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { None } } + + fn expand_generator(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> { + if self.found_any_recursion { + return None; + } + let substs = substs.fold_with(self); + if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { + let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { + Some(expanded_ty) => *expanded_ty, + None => { + for bty in self.tcx.generator_hidden_types(def_id) { + let hidden_ty = bty.subst(self.tcx, substs); + self.fold_ty(hidden_ty); + } + let expanded_ty = self.tcx.mk_generator_witness_mir(def_id, substs); + self.expanded_cache.insert((def_id, substs), expanded_ty); + expanded_ty + } + }; + if self.check_recursion { + self.seen_opaque_tys.remove(&def_id); + } + Some(expanded_ty) + } else { + // If another opaque type that we contain is recursive, then it + // will report the error, so we don't have to. + self.found_any_recursion = true; + self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap(); + None + } + } } impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { @@ -800,13 +848,19 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() { + let mut t = if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() { self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else if t.has_opaque_types() { + } else if t.has_opaque_types() || t.has_generators() { t.super_fold_with(self) } else { t + }; + if self.expand_generators { + if let ty::GeneratorWitnessMIR(def_id, substs) = *t.kind() { + t = self.expand_generator(def_id, substs).unwrap_or(t); + } } + t } } @@ -911,6 +965,7 @@ impl<'tcx> Ty<'tcx> { | ty::Foreign(_) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Infer(_) | ty::Alias(..) | ty::Param(_) @@ -950,6 +1005,7 @@ impl<'tcx> Ty<'tcx> { | ty::Foreign(_) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Infer(_) | ty::Alias(..) | ty::Param(_) @@ -1077,7 +1133,10 @@ impl<'tcx> Ty<'tcx> { false } - ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false, + ty::Foreign(_) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Error(_) => false, } } @@ -1173,6 +1232,7 @@ pub fn needs_drop_components<'tcx>( | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::Str => Ok(SmallVec::new()), @@ -1243,7 +1303,11 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { // Not trivial because they have components, and instead of looking inside, // we'll just perform trait selection. - ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false, + ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) + | ty::Adt(..) => false, ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), @@ -1304,6 +1368,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( found_recursion: false, found_any_recursion: false, check_recursion: false, + expand_generators: false, tcx, }; val.fold_with(&mut visitor) @@ -1326,7 +1391,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// Determines whether an item is an intrinsic by Abi. pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) + matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } pub fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index bee3cc4d7cb..d7b7a094737 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -100,6 +100,9 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { fn has_opaque_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } + fn has_generators(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_GENERATOR) + } fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 708a5e4d059..182945b9c3d 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -190,6 +190,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Adt(_, substs) | ty::Closure(_, substs) | ty::Generator(_, substs, _) + | ty::GeneratorWitnessMIR(_, substs) | ty::FnDef(_, substs) => { stack.extend(substs.iter().rev()); } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 0bca02589bc..dbba529aef7 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -18,6 +18,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { @call("mir_storage_dead", args) => { Ok(StatementKind::StorageDead(self.parse_local(args[0])?)) }, + @call("mir_deinit", args) => { + Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?))) + }, @call("mir_retag", args) => { Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?))) }, @@ -141,12 +144,29 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> { parse_by_kind!(self, expr_id, _, "rvalue", @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant), + @call("mir_checked", args) => { + parse_by_kind!(self, args[0], _, "binary op", + ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp( + *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)) + )), + ) + }, + @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) ), ExprKind::AddressOf { mutability, arg } => Ok( Rvalue::AddressOf(*mutability, self.parse_place(*arg)?) ), + ExprKind::Binary { op, lhs, rhs } => Ok( + Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))) + ), + ExprKind::Unary { op, arg } => Ok( + Rvalue::UnaryOp(*op, self.parse_operand(*arg)?) + ), + ExprKind::Repeat { value, count } => Ok( + Rvalue::Repeat(self.parse_operand(*value)?, *count) + ), _ => self.parse_operand(expr_id).map(Rvalue::Use), ) } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0961ce11e2f..6b960ebdb16 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1747,8 +1747,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); - let fake_borrow_temp = - self.local_decls.push(LocalDecl::new(fake_borrow_ty, temp_span)); + let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); + fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; + fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow)); + let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); (matched_place, fake_borrow_temp) }) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 9daf68a15f4..1655e224ddb 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -439,6 +439,10 @@ fn construct_fn<'tcx>( let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); let generator_kind = tcx.generator_kind(fn_def.did); + // The representation of thir for `-Zunpretty=thir-tree` relies on + // the entry expression being the last element of `thir.exprs`. + assert_eq!(expr.as_usize(), thir.exprs.len() - 1); + // Figure out what primary body this item has. let body_id = tcx.hir().body_owned_by(fn_def.did); let span_with_body = tcx.hir().span_with_body(fn_id); @@ -637,7 +641,7 @@ fn construct_error( let ty = tcx.ty_error(); let num_params = match body_owner_kind { - hir::BodyOwnerKind::Fn => tcx.fn_sig(def).inputs().skip_binder().len(), + hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(), hir::BodyOwnerKind::Closure => { let ty = tcx.type_of(def); match ty.kind() { diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 7f81aef1c73..ced251267d3 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -600,32 +600,56 @@ pub struct BorrowOfMovedValue<'tcx> { pub struct MultipleMutBorrows { #[primary_span] pub span: Span, - #[label] - pub binding_span: Span, #[subdiagnostic] - pub occurences: Vec<MultipleMutBorrowOccurence>, - pub name: Ident, + pub occurences: Vec<Conflict>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_already_borrowed)] +pub struct AlreadyBorrowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub occurences: Vec<Conflict>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_already_mut_borrowed)] +pub struct AlreadyMutBorrowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub occurences: Vec<Conflict>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_moved_while_borrowed)] +pub struct MovedWhileBorrowed { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub occurences: Vec<Conflict>, } #[derive(Subdiagnostic)] -pub enum MultipleMutBorrowOccurence { - #[label(mutable_borrow)] - Mutable { +pub enum Conflict { + #[label(mir_build_mutable_borrow)] + Mut { #[primary_span] span: Span, - name_mut: Ident, + name: Ident, }, - #[label(immutable_borrow)] - Immutable { + #[label(mir_build_borrow)] + Ref { #[primary_span] span: Span, - name_immut: Ident, + name: Ident, }, - #[label(moved)] + #[label(mir_build_moved)] Moved { #[primary_span] span: Span, - name_moved: Ident, + name: Ident, }, } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a428180a4fa..94dae36154c 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -34,4 +34,5 @@ pub fn provide(providers: &mut Providers) { providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::cx::thir_tree; + providers.thir_flat = thir::cx::thir_flat; } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index a355e1bdab5..10df4b22952 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -54,6 +54,16 @@ pub(crate) fn thir_body( pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { match thir_body(tcx, owner_def) { + Ok((thir, _)) => { + let thir = thir.steal(); + tcx.thir_tree_representation(&thir) + } + Err(_) => "error".into(), + } +} + +pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String { + match thir_body(tcx, owner_def) { Ok((thir, _)) => format!("{:#?}", thir.steal()), Err(_) => "error".into(), } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 34e637f5948..2640ca56b00 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -208,9 +208,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` // when the iterator is an uninhabited type. unreachable_code will trigger instead. hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {} - hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - report_arm_reachability(&cx, &report) - } + hir::MatchSource::ForLoopDesugar + | hir::MatchSource::Normal + | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report), // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} @@ -926,58 +926,55 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa sub.each_binding(|_, hir_id, span, name| { match typeck_results.extract_binding_mode(sess, hir_id, span) { Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) { - (Mutability::Not, Mutability::Not) => {} // Both sides are `ref`. - (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`. - _ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction. + // Both sides are `ref`. + (Mutability::Not, Mutability::Not) => {} + // 2x `ref mut`. + (Mutability::Mut, Mutability::Mut) => { + conflicts_mut_mut.push(Conflict::Mut { span, name }) + } + (Mutability::Not, Mutability::Mut) => { + conflicts_mut_ref.push(Conflict::Mut { span, name }) + } + (Mutability::Mut, Mutability::Not) => { + conflicts_mut_ref.push(Conflict::Ref { span, name }) + } }, Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => { - conflicts_move.push((span, name)) // `ref mut?` + by-move conflict. + conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. } Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine. } }); + let report_mut_mut = !conflicts_mut_mut.is_empty(); + let report_mut_ref = !conflicts_mut_ref.is_empty(); + let report_move_conflict = !conflicts_move.is_empty(); + + let mut occurences = match mut_outer { + Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }], + Mutability::Not => vec![Conflict::Ref { span: binding_span, name }], + }; + occurences.extend(conflicts_mut_mut); + occurences.extend(conflicts_mut_ref); + occurences.extend(conflicts_move); + // Report errors if any. - if !conflicts_mut_mut.is_empty() { + if report_mut_mut { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - let mut occurences = vec![]; - - for (span, name_mut) in conflicts_mut_mut { - occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut }); - } - for (span, name_immut) in conflicts_mut_ref { - occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut }); - } - for (span, name_moved) in conflicts_move { - occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved }); - } - sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name }); - } else if !conflicts_mut_ref.is_empty() { + sess.emit_err(MultipleMutBorrows { span: pat.span, occurences }); + } else if report_mut_ref { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. - let (primary, also) = match mut_outer { - Mutability::Mut => ("mutable", "immutable"), - Mutability::Not => ("immutable", "mutable"), + match mut_outer { + Mutability::Mut => { + sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences }); + } + Mutability::Not => { + sess.emit_err(AlreadyBorrowed { span: pat.span, occurences }); + } }; - let msg = - format!("cannot borrow value as {} because it is also borrowed as {}", also, primary); - let mut err = sess.struct_span_err(pat.span, &msg); - err.span_label(binding_span, format!("{} borrow, by `{}`, occurs here", primary, name)); - for (span, name) in conflicts_mut_ref { - err.span_label(span, format!("{} borrow, by `{}`, occurs here", also, name)); - } - for (span, name) in conflicts_move { - err.span_label(span, format!("also moved into `{}` here", name)); - } - err.emit(); - } else if !conflicts_move.is_empty() { + } else if report_move_conflict { // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - let mut err = - sess.struct_span_err(pat.span, "cannot move out of value because it is borrowed"); - err.span_label(binding_span, format!("value borrowed, by `{}`, here", name)); - for (span, name) in conflicts_move { - err.span_label(span, format!("value moved into `{}` here", name)); - } - err.emit(); + sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences }); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 7f3519945c3..ff88d001351 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -192,7 +192,7 @@ impl<'tcx> ConstToPat<'tcx> { let obligation: PredicateObligation<'_> = predicate_for_trait_def( self.tcx(), self.param_env, - ObligationCause::misc(self.span, self.id), + ObligationCause::misc(self.span, self.id.owner.def_id), partial_eq_trait_id, 0, [ty, ty], diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 923dc16c11b..2890fa32cc9 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -271,6 +271,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => None, }; if let Some(destination) = destination { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 8d379b90a86..fcf0ce9d821 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -141,6 +141,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::FakeRead(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop | StatementKind::Retag(..) | StatementKind::Intrinsic(..) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index f46fd118bde..0195693a7cb 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -331,6 +331,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 0522c657939..6bdbda909d7 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -84,7 +84,8 @@ pub trait ValueAnalysis<'tcx> { StatementKind::Retag(..) => { // We don't track references. } - StatementKind::Nop + StatementKind::ConstEvalCounter + | StatementKind::Nop | StatementKind::FakeRead(..) | StatementKind::Coverage(..) | StatementKind::AscribeUserType(..) => (), diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 51abcf51189..3e7571aa7a2 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -1,17 +1,11 @@ -use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::UNALIGNED_REFERENCES; use crate::util; use crate::MirLint; -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; -} - pub struct CheckPackedRef; impl<'tcx> MirLint<'tcx> for CheckPackedRef { @@ -30,32 +24,6 @@ struct PackedRefChecker<'a, 'tcx> { source_info: SourceInfo, } -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - // FIXME: when we make this a hard error, this should have its - // own error code. - - let extra = if tcx.generics_of(def_id).own_requires_monomorphization() { - "with type or const parameters" - } else { - "that does not derive `Copy`" - }; - let message = format!( - "`{}` can't be derived on this `#[repr(packed)]` struct {}", - tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")), - extra - ); - - tcx.struct_span_lint_hir( - UNALIGNED_REFERENCES, - lint_hir_id, - tcx.def_span(def_id), - message, - |lint| lint, - ); -} - impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { // Make sure we know where in the MIR we are. @@ -73,14 +41,13 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { let def_id = self.body.source.instance.def_id(); - if let Some(impl_def_id) = self - .tcx - .impl_of_method(def_id) - .filter(|&def_id| self.tcx.is_builtin_derive(def_id)) + if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) + && self.tcx.is_builtin_derive(impl_def_id) { - // If a method is defined in the local crate, - // the impl containing that method should also be. - self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); + // If we ever reach here it means that the generated derive + // code is somehow doing an unaligned reference, which it + // shouldn't do. + unreachable!(); } else { let source_info = self.source_info; let lint_root = self.body.source_scopes[source_info.scope] diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index adf6ae4c727..8afa53313fc 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -104,6 +104,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => { // safe (at least as emitted during MIR construction) } @@ -445,7 +446,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { _fd: &'tcx hir::FnDecl<'tcx>, b: hir::BodyId, _s: rustc_span::Span, - _id: HirId, + _id: LocalDefId, ) { if matches!(fk, intravisit::FnKind::Closure) { self.visit_body(self.tcx.hir().body(b)) diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 40eefda4f07..da101ca7ad2 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -57,6 +57,15 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { } impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> { + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { + if data.is_cleanup { + // Because of the restrictions around control flow in cleanup blocks, we don't perform + // this optimization at all in such blocks. + return; + } + self.super_basic_block_data(block, data); + } + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { let _: Option<_> = try { let target = terminator.kind.as_goto()?; diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs new file mode 100644 index 00000000000..182b3015dd7 --- /dev/null +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -0,0 +1,178 @@ +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::borrowed_locals; + +use crate::ssa::SsaLocals; +use crate::MirPass; + +/// Unify locals that copy each other. +/// +/// We consider patterns of the form +/// _a = rvalue +/// _b = move? _a +/// _c = move? _a +/// _d = move? _c +/// where each of the locals is only assigned once. +/// +/// We want to replace all those locals by `_a`, either copied or moved. +pub struct CopyProp; + +impl<'tcx> MirPass<'tcx> for CopyProp { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + + #[instrument(level = "trace", skip(self, tcx, body))] + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!(def_id = ?body.source.def_id()); + propagate_ssa(tcx, body); + } +} + +fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let borrowed_locals = borrowed_locals(body); + let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals); + + let fully_moved = fully_moved_locals(&ssa, body); + debug!(?fully_moved); + + let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size()); + for (local, &head) in ssa.copy_classes().iter_enumerated() { + if local != head { + storage_to_remove.insert(head); + } + } + + let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); + + Replacer { + tcx, + copy_classes: &ssa.copy_classes(), + fully_moved, + borrowed_locals, + storage_to_remove, + } + .visit_body_preserves_cfg(body); + + if any_replacement { + crate::simplify::remove_unused_definitions(body); + } +} + +/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments. +/// +/// This function also returns whether all the `move?` in the pattern are `move` and not copies. +/// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be +/// replaced by `copy _a`, as we cannot move multiple times from `_a`. +/// +/// If an operand copies `_c`, it must happen before the assignment `_d = _c`, otherwise it is UB. +/// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is +/// moved, and therefore that `_d` is moved. +#[instrument(level = "trace", skip(ssa, body))] +fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> { + let mut fully_moved = BitSet::new_filled(body.local_decls.len()); + + for (_, rvalue) in ssa.assignments(body) { + let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place)) + = rvalue + else { continue }; + + let Some(rhs) = place.as_local() else { continue }; + if !ssa.is_ssa(rhs) { + continue; + } + + if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue { + fully_moved.remove(rhs); + } + } + + ssa.meet_copy_equivalence(&mut fully_moved); + + fully_moved +} + +/// Utility to help performing subtitution of `*pattern` by `target`. +struct Replacer<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + fully_moved: BitSet<Local>, + storage_to_remove: BitSet<Local>, + borrowed_locals: BitSet<Local>, + copy_classes: &'a IndexVec<Local, Local>, +} + +impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) { + let new_local = self.copy_classes[*local]; + match ctxt { + // Do not modify the local in storage statements. + PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {} + // The local should have been marked as non-SSA. + PlaceContext::MutatingUse(_) => assert_eq!(*local, new_local), + // We access the value. + _ => *local = new_local, + } + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) { + if let Some(new_projection) = self.process_projection(&place.projection, loc) { + place.projection = self.tcx().intern_place_elems(&new_projection); + } + + let observes_address = match ctxt { + PlaceContext::NonMutatingUse( + NonMutatingUseContext::SharedBorrow + | NonMutatingUseContext::ShallowBorrow + | NonMutatingUseContext::UniqueBorrow + | NonMutatingUseContext::AddressOf, + ) => true, + // For debuginfo, merging locals is ok. + PlaceContext::NonUse(NonUseContext::VarDebugInfo) => { + self.borrowed_locals.contains(place.local) + } + _ => false, + }; + if observes_address && !place.is_indirect() { + // We observe the address of `place.local`. Do not replace it. + } else { + self.visit_local( + &mut place.local, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + loc, + ) + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { + if let Operand::Move(place) = *operand + && let Some(local) = place.as_local() + && !self.fully_moved.contains(local) + { + *operand = Operand::Copy(place); + } + self.super_operand(operand, loc); + } + + fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) { + if let StatementKind::StorageDead(l) = stmt.kind + && self.storage_to_remove.contains(l) + { + stmt.make_nop(); + } else if let StatementKind::Assign(box (ref place, ref mut rvalue)) = stmt.kind + && place.as_local().is_some() + { + // Do not replace assignments. + self.visit_rvalue(rvalue, loc) + } else { + self.super_statement(stmt, loc); + } + } +} diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 45de0c28035..658e01d9310 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -520,7 +520,7 @@ impl<'a> BcbCounters<'a> { let mut found_loop_exit = false; for &branch in branches.iter() { if backedge_from_bcbs.iter().any(|&backedge_from_bcb| { - self.bcb_is_dominated_by(backedge_from_bcb, branch.target_bcb) + self.bcb_dominates(branch.target_bcb, backedge_from_bcb) }) { if let Some(reloop_branch) = some_reloop_branch { if reloop_branch.counter(&self.basic_coverage_blocks).is_none() { @@ -603,8 +603,8 @@ impl<'a> BcbCounters<'a> { } #[inline] - fn bcb_is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool { - self.basic_coverage_blocks.is_dominated_by(node, dom) + fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { + self.basic_coverage_blocks.dominates(dom, node) } #[inline] diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 78d28f1ebab..a2671eef2e9 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -209,8 +209,8 @@ impl CoverageGraph { } #[inline(always)] - pub fn is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool { - self.dominators.as_ref().unwrap().is_dominated_by(node, dom) + pub fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { + self.dominators.as_ref().unwrap().dominates(dom, node) } #[inline(always)] @@ -312,7 +312,7 @@ rustc_index::newtype_index! { /// to the BCB's primary counter or expression). /// /// The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based -/// queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow) +/// queries (`dominates()`, `predecessors`, `successors`, etc.) have branch (control flow) /// significance. #[derive(Debug, Clone)] pub(super) struct BasicCoverageBlockData { @@ -594,7 +594,7 @@ impl TraverseCoverageGraphWithLoops { // branching block would have given an `Expression` (or vice versa). let (some_successor_to_add, some_loop_header) = if let Some((_, loop_header)) = context.loop_backedges { - if basic_coverage_blocks.is_dominated_by(successor, loop_header) { + if basic_coverage_blocks.dominates(loop_header, successor) { (Some(successor), Some(loop_header)) } else { (None, None) @@ -666,15 +666,15 @@ pub(super) fn find_loop_backedges( // // The overall complexity appears to be comparable to many other MIR transform algorithms, and I // don't expect that this function is creating a performance hot spot, but if this becomes an - // issue, there may be ways to optimize the `is_dominated_by` algorithm (as indicated by an + // issue, there may be ways to optimize the `dominates` algorithm (as indicated by an // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short - // circuit downstream `is_dominated_by` checks. + // circuit downstream `dominates` checks. // // For now, that kind of optimization seems unnecessarily complicated. for (bcb, _) in basic_coverage_blocks.iter_enumerated() { for &successor in &basic_coverage_blocks.successors[bcb] { - if basic_coverage_blocks.is_dominated_by(bcb, successor) { + if basic_coverage_blocks.dominates(successor, bcb) { let loop_header = successor; let backedge_from_bcb = bcb; debug!( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 1468afc6456..9a617159813 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -540,7 +540,8 @@ fn fn_sig_and_body( // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + let (_, fn_body_id) = + hir::map::associated_body(hir_node).expect("HIR node is a function with body"); (hir_node.fn_sig(), tcx.hir().body(fn_body_id)) } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index c5434840453..f973c1ed28f 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -63,7 +63,7 @@ impl CoverageStatement { /// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that /// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches /// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock` -/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`. +/// `dominates()` the `BasicBlock`s in this `CoverageSpan`. #[derive(Debug, Clone)] pub(super) struct CoverageSpan { pub span: Span, @@ -705,12 +705,12 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { fn hold_pending_dups_unless_dominated(&mut self) { // Equal coverage spans are ordered by dominators before dominated (if any), so it should be // impossible for `curr` to dominate any previous `CoverageSpan`. - debug_assert!(!self.span_bcb_is_dominated_by(self.prev(), self.curr())); + debug_assert!(!self.span_bcb_dominates(self.curr(), self.prev())); let initial_pending_count = self.pending_dups.len(); if initial_pending_count > 0 { let mut pending_dups = self.pending_dups.split_off(0); - pending_dups.retain(|dup| !self.span_bcb_is_dominated_by(self.curr(), dup)); + pending_dups.retain(|dup| !self.span_bcb_dominates(dup, self.curr())); self.pending_dups.append(&mut pending_dups); if self.pending_dups.len() < initial_pending_count { debug!( @@ -721,7 +721,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } } - if self.span_bcb_is_dominated_by(self.curr(), self.prev()) { + if self.span_bcb_dominates(self.prev(), self.curr()) { debug!( " different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}", self.prev() @@ -787,8 +787,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } } - fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &CoverageSpan) -> bool { - self.basic_coverage_blocks.is_dominated_by(covspan.bcb, dom_covspan.bcb) + fn span_bcb_dominates(&self, dom_covspan: &CoverageSpan, covspan: &CoverageSpan) -> bool { + self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb) } } @@ -802,6 +802,8 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> | StatementKind::StorageDead(_) // Coverage should not be encountered, but don't inject coverage coverage | StatementKind::Coverage(_) + // Ignore `ConstEvalCounter`s + | StatementKind::ConstEvalCounter // Ignore `Nop`s | StatementKind::Nop => None, diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs new file mode 100644 index 00000000000..7d127032179 --- /dev/null +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -0,0 +1,59 @@ +//! A pass that inserts the `ConstEvalCounter` instruction into any blocks that have a back edge +//! (thus indicating there is a loop in the CFG), or whose terminator is a function call. +use crate::MirPass; + +use rustc_data_structures::graph::dominators::Dominators; +use rustc_middle::mir::{ + BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind, +}; +use rustc_middle::ty::TyCtxt; + +pub struct CtfeLimit; + +impl<'tcx> MirPass<'tcx> for CtfeLimit { + #[instrument(skip(self, _tcx, body))] + fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let doms = body.basic_blocks.dominators(); + let indices: Vec<BasicBlock> = body + .basic_blocks + .iter_enumerated() + .filter_map(|(node, node_data)| { + if matches!(node_data.terminator().kind, TerminatorKind::Call { .. }) + // Back edges in a CFG indicate loops + || has_back_edge(&doms, node, &node_data) + { + Some(node) + } else { + None + } + }) + .collect(); + for index in indices { + insert_counter( + body.basic_blocks_mut() + .get_mut(index) + .expect("basic_blocks index {index} should exist"), + ); + } + } +} + +fn has_back_edge( + doms: &Dominators<BasicBlock>, + node: BasicBlock, + node_data: &BasicBlockData<'_>, +) -> bool { + if !doms.is_reachable(node) { + return false; + } + // Check if any of the dominators of the node are also the node's successor. + doms.dominators(node) + .any(|dom| node_data.terminator().successors().into_iter().any(|succ| succ == dom)) +} + +fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) { + basic_block_data.statements.push(Statement { + source_info: basic_block_data.terminator().source_info, + kind: StatementKind::ConstEvalCounter, + }); +} diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 09546330cec..9dbfb089dc6 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -53,6 +53,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::StorageDead(_) | StatementKind::Coverage(_) | StatementKind::Intrinsic(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop => (), StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 08e296a8371..5c5baa68e58 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -328,7 +328,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { match &statement.kind { StatementKind::Assign(box (dest, rvalue)) => { match rvalue { - Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { + Rvalue::CopyForDeref(place) + | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { // These might've been turned into self-assignments by the replacement // (this includes the original statement we wanted to eliminate). if dest == place { @@ -577,6 +578,7 @@ impl WriteInfo { self.add_place(**place); } StatementKind::Intrinsic(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop | StatementKind::Coverage(_) | StatementKind::StorageLive(_) @@ -754,7 +756,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { if let StatementKind::Assign(box ( lhs, - Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), + Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), )) = &statement.kind { let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else { diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index b708d780b70..aa19b1fdb5e 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -79,7 +79,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { for bound in bounds { if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) { // Get the argument types as they appear in the function signature. - let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); + let arg_defs = self.tcx.fn_sig(def_id).subst_identity().skip_binder().inputs(); for (arg_num, arg_def) in arg_defs.iter().enumerate() { // For all types reachable from the argument type in the fn sig for generic_inner_ty in arg_def.walk() { @@ -161,7 +161,8 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { .as_ref() .assert_crate_local() .lint_root; - let fn_sig = self.tcx.fn_sig(fn_id); + // FIXME: use existing printing routines to print the function signature + let fn_sig = self.tcx.fn_sig(fn_id).subst(self.tcx, fn_substs); let unsafety = fn_sig.unsafety().prefix_str(); let abi = match fn_sig.abi() { Abi::Rust => String::from(""), diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 39c61a34afc..5624e312da1 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -54,7 +54,8 @@ use crate::deref_separator::deref_finder; use crate::simplify; use crate::util::expand_aggregate; use crate::MirPass; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir::GeneratorKind; @@ -70,6 +71,9 @@ use rustc_mir_dataflow::impls::{ }; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{self, Analysis}; +use rustc_span::def_id::DefId; +use rustc_span::symbol::sym; +use rustc_span::Span; use rustc_target::abi::VariantIdx; use rustc_target::spec::PanicStrategy; use std::{iter, ops}; @@ -854,7 +858,7 @@ fn sanitize_witness<'tcx>( body: &Body<'tcx>, witness: Ty<'tcx>, upvars: Vec<Ty<'tcx>>, - saved_locals: &GeneratorSavedLocals, + layout: &GeneratorLayout<'tcx>, ) { let did = body.source.def_id(); let param_env = tcx.param_env(did); @@ -873,31 +877,36 @@ fn sanitize_witness<'tcx>( } }; - for (local, decl) in body.local_decls.iter_enumerated() { - // Ignore locals which are internal or not saved between yields. - if !saved_locals.contains(local) || decl.internal { + let mut mismatches = Vec::new(); + for fty in &layout.field_tys { + if fty.ignore_for_traits { continue; } - let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); + let decl_ty = tcx.normalize_erasing_regions(param_env, fty.ty); // Sanity check that typeck knows about the type of locals which are // live across a suspension point if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) { - span_bug!( - body.span, - "Broken MIR: generator contains type {} in MIR, \ - but typeck only knows about {} and {:?}", - decl_ty, - allowed, - allowed_upvars - ); + mismatches.push(decl_ty); } } + + if !mismatches.is_empty() { + span_bug!( + body.span, + "Broken MIR: generator contains type {:?} in MIR, \ + but typeck only knows about {} and {:?}", + mismatches, + allowed, + allowed_upvars + ); + } } fn compute_layout<'tcx>( + tcx: TyCtxt<'tcx>, liveness: LivenessInfo, - body: &mut Body<'tcx>, + body: &Body<'tcx>, ) -> ( FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>, GeneratorLayout<'tcx>, @@ -915,9 +924,33 @@ fn compute_layout<'tcx>( let mut locals = IndexVec::<GeneratorSavedLocal, _>::new(); let mut tys = IndexVec::<GeneratorSavedLocal, _>::new(); for (saved_local, local) in saved_locals.iter_enumerated() { - locals.push(local); - tys.push(body.local_decls[local].ty); debug!("generator saved local {:?} => {:?}", saved_local, local); + + locals.push(local); + let decl = &body.local_decls[local]; + debug!(?decl); + + let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir { + match decl.local_info { + // Do not include raw pointers created from accessing `static` items, as those could + // well be re-created by another access to the same static. + Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local, + // Fake borrows are only read by fake reads, so do not have any reality in + // post-analysis MIR. + Some(box LocalInfo::FakeBorrow) => true, + _ => false, + } + } else { + // FIXME(#105084) HIR-based drop tracking does not account for all the temporaries that + // MIR building may introduce. This leads to wrongly ignored types, but this is + // necessary for internal consistency and to avoid ICEs. + decl.internal + }; + let decl = + GeneratorSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits }; + debug!(?decl); + + tys.push(decl); } // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. @@ -947,7 +980,7 @@ fn compute_layout<'tcx>( // just use the first one here. That's fine; fields do not move // around inside generators, so it doesn't matter which variant // index we access them by. - remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx)); + remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx)); } variant_fields.push(fields); variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); @@ -957,6 +990,7 @@ fn compute_layout<'tcx>( let layout = GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; + debug!(?layout); (remap, layout, storage_liveness) } @@ -1351,6 +1385,42 @@ fn create_cases<'tcx>( .collect() } +#[instrument(level = "debug", skip(tcx), ret)] +pub(crate) fn mir_generator_witnesses<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> GeneratorLayout<'tcx> { + assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); + let def_id = def_id.expect_local(); + + let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id)); + let body = body.borrow(); + let body = &*body; + + // The first argument is the generator type passed by value + let gen_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; + + // Get the interior types and substs which typeck computed + let movable = match *gen_ty.kind() { + ty::Generator(_, _, movability) => movability == hir::Movability::Movable, + _ => span_bug!(body.span, "unexpected generator type {}", gen_ty), + }; + + // When first entering the generator, move the resume argument into its new local. + let always_live_locals = always_storage_live_locals(&body); + + let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); + + // Extract locals which are live across suspension point into `layout` + // `remap` gives a mapping from local indices onto generator struct indices + // `storage_liveness` tells us which locals have live storage at suspension points + let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body); + + check_suspend_tys(tcx, &generator_layout, &body); + + generator_layout +} + impl<'tcx> MirPass<'tcx> for StateTransform { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Some(yield_ty) = body.yield_ty() else { @@ -1363,14 +1433,14 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // The first argument is the generator type passed by value let gen_ty = body.local_decls.raw[1].ty; - // Get the interior types and substs which typeck computed - let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() { + // Get the discriminant type and substs which typeck computed + let (discr_ty, upvars, interior, movable) = match *gen_ty.kind() { ty::Generator(_, substs, movability) => { let substs = substs.as_generator(); ( - substs.upvar_tys().collect(), - substs.witness(), substs.discr_ty(tcx), + substs.upvar_tys().collect::<Vec<_>>(), + substs.witness(), movability == hir::Movability::Movable, ) } @@ -1434,8 +1504,6 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); - sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); - if tcx.sess.opts.unstable_opts.validate_mir { let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { assigned_local: None, @@ -1449,7 +1517,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // Extract locals which are live across suspension point into `layout` // `remap` gives a mapping from local indices onto generator struct indices // `storage_liveness` tells us which locals have live storage at suspension points - let (remap, layout, storage_liveness) = compute_layout(liveness_info, body); + let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body); + + if tcx.sess.opts.unstable_opts.validate_mir + && !tcx.sess.opts.unstable_opts.drop_tracking_mir + { + sanitize_witness(tcx, body, interior, upvars, &layout); + } let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); @@ -1583,6 +1657,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} } } @@ -1631,3 +1706,212 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { } } } + +fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &GeneratorLayout<'tcx>, body: &Body<'tcx>) { + let mut linted_tys = FxHashSet::default(); + + // We want a user-facing param-env. + let param_env = tcx.param_env(body.source.def_id()); + + for (variant, yield_source_info) in + layout.variant_fields.iter().zip(&layout.variant_source_info) + { + debug!(?variant); + for &local in variant { + let decl = &layout.field_tys[local]; + debug!(?decl); + + if !decl.ignore_for_traits && linted_tys.insert(decl.ty) { + let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else { continue }; + + check_must_not_suspend_ty( + tcx, + decl.ty, + hir_id, + param_env, + SuspendCheckData { + source_span: decl.source_info.span, + yield_span: yield_source_info.span, + plural_len: 1, + ..Default::default() + }, + ); + } + } + } +} + +#[derive(Default)] +struct SuspendCheckData<'a> { + source_span: Span, + yield_span: Span, + descr_pre: &'a str, + descr_post: &'a str, + plural_len: usize, +} + +// Returns whether it emitted a diagnostic or not +// Note that this fn and the proceeding one are based on the code +// for creating must_use diagnostics +// +// Note that this technique was chosen over things like a `Suspend` marker trait +// as it is simpler and has precedent in the compiler +fn check_must_not_suspend_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + hir_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + data: SuspendCheckData<'_>, +) -> bool { + if ty.is_unit() { + return false; + } + + let plural_suffix = pluralize!(data.plural_len); + + debug!("Checking must_not_suspend for {}", ty); + + match *ty.kind() { + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre = &format!("{}boxed ", data.descr_pre); + check_must_not_suspend_ty( + tcx, + boxed_ty, + hir_id, + param_env, + SuspendCheckData { descr_pre, ..data }, + ) + } + ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), + // FIXME: support adding the attribute to TAITs + ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { + let mut has_emitted = false; + for &(predicate, _) in tcx.explicit_item_bounds(def) { + // We only look at the `DefId`, so it is safe to skip the binder here. + if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = + predicate.kind().skip_binder() + { + let def_id = poly_trait_predicate.trait_ref.def_id; + let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); + if check_must_not_suspend_def( + tcx, + def_id, + hir_id, + SuspendCheckData { descr_pre, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Dynamic(binder, _, _) => { + let mut has_emitted = false; + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + let def_id = trait_ref.def_id; + let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); + if check_must_not_suspend_def( + tcx, + def_id, + hir_id, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Tuple(fields) => { + let mut has_emitted = false; + for (i, ty) in fields.iter().enumerate() { + let descr_post = &format!(" in tuple element {i}"); + if check_must_not_suspend_ty( + tcx, + ty, + hir_id, + param_env, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + } + } + has_emitted + } + ty::Array(ty, len) => { + let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + tcx, + ty, + hir_id, + param_env, + SuspendCheckData { + descr_pre, + plural_len: len.try_eval_usize(tcx, param_env).unwrap_or(0) as usize + 1, + ..data + }, + ) + } + // If drop tracking is enabled, we want to look through references, since the referrent + // may not be considered live across the await point. + ty::Ref(_region, ty, _mutability) => { + let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + tcx, + ty, + hir_id, + param_env, + SuspendCheckData { descr_pre, ..data }, + ) + } + _ => false, + } +} + +fn check_must_not_suspend_def( + tcx: TyCtxt<'_>, + def_id: DefId, + hir_id: hir::HirId, + data: SuspendCheckData<'_>, +) -> bool { + if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) { + let msg = format!( + "{}`{}`{} held across a suspend point, but should not be", + data.descr_pre, + tcx.def_path_str(def_id), + data.descr_post, + ); + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::MUST_NOT_SUSPEND, + hir_id, + data.source_span, + msg, + |lint| { + // add span pointing to the offending yield/await + lint.span_label(data.yield_span, "the value is held across this suspend point"); + + // Add optional reason note + if let Some(note) = attr.value_str() { + // FIXME(guswynn): consider formatting this better + lint.span_note(data.source_span, note.as_str()); + } + + // Add some quick suggestions on what to do + // FIXME: can `drop` work as a suggestion here as well? + lint.span_help( + data.source_span, + "consider using a block (`{ ... }`) \ + to shrink the value's scope, ending before the suspend point", + ) + }, + ); + + true + } else { + false + } +} diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 28c9080d38d..84640b703c8 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -331,7 +331,7 @@ impl<'tcx> Inliner<'tcx> { return None; } - let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs); + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); let source_info = SourceInfo { span: fn_span, ..terminator.source_info }; return Some(CallSite { callee, fn_sig, block: bb, target, source_info }); @@ -947,12 +947,12 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { return; }; - let Some(&f_ty) = layout.field_tys.get(local) else { + let Some(f_ty) = layout.field_tys.get(local) else { self.validation = Err("malformed MIR"); return; }; - f_ty + f_ty.ty } else { let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { self.validation = Err("malformed MIR"); diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index 2f3c65869ef..e1faa7a08d9 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -6,7 +6,8 @@ use rustc_middle::mir::{ BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp, }; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, layout::TyAndLayout, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt}; +use rustc_span::symbol::{sym, Symbol}; pub struct InstCombine; @@ -16,7 +17,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let ctx = InstCombineContext { tcx, local_decls: &body.local_decls }; + let ctx = InstCombineContext { + tcx, + local_decls: &body.local_decls, + param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()), + }; for block in body.basic_blocks.as_mut() { for statement in block.statements.iter_mut() { match statement.kind { @@ -33,6 +38,10 @@ impl<'tcx> MirPass<'tcx> for InstCombine { &mut block.terminator.as_mut().unwrap(), &mut block.statements, ); + ctx.combine_intrinsic_assert( + &mut block.terminator.as_mut().unwrap(), + &mut block.statements, + ); } } } @@ -40,6 +49,7 @@ impl<'tcx> MirPass<'tcx> for InstCombine { struct InstCombineContext<'tcx, 'a> { tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, + param_env: ParamEnv<'tcx>, } impl<'tcx> InstCombineContext<'tcx, '_> { @@ -200,4 +210,76 @@ impl<'tcx> InstCombineContext<'tcx, '_> { }); terminator.kind = TerminatorKind::Goto { target: destination_block }; } + + fn combine_intrinsic_assert( + &self, + terminator: &mut Terminator<'tcx>, + _statements: &mut Vec<Statement<'tcx>>, + ) { + let TerminatorKind::Call { func, target, .. } = &mut terminator.kind else { return; }; + let Some(target_block) = target else { return; }; + let func_ty = func.ty(self.local_decls, self.tcx); + let Some((intrinsic_name, substs)) = resolve_rust_intrinsic(self.tcx, func_ty) else { + return; + }; + // The intrinsics we are interested in have one generic parameter + if substs.is_empty() { + return; + } + let ty = substs.type_at(0); + + // Check this is a foldable intrinsic before we query the layout of our generic parameter + let Some(assert_panics) = intrinsic_assert_panics(intrinsic_name) else { return; }; + let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else { return; }; + if assert_panics(self.tcx, self.param_env.and(layout)) { + // If we know the assert panics, indicate to later opts that the call diverges + *target = None; + } else { + // If we know the assert does not panic, turn the call into a Goto + terminator.kind = TerminatorKind::Goto { target: *target_block }; + } + } +} + +fn intrinsic_assert_panics<'tcx>( + intrinsic_name: Symbol, +) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool> { + fn inhabited_predicate<'tcx>( + _tcx: TyCtxt<'tcx>, + param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>, + ) -> bool { + let (_param_env, layout) = param_env_and_layout.into_parts(); + layout.abi.is_uninhabited() + } + fn zero_valid_predicate<'tcx>( + tcx: TyCtxt<'tcx>, + param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>, + ) -> bool { + !tcx.permits_zero_init(param_env_and_layout) + } + fn mem_uninitialized_valid_predicate<'tcx>( + tcx: TyCtxt<'tcx>, + param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>, + ) -> bool { + !tcx.permits_uninit_init(param_env_and_layout) + } + + match intrinsic_name { + sym::assert_inhabited => Some(inhabited_predicate), + sym::assert_zero_valid => Some(zero_valid_predicate), + sym::assert_mem_uninitialized_valid => Some(mem_uninitialized_valid_predicate), + _ => None, + } +} + +fn resolve_rust_intrinsic<'tcx>( + tcx: TyCtxt<'tcx>, + func_ty: Ty<'tcx>, +) -> Option<(Symbol, SubstsRef<'tcx>)> { + if let ty::FnDef(def_id, substs) = *func_ty.kind() { + if tcx.is_intrinsic(def_id) { + return Some((tcx.item_name(def_id), substs)); + } + } + None } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 20b7fdcfe6d..cbebca15483 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -54,7 +54,9 @@ mod const_debuginfo; mod const_goto; mod const_prop; mod const_prop_lint; +mod copy_prop; mod coverage; +mod ctfe_limit; mod dataflow_const_prop; mod dead_store_elimination; mod deaggregator; @@ -86,11 +88,11 @@ mod required_consts; mod reveal_all; mod separate_const_switch; mod shim; +mod ssa; // This pass is public to allow external drivers to perform MIR cleanup pub mod simplify; mod simplify_branches; mod simplify_comparison_integral; -mod simplify_try; mod sroa; mod uninhabited_enum_branching; mod unreachable_prop; @@ -102,7 +104,6 @@ use rustc_mir_dataflow::rustc_peek; pub fn provide(providers: &mut Providers) { check_unsafety::provide(providers); - check_packed_ref::provide(providers); coverage::query::provide(providers); ffi_unwind_calls::provide(providers); shim::provide(providers); @@ -124,6 +125,7 @@ pub fn provide(providers: &mut Providers) { mir_drops_elaborated_and_const_checked, mir_for_ctfe, mir_for_ctfe_of_const_arg, + mir_generator_witnesses: generator::mir_generator_witnesses, optimized_mir, is_mir_available, is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), @@ -410,6 +412,8 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) - } } + pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None); + debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); body @@ -426,6 +430,9 @@ fn mir_drops_elaborated_and_const_checked( return tcx.mir_drops_elaborated_and_const_checked(def); } + if tcx.generator_kind(def.did).is_some() && tcx.sess.opts.unstable_opts.drop_tracking_mir { + tcx.ensure().mir_generator_witnesses(def.did); + } let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def); let is_fn_like = tcx.def_kind(def.did).is_fn_like(); @@ -541,13 +548,13 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &[ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode. &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first - &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")), &inline::Inline, &remove_storage_markers::RemoveStorageMarkers, &remove_zsts::RemoveZsts, + &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &const_goto::ConstGoto, &remove_unneeded_drops::RemoveUnneededDrops, &sroa::ScalarReplacementOfAggregates, @@ -557,6 +564,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &instcombine::InstCombine, &separate_const_switch::SeparateConstSwitch, &simplify::SimplifyLocals::new("before-const-prop"), + ©_prop::CopyProp, // // FIXME(#70073): This pass is responsible for both optimization as well as some lints. &const_prop::ConstProp, @@ -567,8 +575,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")), &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, - &simplify_try::SimplifyArmIdentity, - &simplify_try::SimplifyBranchSame, &dead_store_elimination::DeadStoreElimination, &dest_prop::DestinationPropagation, &o1(simplify_branches::SimplifyConstCondition::new("final")), diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 1708b287e56..b36c8a0bd53 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -1,288 +1,104 @@ //! This pass eliminates casting of arrays into slices when their length //! is taken using `.len()` method. Handy to preserve information in MIR for const prop +use crate::ssa::SsaLocals; use crate::MirPass; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::intern::Interned; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ReErased, Region, TyCtxt}; - -const MAX_NUM_BLOCKS: usize = 800; -const MAX_NUM_LOCALS: usize = 3000; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_mir_dataflow::impls::borrowed_locals; pub struct NormalizeArrayLen; impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // See #105929 - sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts + sess.mir_opt_level() >= 3 } + #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // early returns for edge cases of highly unrolled functions - if body.basic_blocks.len() > MAX_NUM_BLOCKS { - return; - } - if body.local_decls.len() > MAX_NUM_LOCALS { - return; - } + debug!(def_id = ?body.source.def_id()); normalize_array_len_calls(tcx, body) } } -pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // We don't ever touch terminators, so no need to invalidate the CFG cache - let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); - let local_decls = &mut body.local_decls; +fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let borrowed_locals = borrowed_locals(body); + let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals); - // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]` - let mut interesting_locals = BitSet::new_empty(local_decls.len()); - for (local, decl) in local_decls.iter_enumerated() { - match decl.ty.kind() { - ty::Array(..) => { - interesting_locals.insert(local); - } - ty::Ref(.., ty, Mutability::Not) => match ty.kind() { - ty::Array(..) => { - interesting_locals.insert(local); - } - _ => {} - }, - _ => {} - } - } - if interesting_locals.is_empty() { - // we have found nothing to analyze - return; - } - let num_intesting_locals = interesting_locals.count(); - let mut state = FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - let mut patches_scratchpad = - FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - let mut replacements_scratchpad = - FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - for block in basic_blocks { - // make length calls for arrays [T; N] not to decay into length calls for &[T] - // that forbids constant propagation - normalize_array_len_call( - tcx, - block, - local_decls, - &interesting_locals, - &mut state, - &mut patches_scratchpad, - &mut replacements_scratchpad, - ); - state.clear(); - patches_scratchpad.clear(); - replacements_scratchpad.clear(); - } -} + let slice_lengths = compute_slice_length(tcx, &ssa, body); + debug!(?slice_lengths); -struct Patcher<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - patches_scratchpad: &'a FxIndexMap<usize, usize>, - replacements_scratchpad: &'a mut FxIndexMap<usize, Local>, - local_decls: &'a mut IndexVec<Local, LocalDecl<'tcx>>, - statement_idx: usize, + Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body); } -impl<'tcx> Patcher<'_, 'tcx> { - fn patch_expand_statement( - &mut self, - statement: &mut Statement<'tcx>, - ) -> Option<std::vec::IntoIter<Statement<'tcx>>> { - let idx = self.statement_idx; - if let Some(len_statemnt_idx) = self.patches_scratchpad.get(&idx).copied() { - let mut statements = Vec::with_capacity(2); - - // we are at statement that performs a cast. The only sound way is - // to create another local that performs a similar copy without a cast and then - // use this copy in the Len operation - - match &statement.kind { - StatementKind::Assign(box ( - .., - Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), - operand, - _, - ), - )) => { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - // create new local - let ty = operand.ty(self.local_decls, self.tcx); - let local_decl = LocalDecl::with_source_info(ty, statement.source_info); - let local = self.local_decls.push(local_decl); - // make it live - let mut make_live_statement = statement.clone(); - make_live_statement.kind = StatementKind::StorageLive(local); - statements.push(make_live_statement); - // copy into it - - let operand = Operand::Copy(*place); - let mut make_copy_statement = statement.clone(); - let assign_to = Place::from(local); - let rvalue = Rvalue::Use(operand); - make_copy_statement.kind = - StatementKind::Assign(Box::new((assign_to, rvalue))); - statements.push(make_copy_statement); - - // to reorder we have to copy and make NOP - statements.push(statement.clone()); - statement.make_nop(); - - self.replacements_scratchpad.insert(len_statemnt_idx, local); - } - _ => { - unreachable!("it's a bug in the implementation") - } - } - } - _ => { - unreachable!("it's a bug in the implementation") +fn compute_slice_length<'tcx>( + tcx: TyCtxt<'tcx>, + ssa: &SsaLocals, + body: &Body<'tcx>, +) -> IndexVec<Local, Option<ty::Const<'tcx>>> { + let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls); + + for (local, rvalue) in ssa.assignments(body) { + match rvalue { + Rvalue::Cast( + CastKind::Pointer(ty::adjustment::PointerCast::Unsize), + operand, + cast_ty, + ) => { + let operand_ty = operand.ty(body, tcx); + debug!(?operand_ty); + if let Some(operand_ty) = operand_ty.builtin_deref(true) + && let ty::Array(_, len) = operand_ty.ty.kind() + && let Some(cast_ty) = cast_ty.builtin_deref(true) + && let ty::Slice(..) = cast_ty.ty.kind() + { + slice_lengths[local] = Some(*len); } } - - self.statement_idx += 1; - - Some(statements.into_iter()) - } else if let Some(local) = self.replacements_scratchpad.get(&idx).copied() { - let mut statements = Vec::with_capacity(2); - - match &statement.kind { - StatementKind::Assign(box (into, Rvalue::Len(place))) => { - let add_deref = if let Some(..) = place.as_local() { - false - } else if let Some(..) = place.local_or_deref_local() { - true - } else { - unreachable!("it's a bug in the implementation") - }; - // replace len statement - let mut len_statement = statement.clone(); - let mut place = Place::from(local); - if add_deref { - place = self.tcx.mk_place_deref(place); - } - len_statement.kind = - StatementKind::Assign(Box::new((*into, Rvalue::Len(place)))); - statements.push(len_statement); - - // make temporary dead - let mut make_dead_statement = statement.clone(); - make_dead_statement.kind = StatementKind::StorageDead(local); - statements.push(make_dead_statement); - - // make original statement NOP - statement.make_nop(); + // The length information is stored in the fat pointer, so we treat `operand` as a value. + Rvalue::Use(operand) => { + if let Some(rhs) = operand.place() && let Some(rhs) = rhs.as_local() { + slice_lengths[local] = slice_lengths[rhs]; } - _ => { - unreachable!("it's a bug in the implementation") + } + // The length information is stored in the fat pointer. + // Reborrowing copies length information from one pointer to the other. + Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => { + if let [PlaceElem::Deref] = rhs.projection[..] { + slice_lengths[local] = slice_lengths[rhs.local]; } } - - self.statement_idx += 1; - - Some(statements.into_iter()) - } else { - self.statement_idx += 1; - None + _ => {} } } + + slice_lengths } -fn normalize_array_len_call<'tcx>( +struct Replacer<'tcx> { tcx: TyCtxt<'tcx>, - block: &mut BasicBlockData<'tcx>, - local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, - interesting_locals: &BitSet<Local>, - state: &mut FxIndexMap<Local, usize>, - patches_scratchpad: &mut FxIndexMap<usize, usize>, - replacements_scratchpad: &mut FxIndexMap<usize, Local>, -) { - for (statement_idx, statement) in block.statements.iter_mut().enumerate() { - match &mut statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - match rvalue { - Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), - operand, - cast_ty, - ) => { - let Some(local) = place.as_local() else { return }; - match operand { - Operand::Copy(place) | Operand::Move(place) => { - let Some(operand_local) = place.local_or_deref_local() else { return; }; - if !interesting_locals.contains(operand_local) { - return; - } - let operand_ty = local_decls[operand_local].ty; - match (operand_ty.kind(), cast_ty.kind()) { - (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { - if of_ty_src == of_ty_dst { - // this is a cast from [T; N] into [T], so we are good - state.insert(local, statement_idx); - } - } - // current way of patching doesn't allow to work with `mut` - ( - ty::Ref( - Region(Interned(ReErased, _)), - operand_ty, - Mutability::Not, - ), - ty::Ref( - Region(Interned(ReErased, _)), - cast_ty, - Mutability::Not, - ), - ) => { - match (operand_ty.kind(), cast_ty.kind()) { - // current way of patching doesn't allow to work with `mut` - (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { - if of_ty_src == of_ty_dst { - // this is a cast from [T; N] into [T], so we are good - state.insert(local, statement_idx); - } - } - _ => {} - } - } - _ => {} - } - } - _ => {} - } - } - Rvalue::Len(place) => { - let Some(local) = place.local_or_deref_local() else { - return; - }; - if let Some(cast_statement_idx) = state.get(&local).copied() { - patches_scratchpad.insert(cast_statement_idx, statement_idx); - } - } - _ => { - // invalidate - state.remove(&place.local); - } - } - } - _ => {} - } - } + slice_lengths: IndexVec<Local, Option<ty::Const<'tcx>>>, +} - let mut patcher = Patcher { - tcx, - patches_scratchpad: &*patches_scratchpad, - replacements_scratchpad, - local_decls, - statement_idx: 0, - }; +impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } - block.expand_statements(|st| patcher.patch_expand_statement(st)); + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) { + if let Rvalue::Len(place) = rvalue + && let [PlaceElem::Deref] = &place.projection[..] + && let Some(len) = self.slice_lengths[place.local] + { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant { + span: rustc_span::DUMMY_SP, + user_ty: None, + literal: ConstantKind::from_const(len, self.tcx), + }))); + } + self.super_rvalue(rvalue, loc); + } } diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index f1bbf2ea7e8..e3a03aa08af 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -35,6 +35,7 @@ impl RemoveNoopLandingPads { | StatementKind::StorageDead(_) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => { // These are all noops in a landing pad } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 2f116aaa958..a24d2d34d79 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -250,6 +250,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | StatementKind::Coverage(_) | StatementKind::StorageDead(_) | StatementKind::Intrinsic(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} } } @@ -318,6 +319,7 @@ fn find_determining_place<'tcx>( | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) | StatementKind::Intrinsic(_) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} // If the discriminant is set, it is always set diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index dace540fa29..8d4fe74e7d3 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -152,7 +152,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) } else { InternalSubsts::identity_for_item(tcx, def_id) }; - let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs); + let sig = tcx.fn_sig(def_id).subst(tcx, substs); let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); @@ -363,7 +363,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { // we must subst the self_ty because it's // otherwise going to be TySelf and we can't index // or access fields of a Place of type TySelf. - let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]); + let sig = tcx.fn_sig(def_id).subst(tcx, &[self_ty.into()]); let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); @@ -606,7 +606,7 @@ fn build_call_shim<'tcx>( }; let def_id = instance.def_id(); - let sig = tcx.bound_fn_sig(def_id); + let sig = tcx.fn_sig(def_id); let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig)); assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); @@ -798,7 +798,11 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let param_env = tcx.param_env(ctor_id); // Normalize the sig. - let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature"); + let sig = tcx + .fn_sig(ctor_id) + .subst_identity() + .no_bound_vars() + .expect("LBR in ADT constructor signature"); let sig = tcx.normalize_erasing_regions(param_env, sig); let ty::Adt(adt_def, substs) = sig.output().kind() else { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 8f6abe7a912..ced97b2c788 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -404,6 +404,18 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals { } } +pub fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) { + // First, we're going to get a count of *actual* uses for every `Local`. + let mut used_locals = UsedLocals::new(body); + + // Next, we're going to remove any `Local` with zero actual uses. When we remove those + // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` + // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from + // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a + // fixedpoint where there are no more unused locals. + remove_unused_definitions_helper(&mut used_locals, body); +} + pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { // First, we're going to get a count of *actual* uses for every `Local`. let mut used_locals = UsedLocals::new(body); @@ -413,7 +425,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a // fixedpoint where there are no more unused locals. - remove_unused_definitions(&mut used_locals, body); + remove_unused_definitions_helper(&mut used_locals, body); // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. let map = make_local_map(&mut body.local_decls, &used_locals); @@ -517,7 +529,7 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { self.super_statement(statement, location); } - StatementKind::Nop => {} + StatementKind::ConstEvalCounter | StatementKind::Nop => {} StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {} @@ -548,7 +560,7 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { } /// Removes unused definitions. Updates the used locals to reflect the changes made. -fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) { +fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Body<'_>) { // The use counts are updated as we remove the statements. A local might become unused // during the retain operation, leading to a temporary inconsistency (storage statements or // definitions referencing the local might remain). For correctness it is crucial that this diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs deleted file mode 100644 index e4f3ace9a93..00000000000 --- a/compiler/rustc_mir_transform/src/simplify_try.rs +++ /dev/null @@ -1,822 +0,0 @@ -//! The general point of the optimizations provided here is to simplify something like: -//! -//! ```rust -//! # fn foo<T, E>(x: Result<T, E>) -> Result<T, E> { -//! match x { -//! Ok(x) => Ok(x), -//! Err(x) => Err(x) -//! } -//! # } -//! ``` -//! -//! into just `x`. - -use crate::{simplify, MirPass}; -use itertools::Itertools as _; -use rustc_index::{bit_set::BitSet, vec::IndexVec}; -use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, List, Ty, TyCtxt}; -use rustc_target::abi::VariantIdx; -use std::iter::{once, Enumerate, Peekable}; -use std::slice::Iter; - -/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move. -/// -/// This is done by transforming basic blocks where the statements match: -/// -/// ```ignore (MIR) -/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY ); -/// _TMP_2 = _LOCAL_TMP; -/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2; -/// discriminant(_LOCAL_0) = VAR_IDX; -/// ``` -/// -/// into: -/// -/// ```ignore (MIR) -/// _LOCAL_0 = move _LOCAL_1 -/// ``` -pub struct SimplifyArmIdentity; - -#[derive(Debug)] -struct ArmIdentityInfo<'tcx> { - /// Storage location for the variant's field - local_temp_0: Local, - /// Storage location holding the variant being read from - local_1: Local, - /// The variant field being read from - vf_s0: VarField<'tcx>, - /// Index of the statement which loads the variant being read - get_variant_field_stmt: usize, - - /// Tracks each assignment to a temporary of the variant's field - field_tmp_assignments: Vec<(Local, Local)>, - - /// Storage location holding the variant's field that was read from - local_tmp_s1: Local, - /// Storage location holding the enum that we are writing to - local_0: Local, - /// The variant field being written to - vf_s1: VarField<'tcx>, - - /// Storage location that the discriminant is being written to - set_discr_local: Local, - /// The variant being written - set_discr_var_idx: VariantIdx, - - /// Index of the statement that should be overwritten as a move - stmt_to_overwrite: usize, - /// SourceInfo for the new move - source_info: SourceInfo, - - /// Indices of matching Storage{Live,Dead} statements encountered. - /// (StorageLive index,, StorageDead index, Local) - storage_stmts: Vec<(usize, usize, Local)>, - - /// The statements that should be removed (turned into nops) - stmts_to_remove: Vec<usize>, - - /// Indices of debug variables that need to be adjusted to point to - // `{local_0}.{dbg_projection}`. - dbg_info_to_adjust: Vec<usize>, - - /// The projection used to rewrite debug info. - dbg_projection: &'tcx List<PlaceElem<'tcx>>, -} - -fn get_arm_identity_info<'a, 'tcx>( - stmts: &'a [Statement<'tcx>], - locals_count: usize, - debug_info: &'a [VarDebugInfo<'tcx>], -) -> Option<ArmIdentityInfo<'tcx>> { - // This can't possibly match unless there are at least 3 statements in the block - // so fail fast on tiny blocks. - if stmts.len() < 3 { - return None; - } - - let mut tmp_assigns = Vec::new(); - let mut nop_stmts = Vec::new(); - let mut storage_stmts = Vec::new(); - let mut storage_live_stmts = Vec::new(); - let mut storage_dead_stmts = Vec::new(); - - type StmtIter<'a, 'tcx> = Peekable<Enumerate<Iter<'a, Statement<'tcx>>>>; - - fn is_storage_stmt(stmt: &Statement<'_>) -> bool { - matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_)) - } - - /// Eats consecutive Statements which match `test`, performing the specified `action` for each. - /// The iterator `stmt_iter` is not advanced if none were matched. - fn try_eat<'a, 'tcx>( - stmt_iter: &mut StmtIter<'a, 'tcx>, - test: impl Fn(&'a Statement<'tcx>) -> bool, - mut action: impl FnMut(usize, &'a Statement<'tcx>), - ) { - while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) { - let (idx, stmt) = stmt_iter.next().unwrap(); - - action(idx, stmt); - } - } - - /// Eats consecutive `StorageLive` and `StorageDead` Statements. - /// The iterator `stmt_iter` is not advanced if none were found. - fn try_eat_storage_stmts( - stmt_iter: &mut StmtIter<'_, '_>, - storage_live_stmts: &mut Vec<(usize, Local)>, - storage_dead_stmts: &mut Vec<(usize, Local)>, - ) { - try_eat(stmt_iter, is_storage_stmt, |idx, stmt| { - if let StatementKind::StorageLive(l) = stmt.kind { - storage_live_stmts.push((idx, l)); - } else if let StatementKind::StorageDead(l) = stmt.kind { - storage_dead_stmts.push((idx, l)); - } - }) - } - - fn is_tmp_storage_stmt(stmt: &Statement<'_>) -> bool { - use rustc_middle::mir::StatementKind::Assign; - if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind { - place.as_local().is_some() && p.as_local().is_some() - } else { - false - } - } - - /// Eats consecutive `Assign` Statements. - // The iterator `stmt_iter` is not advanced if none were found. - fn try_eat_assign_tmp_stmts( - stmt_iter: &mut StmtIter<'_, '_>, - tmp_assigns: &mut Vec<(Local, Local)>, - nop_stmts: &mut Vec<usize>, - ) { - try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| { - use rustc_middle::mir::StatementKind::Assign; - if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = - &stmt.kind - { - tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap())); - nop_stmts.push(idx); - } - }) - } - - fn find_storage_live_dead_stmts_for_local( - local: Local, - stmts: &[Statement<'_>], - ) -> Option<(usize, usize)> { - trace!("looking for {:?}", local); - let mut storage_live_stmt = None; - let mut storage_dead_stmt = None; - for (idx, stmt) in stmts.iter().enumerate() { - if stmt.kind == StatementKind::StorageLive(local) { - storage_live_stmt = Some(idx); - } else if stmt.kind == StatementKind::StorageDead(local) { - storage_dead_stmt = Some(idx); - } - } - - Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX))) - } - - // Try to match the expected MIR structure with the basic block we're processing. - // We want to see something that looks like: - // ``` - // (StorageLive(_) | StorageDead(_));* - // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY); - // (StorageLive(_) | StorageDead(_));* - // (tmp_n+1 = tmp_n);* - // (StorageLive(_) | StorageDead(_));* - // (tmp_n+1 = tmp_n);* - // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp; - // discriminant(LOCAL_FROM) = VariantIdx; - // (StorageLive(_) | StorageDead(_));* - // ``` - let mut stmt_iter = stmts.iter().enumerate().peekable(); - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - let (get_variant_field_stmt, stmt) = stmt_iter.next()?; - let (local_tmp_s0, local_1, vf_s0, dbg_projection) = match_get_variant_field(stmt)?; - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts); - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts); - - let (idx, stmt) = stmt_iter.next()?; - let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?; - nop_stmts.push(idx); - - let (idx, stmt) = stmt_iter.next()?; - let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?; - let discr_stmt_source_info = stmt.source_info; - nop_stmts.push(idx); - - try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts); - - for (live_idx, live_local) in storage_live_stmts { - if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) { - let (dead_idx, _) = storage_dead_stmts.swap_remove(i); - storage_stmts.push((live_idx, dead_idx, live_local)); - - if live_local == local_tmp_s0 { - nop_stmts.push(get_variant_field_stmt); - } - } - } - // We sort primitive usize here so we can use unstable sort - nop_stmts.sort_unstable(); - - // Use one of the statements we're going to discard between the point - // where the storage location for the variant field becomes live and - // is killed. - let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?; - let stmt_to_overwrite = - nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx); - - let mut tmp_assigned_vars = BitSet::new_empty(locals_count); - for (l, r) in &tmp_assigns { - tmp_assigned_vars.insert(*l); - tmp_assigned_vars.insert(*r); - } - - let dbg_info_to_adjust: Vec<_> = debug_info - .iter() - .enumerate() - .filter_map(|(i, var_info)| { - if let VarDebugInfoContents::Place(p) = var_info.value { - if tmp_assigned_vars.contains(p.local) { - return Some(i); - } - } - - None - }) - .collect(); - - Some(ArmIdentityInfo { - local_temp_0: local_tmp_s0, - local_1, - vf_s0, - get_variant_field_stmt, - field_tmp_assignments: tmp_assigns, - local_tmp_s1, - local_0, - vf_s1, - set_discr_local, - set_discr_var_idx, - stmt_to_overwrite: *stmt_to_overwrite?, - source_info: discr_stmt_source_info, - storage_stmts, - stmts_to_remove: nop_stmts, - dbg_info_to_adjust, - dbg_projection, - }) -} - -fn optimization_applies<'tcx>( - opt_info: &ArmIdentityInfo<'tcx>, - local_decls: &IndexVec<Local, LocalDecl<'tcx>>, - local_uses: &IndexVec<Local, usize>, - var_debug_info: &[VarDebugInfo<'tcx>], -) -> bool { - trace!("testing if optimization applies..."); - - // FIXME(wesleywiser): possibly relax this restriction? - if opt_info.local_0 == opt_info.local_1 { - trace!("NO: moving into ourselves"); - return false; - } else if opt_info.vf_s0 != opt_info.vf_s1 { - trace!("NO: the field-and-variant information do not match"); - return false; - } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty { - // FIXME(Centril,oli-obk): possibly relax to same layout? - trace!("NO: source and target locals have different types"); - return false; - } else if (opt_info.local_0, opt_info.vf_s0.var_idx) - != (opt_info.set_discr_local, opt_info.set_discr_var_idx) - { - trace!("NO: the discriminants do not match"); - return false; - } - - // Verify the assignment chain consists of the form b = a; c = b; d = c; etc... - if opt_info.field_tmp_assignments.is_empty() { - trace!("NO: no assignments found"); - return false; - } - let mut last_assigned_to = opt_info.field_tmp_assignments[0].1; - let source_local = last_assigned_to; - for (l, r) in &opt_info.field_tmp_assignments { - if *r != last_assigned_to { - trace!("NO: found unexpected assignment {:?} = {:?}", l, r); - return false; - } - - last_assigned_to = *l; - } - - // Check that the first and last used locals are only used twice - // since they are of the form: - // - // ``` - // _first = ((_x as Variant).n: ty); - // _n = _first; - // ... - // ((_y as Variant).n: ty) = _n; - // discriminant(_y) = z; - // ``` - for (l, r) in &opt_info.field_tmp_assignments { - if local_uses[*l] != 2 { - warn!("NO: FAILED assignment chain local {:?} was used more than twice", l); - return false; - } else if local_uses[*r] != 2 { - warn!("NO: FAILED assignment chain local {:?} was used more than twice", r); - return false; - } - } - - // Check that debug info only points to full Locals and not projections. - for dbg_idx in &opt_info.dbg_info_to_adjust { - let dbg_info = &var_debug_info[*dbg_idx]; - if let VarDebugInfoContents::Place(p) = dbg_info.value { - if !p.projection.is_empty() { - trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p); - return false; - } - } - } - - if source_local != opt_info.local_temp_0 { - trace!( - "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}", - source_local, - opt_info.local_temp_0 - ); - return false; - } else if last_assigned_to != opt_info.local_tmp_s1 { - trace!( - "NO: end of assignment chain does not match written enum temp: {:?} != {:?}", - last_assigned_to, - opt_info.local_tmp_s1 - ); - return false; - } - - trace!("SUCCESS: optimization applies!"); - true -} - -impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // FIXME(77359): This optimization can result in unsoundness. - if !tcx.sess.opts.unstable_opts.unsound_mir_opts { - return; - } - - let source = body.source; - trace!("running SimplifyArmIdentity on {:?}", source); - - let local_uses = LocalUseCounter::get_local_uses(body); - for bb in body.basic_blocks.as_mut() { - if let Some(opt_info) = - get_arm_identity_info(&bb.statements, body.local_decls.len(), &body.var_debug_info) - { - trace!("got opt_info = {:#?}", opt_info); - if !optimization_applies( - &opt_info, - &body.local_decls, - &local_uses, - &body.var_debug_info, - ) { - debug!("optimization skipped for {:?}", source); - continue; - } - - // Also remove unused Storage{Live,Dead} statements which correspond - // to temps used previously. - for (live_idx, dead_idx, local) in &opt_info.storage_stmts { - // The temporary that we've read the variant field into is scoped to this block, - // so we can remove the assignment. - if *local == opt_info.local_temp_0 { - bb.statements[opt_info.get_variant_field_stmt].make_nop(); - } - - for (left, right) in &opt_info.field_tmp_assignments { - if local == left || local == right { - bb.statements[*live_idx].make_nop(); - bb.statements[*dead_idx].make_nop(); - } - } - } - - // Right shape; transform - for stmt_idx in opt_info.stmts_to_remove { - bb.statements[stmt_idx].make_nop(); - } - - let stmt = &mut bb.statements[opt_info.stmt_to_overwrite]; - stmt.source_info = opt_info.source_info; - stmt.kind = StatementKind::Assign(Box::new(( - opt_info.local_0.into(), - Rvalue::Use(Operand::Move(opt_info.local_1.into())), - ))); - - bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop); - - // Fix the debug info to point to the right local - for dbg_index in opt_info.dbg_info_to_adjust { - let dbg_info = &mut body.var_debug_info[dbg_index]; - assert!( - matches!(dbg_info.value, VarDebugInfoContents::Place(_)), - "value was not a Place" - ); - if let VarDebugInfoContents::Place(p) = &mut dbg_info.value { - assert!(p.projection.is_empty()); - p.local = opt_info.local_0; - p.projection = opt_info.dbg_projection; - } - } - - trace!("block is now {:?}", bb.statements); - } - } - } -} - -struct LocalUseCounter { - local_uses: IndexVec<Local, usize>, -} - -impl LocalUseCounter { - fn get_local_uses(body: &Body<'_>) -> IndexVec<Local, usize> { - let mut counter = LocalUseCounter { local_uses: IndexVec::from_elem(0, &body.local_decls) }; - counter.visit_body(body); - counter.local_uses - } -} - -impl Visitor<'_> for LocalUseCounter { - fn visit_local(&mut self, local: Local, context: PlaceContext, _location: Location) { - if context.is_storage_marker() - || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) - { - return; - } - - self.local_uses[local] += 1; - } -} - -/// Match on: -/// ```ignore (MIR) -/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY); -/// ``` -fn match_get_variant_field<'tcx>( - stmt: &Statement<'tcx>, -) -> Option<(Local, Local, VarField<'tcx>, &'tcx List<PlaceElem<'tcx>>)> { - match &stmt.kind { - StatementKind::Assign(box ( - place_into, - Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)), - )) => { - let local_into = place_into.as_local()?; - let (local_from, vf) = match_variant_field_place(*pf)?; - Some((local_into, local_from, vf, pf.projection)) - } - _ => None, - } -} - -/// Match on: -/// ```ignore (MIR) -/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO; -/// ``` -fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> { - match &stmt.kind { - StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => { - let local_into = place_into.as_local()?; - let (local_from, vf) = match_variant_field_place(*place_from)?; - Some((local_into, local_from, vf)) - } - _ => None, - } -} - -/// Match on: -/// ```ignore (MIR) -/// discriminant(_LOCAL_TO_SET) = VAR_IDX; -/// ``` -fn match_set_discr(stmt: &Statement<'_>) -> Option<(Local, VariantIdx)> { - match &stmt.kind { - StatementKind::SetDiscriminant { place, variant_index } => { - Some((place.as_local()?, *variant_index)) - } - _ => None, - } -} - -#[derive(PartialEq, Debug)] -struct VarField<'tcx> { - field: Field, - field_ty: Ty<'tcx>, - var_idx: VariantIdx, -} - -/// Match on `((_LOCAL as Variant).FIELD: TY)`. -fn match_variant_field_place(place: Place<'_>) -> Option<(Local, VarField<'_>)> { - match place.as_ref() { - PlaceRef { - local, - projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)], - } => Some((local, VarField { field, field_ty: ty, var_idx })), - _ => None, - } -} - -/// Simplifies `SwitchInt(_) -> [targets]`, -/// where all the `targets` have the same form, -/// into `goto -> target_first`. -pub struct SimplifyBranchSame; - -impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // This optimization is disabled by default for now due to - // soundness concerns; see issue #89485 and PR #89489. - if !tcx.sess.opts.unstable_opts.unsound_mir_opts { - return; - } - - trace!("Running SimplifyBranchSame on {:?}", body.source); - let finder = SimplifyBranchSameOptimizationFinder { body, tcx }; - let opts = finder.find(); - - let did_remove_blocks = opts.len() > 0; - for opt in opts.iter() { - trace!("SUCCESS: Applying optimization {:?}", opt); - // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`. - body.basic_blocks_mut()[opt.bb_to_opt_terminator].terminator_mut().kind = - TerminatorKind::Goto { target: opt.bb_to_goto }; - } - - if did_remove_blocks { - // We have dead blocks now, so remove those. - simplify::remove_dead_blocks(tcx, body); - } - } -} - -#[derive(Debug)] -struct SimplifyBranchSameOptimization { - /// All basic blocks are equal so go to this one - bb_to_goto: BasicBlock, - /// Basic block where the terminator can be simplified to a goto - bb_to_opt_terminator: BasicBlock, -} - -struct SwitchTargetAndValue { - target: BasicBlock, - // None in case of the `otherwise` case - value: Option<u128>, -} - -struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> { - fn find(&self) -> Vec<SimplifyBranchSameOptimization> { - self.body - .basic_blocks - .iter_enumerated() - .filter_map(|(bb_idx, bb)| { - let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, .. } => { - let targets_and_values: Vec<_> = targets.iter() - .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) }) - .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None })) - .collect(); - (discr, targets_and_values) - }, - _ => return None, - }; - - // find the adt that has its discriminant read - // assuming this must be the last statement of the block - let adt_matched_on = match &bb.statements.last()?.kind { - StatementKind::Assign(box (place, rhs)) - if Some(*place) == discr_switched_on.place() => - { - match rhs { - Rvalue::Discriminant(adt_place) if adt_place.ty(self.body, self.tcx).ty.is_enum() => adt_place, - _ => { - trace!("NO: expected a discriminant read of an enum instead of: {:?}", rhs); - return None; - } - } - } - other => { - trace!("NO: expected an assignment of a discriminant read to a place. Found: {:?}", other); - return None - }, - }; - - let mut iter_bbs_reachable = targets_and_values - .iter() - .map(|target_and_value| (target_and_value, &self.body.basic_blocks[target_and_value.target])) - .filter(|(_, bb)| { - // Reaching `unreachable` is UB so assume it doesn't happen. - bb.terminator().kind != TerminatorKind::Unreachable - }) - .peekable(); - - let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx); - let mut all_successors_equivalent = StatementEquality::TrivialEqual; - - // All successor basic blocks must be equal or contain statements that are pairwise considered equal. - for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() { - let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup - && bb_l.terminator().kind == bb_r.terminator().kind - && bb_l.statements.len() == bb_r.statements.len(); - let statement_check = || { - bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| { - let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r); - if matches!(stmt_equality, StatementEquality::NotEqual) { - // short circuit - None - } else { - Some(acc.combine(&stmt_equality)) - } - }) - .unwrap_or(StatementEquality::NotEqual) - }; - if !trivial_checks { - all_successors_equivalent = StatementEquality::NotEqual; - break; - } - all_successors_equivalent = all_successors_equivalent.combine(&statement_check()); - }; - - match all_successors_equivalent{ - StatementEquality::TrivialEqual => { - // statements are trivially equal, so just take first - trace!("Statements are trivially equal"); - Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_first.target, - bb_to_opt_terminator: bb_idx, - }) - } - StatementEquality::ConsideredEqual(bb_to_choose) => { - trace!("Statements are considered equal"); - Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_to_choose, - bb_to_opt_terminator: bb_idx, - }) - } - StatementEquality::NotEqual => { - trace!("NO: not all successors of basic block {:?} were equivalent", bb_idx); - None - } - } - }) - .collect() - } - - /// Tests if two statements can be considered equal - /// - /// Statements can be trivially equal if the kinds match. - /// But they can also be considered equal in the following case A: - /// ```ignore (MIR) - /// discriminant(_0) = 0; // bb1 - /// _0 = move _1; // bb2 - /// ``` - /// In this case the two statements are equal iff - /// - `_0` is an enum where the variant index 0 is fieldless, and - /// - bb1 was targeted by a switch where the discriminant of `_1` was switched on - fn statement_equality( - &self, - adt_matched_on: Place<'tcx>, - x: &Statement<'tcx>, - x_target_and_value: &SwitchTargetAndValue, - y: &Statement<'tcx>, - y_target_and_value: &SwitchTargetAndValue, - ) -> StatementEquality { - let helper = |rhs: &Rvalue<'tcx>, - place: &Place<'tcx>, - variant_index: VariantIdx, - switch_value: u128, - side_to_choose| { - let place_type = place.ty(self.body, self.tcx).ty; - let adt = match *place_type.kind() { - ty::Adt(adt, _) if adt.is_enum() => adt, - _ => return StatementEquality::NotEqual, - }; - // We need to make sure that the switch value that targets the bb with - // SetDiscriminant is the same as the variant discriminant. - let variant_discr = adt.discriminant_for_variant(self.tcx, variant_index).val; - if variant_discr != switch_value { - trace!( - "NO: variant discriminant {} does not equal switch value {}", - variant_discr, - switch_value - ); - return StatementEquality::NotEqual; - } - let variant_is_fieldless = adt.variant(variant_index).fields.is_empty(); - if !variant_is_fieldless { - trace!("NO: variant {:?} was not fieldless", variant_index); - return StatementEquality::NotEqual; - } - - match rhs { - Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { - StatementEquality::ConsideredEqual(side_to_choose) - } - _ => { - trace!( - "NO: RHS of assignment was {:?}, but expected it to match the adt being matched on in the switch, which is {:?}", - rhs, - adt_matched_on - ); - StatementEquality::NotEqual - } - } - }; - match (&x.kind, &y.kind) { - // trivial case - (x, y) if x == y => StatementEquality::TrivialEqual, - - // check for case A - ( - StatementKind::Assign(box (_, rhs)), - &StatementKind::SetDiscriminant { ref place, variant_index }, - ) if y_target_and_value.value.is_some() => { - // choose basic block of x, as that has the assign - helper( - rhs, - place, - variant_index, - y_target_and_value.value.unwrap(), - x_target_and_value.target, - ) - } - ( - &StatementKind::SetDiscriminant { ref place, variant_index }, - &StatementKind::Assign(box (_, ref rhs)), - ) if x_target_and_value.value.is_some() => { - // choose basic block of y, as that has the assign - helper( - rhs, - place, - variant_index, - x_target_and_value.value.unwrap(), - y_target_and_value.target, - ) - } - _ => { - trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y); - StatementEquality::NotEqual - } - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq)] -enum StatementEquality { - /// The two statements are trivially equal; same kind - TrivialEqual, - /// The two statements are considered equal, but may be of different kinds. The BasicBlock field is the basic block to jump to when performing the branch-same optimization. - /// For example, `_0 = _1` and `discriminant(_0) = discriminant(0)` are considered equal if 0 is a fieldless variant of an enum. But we don't want to jump to the basic block with the SetDiscriminant, as that is not legal if _1 is not the 0 variant index - ConsideredEqual(BasicBlock), - /// The two statements are not equal - NotEqual, -} - -impl StatementEquality { - fn combine(&self, other: &StatementEquality) -> StatementEquality { - use StatementEquality::*; - match (self, other) { - (TrivialEqual, TrivialEqual) => TrivialEqual, - (TrivialEqual, ConsideredEqual(b)) | (ConsideredEqual(b), TrivialEqual) => { - ConsideredEqual(*b) - } - (ConsideredEqual(b1), ConsideredEqual(b2)) => { - if b1 == b2 { - ConsideredEqual(*b1) - } else { - NotEqual - } - } - (_, NotEqual) | (NotEqual, _) => NotEqual, - } - } -} diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs new file mode 100644 index 00000000000..bc3fe65cf6c --- /dev/null +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -0,0 +1,222 @@ +use either::Either; +use rustc_data_structures::graph::dominators::Dominators; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::middle::resolve_lifetime::Set1; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::{ParamEnv, TyCtxt}; + +#[derive(Debug)] +pub struct SsaLocals { + /// Assignments to each local. This defines whether the local is SSA. + assignments: IndexVec<Local, Set1<LocationExtended>>, + /// We visit the body in reverse postorder, to ensure each local is assigned before it is used. + /// We remember the order in which we saw the assignments to compute the SSA values in a single + /// pass. + assignment_order: Vec<Local>, + /// Copy equivalence classes between locals. See `copy_classes` for documentation. + copy_classes: IndexVec<Local, Local>, +} + +impl SsaLocals { + pub fn new<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + borrowed_locals: &BitSet<Local>, + ) -> SsaLocals { + let assignment_order = Vec::new(); + + let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls); + let dominators = body.basic_blocks.dominators(); + let mut visitor = SsaVisitor { assignments, assignment_order, dominators }; + + for (local, decl) in body.local_decls.iter_enumerated() { + if matches!(body.local_kind(local), LocalKind::Arg) { + visitor.assignments[local] = Set1::One(LocationExtended::Arg); + } + if borrowed_locals.contains(local) && !decl.ty.is_freeze(tcx, param_env) { + visitor.assignments[local] = Set1::Many; + } + } + + for (bb, data) in traversal::reverse_postorder(body) { + visitor.visit_basic_block_data(bb, data); + } + + for var_debug_info in &body.var_debug_info { + visitor.visit_var_debug_info(var_debug_info); + } + + debug!(?visitor.assignments); + + visitor + .assignment_order + .retain(|&local| matches!(visitor.assignments[local], Set1::One(_))); + debug!(?visitor.assignment_order); + + let copy_classes = compute_copy_classes(&visitor, body); + + SsaLocals { + assignments: visitor.assignments, + assignment_order: visitor.assignment_order, + copy_classes, + } + } + + pub fn is_ssa(&self, local: Local) -> bool { + matches!(self.assignments[local], Set1::One(_)) + } + + pub fn assignments<'a, 'tcx>( + &'a self, + body: &'a Body<'tcx>, + ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>)> + 'a { + self.assignment_order.iter().filter_map(|&local| { + if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] { + // `loc` must point to a direct assignment to `local`. + let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; + let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() }; + assert_eq!(target.as_local(), Some(local)); + Some((local, rvalue)) + } else { + None + } + }) + } + + /// Compute the equivalence classes for locals, based on copy statements. + /// + /// The returned vector maps each local to the one it copies. In the following case: + /// _a = &mut _0 + /// _b = move? _a + /// _c = move? _a + /// _d = move? _c + /// We return the mapping + /// _a => _a // not a copy so, represented by itself + /// _b => _a + /// _c => _a + /// _d => _a // transitively through _c + /// + /// Exception: we do not see through the return place, as it cannot be substituted. + pub fn copy_classes(&self) -> &IndexVec<Local, Local> { + &self.copy_classes + } + + /// Make a property uniform on a copy equivalence class by removing elements. + pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) { + // Consolidate to have a local iff all its copies are. + // + // `copy_classes` defines equivalence classes between locals. The `local`s that recursively + // move/copy the same local all have the same `head`. + for (local, &head) in self.copy_classes.iter_enumerated() { + // If any copy does not have `property`, then the head is not. + if !property.contains(local) { + property.remove(head); + } + } + for (local, &head) in self.copy_classes.iter_enumerated() { + // If any copy does not have `property`, then the head doesn't either, + // then no copy has `property`. + if !property.contains(head) { + property.remove(local); + } + } + + // Verify that we correctly computed equivalence classes. + #[cfg(debug_assertions)] + for (local, &head) in self.copy_classes.iter_enumerated() { + assert_eq!(property.contains(local), property.contains(head)); + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum LocationExtended { + Plain(Location), + Arg, +} + +struct SsaVisitor { + dominators: Dominators<BasicBlock>, + assignments: IndexVec<Local, Set1<LocationExtended>>, + assignment_order: Vec<Local>, +} + +impl<'tcx> Visitor<'tcx> for SsaVisitor { + fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) { + match ctxt { + PlaceContext::MutatingUse(MutatingUseContext::Store) => { + self.assignments[local].insert(LocationExtended::Plain(loc)); + self.assignment_order.push(local); + } + // Anything can happen with raw pointers, so remove them. + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) + | PlaceContext::MutatingUse(_) => self.assignments[local] = Set1::Many, + // Immutable borrows are taken into account in `SsaLocals::new` by + // removing non-freeze locals. + PlaceContext::NonMutatingUse(_) => { + let set = &mut self.assignments[local]; + let assign_dominates = match *set { + Set1::Empty | Set1::Many => false, + Set1::One(LocationExtended::Arg) => true, + Set1::One(LocationExtended::Plain(assign)) => { + assign.successor_within_block().dominates(loc, &self.dominators) + } + }; + // We are visiting a use that is not dominated by an assignment. + // Either there is a cycle involved, or we are reading for uninitialized local. + // Bail out. + if !assign_dominates { + *set = Set1::Many; + } + } + PlaceContext::NonUse(_) => {} + } + } +} + +#[instrument(level = "trace", skip(ssa, body))] +fn compute_copy_classes(ssa: &SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> { + let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len()); + + for &local in &ssa.assignment_order { + debug!(?local); + + if local == RETURN_PLACE { + // `_0` is special, we cannot rename it. + continue; + } + + // This is not SSA: mark that we don't know the value. + debug!(assignments = ?ssa.assignments[local]); + let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue }; + + // `loc` must point to a direct assignment to `local`. + let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; + let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() }; + assert_eq!(_target.as_local(), Some(local)); + + let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place)) + = rvalue + else { continue }; + + let Some(rhs) = place.as_local() else { continue }; + let Set1::One(_) = ssa.assignments[rhs] else { continue }; + + // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been + // visited before `local`, and we just have to copy the representing local. + copies[local] = copies[rhs]; + } + + debug!(?copies); + + // Invariant: `copies` must point to the head of an equivalence class. + #[cfg(debug_assertions)] + for &head in copies.iter() { + assert_eq!(copies[head], head); + } + + copies +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index ec1de305687..305f0427e50 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1296,7 +1296,7 @@ impl<'v> RootCollector<'_, 'v> { }; let start_def_id = self.tcx.require_lang_item(LangItem::Start, None); - let main_ret_ty = self.tcx.fn_sig(main_def_id).output(); + let main_ret_ty = self.tcx.fn_sig(main_def_id).no_bound_vars().unwrap().output(); // Given that `main()` has no arguments, // then its return type cannot have diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index fd6bcad1898..615126e8b58 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -180,7 +180,7 @@ pub fn partition<'tcx>( partitioner.place_root_mono_items(cx, mono_items) }; - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -200,7 +200,7 @@ pub fn partition<'tcx>( partitioner.place_inlined_mono_items(cx, initial_partitioning) }; - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 06b970ad979..054b41b478d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -337,7 +337,9 @@ pub(crate) struct IfExpressionMissingThenBlock { #[primary_span] pub if_span: Span, #[subdiagnostic] - pub sub: IfExpressionMissingThenBlockSub, + pub missing_then_block_sub: IfExpressionMissingThenBlockSub, + #[subdiagnostic] + pub let_else_sub: Option<IfExpressionLetSomeSub>, } #[derive(Subdiagnostic)] @@ -348,6 +350,13 @@ pub(crate) enum IfExpressionMissingThenBlockSub { AddThenBlock(#[primary_span] Span), } +#[derive(Subdiagnostic)] +#[help(parse_extra_if_in_let_else)] +pub(crate) struct IfExpressionLetSomeSub { + #[primary_span] + pub if_span: Span, +} + #[derive(Diagnostic)] #[diag(parse_if_expression_missing_condition)] pub(crate) struct IfExpressionMissingCondition { @@ -640,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces { pub sub: MatchArmBodyWithoutBracesSugg, } +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_extra_equals)] +#[note] +pub(crate) struct InclusiveRangeExtraEquals { + #[primary_span] + #[suggestion( + suggestion_remove_eq, + style = "short", + code = "..=", + applicability = "maybe-incorrect" + )] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_match_arrow)] +pub(crate) struct InclusiveRangeMatchArrow { + #[primary_span] + pub span: Span, + #[suggestion( + suggestion_add_space, + style = "verbose", + code = " ", + applicability = "machine-applicable" + )] + pub after_pat: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_no_end, code = "E0586")] +#[note] +pub(crate) struct InclusiveRangeNoEnd { + #[primary_span] + #[suggestion( + suggestion_open_range, + code = "..", + applicability = "machine-applicable", + style = "short" + )] + pub span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum MatchArmBodyWithoutBracesSugg { #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")] diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs new file mode 100644 index 00000000000..386bf026bb4 --- /dev/null +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -0,0 +1,119 @@ +use super::UnmatchedBrace; +use rustc_ast::token::Delimiter; +use rustc_errors::Diagnostic; +use rustc_span::source_map::SourceMap; +use rustc_span::Span; + +#[derive(Default)] +pub struct TokenTreeDiagInfo { + /// Stack of open delimiters and their spans. Used for error message. + pub open_braces: Vec<(Delimiter, Span)>, + pub unmatched_braces: Vec<UnmatchedBrace>, + + /// Used only for error recovery when arriving to EOF with mismatched braces. + pub last_unclosed_found_span: Option<Span>, + + /// Collect empty block spans that might have been auto-inserted by editors. + pub empty_block_spans: Vec<Span>, + + /// Collect the spans of braces (Open, Close). Used only + /// for detecting if blocks are empty and only braces. + pub matching_block_spans: Vec<(Span, Span)>, +} + +pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { + match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) { + (Some(open_padding), Some(close_padding)) => open_padding == close_padding, + _ => false, + } +} + +// When we get a `)` or `]` for `{`, we should emit help message here +// it's more friendly compared to report `unmatched error` in later phase +pub fn report_missing_open_delim( + err: &mut Diagnostic, + unmatched_braces: &[UnmatchedBrace], +) -> bool { + let mut reported_missing_open = false; + for unmatch_brace in unmatched_braces.iter() { + if let Some(delim) = unmatch_brace.found_delim + && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket) + { + let missed_open = match delim { + Delimiter::Parenthesis => "(", + Delimiter::Bracket => "[", + _ => unreachable!(), + }; + err.span_label( + unmatch_brace.found_span.shrink_to_lo(), + format!("missing open `{}` for this delimiter", missed_open), + ); + reported_missing_open = true; + } + } + reported_missing_open +} + +pub fn report_suspicious_mismatch_block( + err: &mut Diagnostic, + diag_info: &TokenTreeDiagInfo, + sm: &SourceMap, + delim: Delimiter, +) { + if report_missing_open_delim(err, &diag_info.unmatched_braces) { + return; + } + + let mut matched_spans: Vec<(Span, bool)> = diag_info + .matching_block_spans + .iter() + .map(|&(open, close)| (open.with_hi(close.lo()), same_identation_level(sm, open, close))) + .collect(); + + // sort by `lo`, so the large block spans in the front + matched_spans.sort_by(|a, b| a.0.lo().cmp(&b.0.lo())); + + // We use larger block whose identation is well to cover those inner mismatched blocks + // O(N^2) here, but we are on error reporting path, so it is fine + for i in 0..matched_spans.len() { + let (block_span, same_ident) = matched_spans[i]; + if same_ident { + for j in i + 1..matched_spans.len() { + let (inner_block, inner_same_ident) = matched_spans[j]; + if block_span.contains(inner_block) && !inner_same_ident { + matched_spans[j] = (inner_block, true); + } + } + } + } + + // Find the inner-most span candidate for final report + let candidate_span = + matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span); + + if let Some(block_span) = candidate_span { + err.span_label(block_span.shrink_to_lo(), "this delimiter might not be properly closed..."); + err.span_label( + block_span.shrink_to_hi(), + "...as it matches this but it has different indentation", + ); + + // If there is a empty block in the mismatched span, note it + if delim == Delimiter::Brace { + for span in diag_info.empty_block_spans.iter() { + if block_span.contains(*span) { + err.span_label(*span, "block is empty, you might have not meant to close it"); + break; + } + } + } + } else { + // If there is no suspicious span, give the last properly closed block may help + if let Some(parent) = diag_info.matching_block_spans.last() + && diag_info.open_braces.last().is_none() + && diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) { + err.span_label(parent.0, "this opening brace..."); + err.span_label(parent.1, "...matches this closing brace"); + } + } +} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 9fe8d9836ba..e957224a033 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -17,6 +17,7 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{edition::Edition, BytePos, Pos, Span}; +mod diagnostics; mod tokentrees; mod unescape_error_reporting; mod unicode_chars; diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index b2701817d48..0de8f79112c 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -1,29 +1,18 @@ +use super::diagnostics::report_suspicious_mismatch_block; +use super::diagnostics::same_identation_level; +use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedBrace}; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::{PErr, PResult}; -use rustc_span::Span; pub(super) struct TokenTreesReader<'a> { string_reader: StringReader<'a>, /// The "next" token, which has been obtained from the `StringReader` but /// not yet handled by the `TokenTreesReader`. token: Token, - /// Stack of open delimiters and their spans. Used for error message. - open_braces: Vec<(Delimiter, Span)>, - unmatched_braces: Vec<UnmatchedBrace>, - /// The type and spans for all braces - /// - /// Used only for error recovery when arriving to EOF with mismatched braces. - matching_delim_spans: Vec<(Delimiter, Span, Span)>, - last_unclosed_found_span: Option<Span>, - /// Collect empty block spans that might have been auto-inserted by editors. - last_delim_empty_block_spans: FxHashMap<Delimiter, Span>, - /// Collect the spans of braces (Open, Close). Used only - /// for detecting if blocks are empty and only braces. - matching_block_spans: Vec<(Span, Span)>, + diag_info: TokenTreeDiagInfo, } impl<'a> TokenTreesReader<'a> { @@ -33,15 +22,10 @@ impl<'a> TokenTreesReader<'a> { let mut tt_reader = TokenTreesReader { string_reader, token: Token::dummy(), - open_braces: Vec::new(), - unmatched_braces: Vec::new(), - matching_delim_spans: Vec::new(), - last_unclosed_found_span: None, - last_delim_empty_block_spans: FxHashMap::default(), - matching_block_spans: Vec::new(), + diag_info: TokenTreeDiagInfo::default(), }; let res = tt_reader.parse_token_trees(/* is_delimited */ false); - (res, tt_reader.unmatched_braces) + (res, tt_reader.diag_info.unmatched_braces) } // Parse a stream of tokens into a list of `TokenTree`s. @@ -92,9 +76,9 @@ impl<'a> TokenTreesReader<'a> { fn eof_err(&mut self) -> PErr<'a> { let msg = "this file contains an unclosed delimiter"; let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg); - for &(_, sp) in &self.open_braces { + for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); - self.unmatched_braces.push(UnmatchedBrace { + self.diag_info.unmatched_braces.push(UnmatchedBrace { expected_delim: Delimiter::Brace, found_delim: None, found_span: self.token.span, @@ -103,23 +87,13 @@ impl<'a> TokenTreesReader<'a> { }); } - if let Some((delim, _)) = self.open_braces.last() { - if let Some((_, open_sp, close_sp)) = - self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| { - let sm = self.string_reader.sess.source_map(); - if let Some(close_padding) = sm.span_to_margin(*close_sp) { - if let Some(open_padding) = sm.span_to_margin(*open_sp) { - return delim == d && close_padding != open_padding; - } - } - false - }) - // these are in reverse order as they get inserted on close, but - { - // we want the last open/first close - err.span_label(*open_sp, "this delimiter might not be properly closed..."); - err.span_label(*close_sp, "...as it matches this but it has different indentation"); - } + if let Some((delim, _)) = self.diag_info.open_braces.last() { + report_suspicious_mismatch_block( + &mut err, + &self.diag_info, + &self.string_reader.sess.source_map(), + *delim, + ) } err } @@ -128,7 +102,7 @@ impl<'a> TokenTreesReader<'a> { // The span for beginning of the delimited section let pre_span = self.token.span; - self.open_braces.push((open_delim, self.token.span)); + self.diag_info.open_braces.push((open_delim, self.token.span)); // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -137,35 +111,29 @@ impl<'a> TokenTreesReader<'a> { // Expand to cover the entire delimited token tree let delim_span = DelimSpan::from_pair(pre_span, self.token.span); + let sm = self.string_reader.sess.source_map(); match self.token.kind { // Correct delimiter. token::CloseDelim(close_delim) if close_delim == open_delim => { - let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap(); let close_brace_span = self.token.span; - if tts.is_empty() { + if tts.is_empty() && close_delim == Delimiter::Brace { let empty_block_span = open_brace_span.to(close_brace_span); - let sm = self.string_reader.sess.source_map(); if !sm.is_multiline(empty_block_span) { // Only track if the block is in the form of `{}`, otherwise it is // likely that it was written on purpose. - self.last_delim_empty_block_spans.insert(open_delim, empty_block_span); + self.diag_info.empty_block_spans.push(empty_block_span); } } - //only add braces + // only add braces if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) { - self.matching_block_spans.push((open_brace_span, close_brace_span)); + // Add all the matching spans, we will sort by span later + self.diag_info.matching_block_spans.push((open_brace_span, close_brace_span)); } - if self.open_braces.is_empty() { - // Clear up these spans to avoid suggesting them as we've found - // properly matched delimiters so far for an entire block. - self.matching_delim_spans.clear(); - } else { - self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span)); - } // Move past the closing delimiter. self.token = self.string_reader.next_token().0; } @@ -174,28 +142,25 @@ impl<'a> TokenTreesReader<'a> { let mut unclosed_delimiter = None; let mut candidate = None; - if self.last_unclosed_found_span != Some(self.token.span) { + if self.diag_info.last_unclosed_found_span != Some(self.token.span) { // do not complain about the same unclosed delimiter multiple times - self.last_unclosed_found_span = Some(self.token.span); + self.diag_info.last_unclosed_found_span = Some(self.token.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. - if let Some(&(_, sp)) = self.open_braces.last() { + if let Some(&(_, sp)) = self.diag_info.open_braces.last() { unclosed_delimiter = Some(sp); }; - let sm = self.string_reader.sess.source_map(); - if let Some(current_padding) = sm.span_to_margin(self.token.span) { - for (brace, brace_span) in &self.open_braces { - if let Some(padding) = sm.span_to_margin(*brace_span) { - // high likelihood of these two corresponding - if current_padding == padding && brace == &close_delim { - candidate = Some(*brace_span); - } - } + for (brace, brace_span) in &self.diag_info.open_braces { + if same_identation_level(&sm, self.token.span, *brace_span) + && brace == &close_delim + { + // high likelihood of these two corresponding + candidate = Some(*brace_span); } } - let (tok, _) = self.open_braces.pop().unwrap(); - self.unmatched_braces.push(UnmatchedBrace { + let (tok, _) = self.diag_info.open_braces.pop().unwrap(); + self.diag_info.unmatched_braces.push(UnmatchedBrace { expected_delim: tok, found_delim: Some(close_delim), found_span: self.token.span, @@ -203,7 +168,7 @@ impl<'a> TokenTreesReader<'a> { candidate_span: candidate, }); } else { - self.open_braces.pop(); + self.diag_info.open_braces.pop(); } // If the incorrect delimiter matches an earlier opening @@ -213,7 +178,7 @@ impl<'a> TokenTreesReader<'a> { // fn foo() { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` - if !self.open_braces.iter().any(|&(b, _)| b == close_delim) { + if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) { self.token = self.string_reader.next_token().0; } } @@ -236,22 +201,12 @@ impl<'a> TokenTreesReader<'a> { let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg); - // Braces are added at the end, so the last element is the biggest block - if let Some(parent) = self.matching_block_spans.last() { - if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { - // Check if the (empty block) is in the last properly closed block - if (parent.0.to(parent.1)).contains(span) { - err.span_label(span, "block is empty, you might have not meant to close it"); - } else { - err.span_label(parent.0, "this opening brace..."); - err.span_label(parent.1, "...matches this closing brace"); - } - } else { - err.span_label(parent.0, "this opening brace..."); - err.span_label(parent.1, "...matches this closing brace"); - } - } - + report_suspicious_mismatch_block( + &mut err, + &self.diag_info, + &self.string_reader.sess.source_map(), + delim, + ); err.span_label(self.token.span, "unexpected closing delimiter"); err } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4c918c6702e..f4c08031bcc 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2353,6 +2353,28 @@ impl<'a> Parser<'a> { Err(err) } + /// Try to recover from an unbraced const argument whose first token [could begin a type][ty]. + /// + /// [ty]: token::Token::can_begin_type + pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty( + &mut self, + mut snapshot: SnapshotParser<'a>, + ) -> Option<P<ast::Expr>> { + match snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) { + // Since we don't know the exact reason why we failed to parse the type or the + // expression, employ a simple heuristic to weed out some pathological cases. + Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => { + self.restore_snapshot(snapshot); + Some(expr) + } + Ok(_) => None, + Err(err) => { + err.cancel(); + None + } + } + } + /// Creates a dummy const argument, and reports that the expression must be enclosed in braces pub fn dummy_const_arg_needs_braces( &self, @@ -2372,7 +2394,7 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - pub(crate) fn maybe_recover_colon_colon_in_pat_typo( + pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum( &mut self, mut first_pat: P<Pat>, expected: Expected, @@ -2383,26 +2405,41 @@ impl<'a> Parser<'a> { if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) { + let mut snapshot_type = self.create_snapshot_for_diagnostic(); + snapshot_type.bump(); // `:` + match snapshot_type.parse_ty() { + Err(inner_err) => { + inner_err.cancel(); + } + Ok(ty) => { + let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else { + return first_pat; + }; + err.span_label(ty.span, "specifying the type of a pattern isn't supported"); + self.restore_snapshot(snapshot_type); + let span = first_pat.span.to(ty.span); + first_pat = self.mk_pat(span, PatKind::Wild); + err.emit(); + } + } return first_pat; } // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` - let span = self.token.span; + let colon_span = self.token.span; // We only emit "unexpected `:`" error here if we can successfully parse the // whole pattern correctly in that case. - let snapshot = self.create_snapshot_for_diagnostic(); + let mut snapshot_pat = self.create_snapshot_for_diagnostic(); + let mut snapshot_type = self.create_snapshot_for_diagnostic(); // Create error for "unexpected `:`". match self.expected_one_of_not_found(&[], &[]) { Err(mut err) => { - self.bump(); // Skip the `:`. - match self.parse_pat_no_top_alt(expected) { + snapshot_pat.bump(); // Skip the `:`. + snapshot_type.bump(); // Skip the `:`. + match snapshot_pat.parse_pat_no_top_alt(expected) { Err(inner_err) => { - // Carry on as if we had not done anything, callers will emit a - // reasonable error. inner_err.cancel(); - err.cancel(); - self.restore_snapshot(snapshot); } Ok(mut pat) => { // We've parsed the rest of the pattern. @@ -2466,8 +2503,8 @@ impl<'a> Parser<'a> { _ => {} } if show_sugg { - err.span_suggestion( - span, + err.span_suggestion_verbose( + colon_span.until(self.look_ahead(1, |t| t.span)), "maybe write a path separator here", "::", Applicability::MaybeIncorrect, @@ -2475,13 +2512,24 @@ impl<'a> Parser<'a> { } else { first_pat = self.mk_pat(new_span, PatKind::Wild); } - err.emit(); + self.restore_snapshot(snapshot_pat); } } + match snapshot_type.parse_ty() { + Err(inner_err) => { + inner_err.cancel(); + } + Ok(ty) => { + err.span_label(ty.span, "specifying the type of a pattern isn't supported"); + self.restore_snapshot(snapshot_type); + let new_span = first_pat.span.to(ty.span); + first_pat = self.mk_pat(new_span, PatKind::Wild); + } + } + err.emit(); } _ => { // Carry on as if we had not done anything. This should be unreachable. - self.restore_snapshot(snapshot); } }; first_pat diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bf93a89f065..17d1e200b41 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -11,15 +11,15 @@ use crate::errors::{ ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt, - IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, - InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub, - InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator, - InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator, - LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel, - MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm, - MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, - NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub, - OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, + IfExpressionLetSomeSub, IfExpressionMissingCondition, IfExpressionMissingThenBlock, + IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator, + InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, + InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, + LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, + MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, + MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, + MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator, + NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere, StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf, UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses, @@ -2251,9 +2251,10 @@ impl<'a> Parser<'a> { if let ExprKind::Block(_, None) = right.kind => { self.sess.emit_err(IfExpressionMissingThenBlock { if_span: lo, - sub: IfExpressionMissingThenBlockSub::UnfinishedCondition( - cond_span.shrink_to_lo().to(*binop_span) - ), + missing_then_block_sub: + IfExpressionMissingThenBlockSub::UnfinishedCondition(cond_span.shrink_to_lo().to(*binop_span)), + let_else_sub: None, + }); std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi())) }, @@ -2279,9 +2280,15 @@ impl<'a> Parser<'a> { if let Some(block) = recover_block_from_condition(self) { block } else { + let let_else_sub = matches!(cond.kind, ExprKind::Let(..)) + .then(|| IfExpressionLetSomeSub { if_span: lo }); + self.sess.emit_err(IfExpressionMissingThenBlock { if_span: lo, - sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()), + missing_then_block_sub: IfExpressionMissingThenBlockSub::AddThenBlock( + cond_span.shrink_to_hi(), + ), + let_else_sub, }); self.mk_block_err(cond_span.shrink_to_hi()) } @@ -3161,7 +3168,7 @@ impl<'a> Parser<'a> { limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.inclusive_range_with_incorrect_end(self.prev_token.span); + self.inclusive_range_with_incorrect_end(); ExprKind::Err } else { ExprKind::Range(start, end, limits) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e73a17ced7d..912f7cc14f6 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,5 +1,7 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; -use crate::errors::RemoveLet; +use crate::errors::{ + InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet, +}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -9,7 +11,7 @@ use rustc_ast::{ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -116,7 +118,8 @@ impl<'a> Parser<'a> { // Check if the user wrote `foo:bar` instead of `foo::bar`. if ra == RecoverColon::Yes { - first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected); + first_pat = + self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected); } if let Some(leading_vert_span) = leading_vert_span { @@ -745,47 +748,52 @@ impl<'a> Parser<'a> { // Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. - self.inclusive_range_with_incorrect_end(re.span); + self.inclusive_range_with_incorrect_end(); } None }; Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self) { let tok = &self.token; - + let span = self.prev_token.span; // If the user typed "..==" instead of "..=", we want to give them // a specific error message telling them to use "..=". + // If they typed "..=>", suggest they use ".. =>". // Otherwise, we assume that they meant to type a half open exclusive // range and give them an error telling them to do that instead. - if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() { - let span_with_eq = span.to(tok.span); + let no_space = tok.span.lo() == span.hi(); + match tok.kind { + token::Eq if no_space => { + let span_with_eq = span.to(tok.span); - // Ensure the user doesn't receive unhelpful unexpected token errors - self.bump(); - if self.is_pat_range_end_start(0) { - let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); - } + // Ensure the user doesn't receive unhelpful unexpected token errors + self.bump(); + if self.is_pat_range_end_start(0) { + let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); + } - self.error_inclusive_range_with_extra_equals(span_with_eq); - } else { - self.error_inclusive_range_with_no_end(span); + self.error_inclusive_range_with_extra_equals(span_with_eq); + } + token::Gt if no_space => { + self.error_inclusive_range_match_arrow(span); + } + _ => self.error_inclusive_range_with_no_end(span), } } fn error_inclusive_range_with_extra_equals(&self, span: Span) { - self.struct_span_err(span, "unexpected `=` after inclusive range") - .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect) - .note("inclusive ranges end with a single equals sign (`..=`)") - .emit(); + self.sess.emit_err(InclusiveRangeExtraEquals { span }); + } + + fn error_inclusive_range_match_arrow(&self, span: Span) { + let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); + self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat }); } fn error_inclusive_range_with_no_end(&self, span: Span) { - struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") - .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable) - .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)") - .emit(); + self.sess.emit_err(InclusiveRangeNoEnd { span }); } /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 5333d3b8587..2e706a00cf7 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -675,22 +675,42 @@ impl<'a> Parser<'a> { GenericArg::Const(self.parse_const_arg()?) } else if self.check_type() { // Parse type argument. - let is_const_fn = - self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)); - let mut snapshot = self.create_snapshot_for_diagnostic(); + + // Proactively create a parser snapshot enabling us to rewind and try to reparse the + // input as a const expression in case we fail to parse a type. If we successfully + // do so, we will report an error that it needs to be wrapped in braces. + let mut snapshot = None; + if self.may_recover() && self.token.can_begin_expr() { + snapshot = Some(self.create_snapshot_for_diagnostic()); + } + match self.parse_ty() { - Ok(ty) => GenericArg::Type(ty), + Ok(ty) => { + // Since the type parser recovers from some malformed slice and array types and + // successfully returns a type, we need to look for `TyKind::Err`s in the + // type to determine if error recovery has occurred and if the input is not a + // syntactically valid type after all. + if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind + && let ast::TyKind::Err = inner_ty.kind + && let Some(snapshot) = snapshot + && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) + { + return Ok(Some(self.dummy_const_arg_needs_braces( + self.struct_span_err(expr.span, "invalid const generic expression"), + expr.span, + ))); + } + + GenericArg::Type(ty) + } Err(err) => { - if is_const_fn { - match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) { - Ok(expr) => { - self.restore_snapshot(snapshot); - return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); - } - Err(err) => { - err.cancel(); - } - } + if let Some(snapshot) = snapshot + && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) + { + return Ok(Some(self.dummy_const_arg_needs_braces( + err, + expr.span, + ))); } // Try to recover from possible `const` arg without braces. return self.recover_const_arg(start, err).map(Some); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1766b0293de..82d9138c7a3 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -11,6 +11,7 @@ use rustc_ast::{ self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind, }; +use rustc_ast_pretty::pprust; use rustc_errors::{pluralize, struct_span_err, Applicability, PResult}; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident}; @@ -43,17 +44,24 @@ pub(super) enum AllowPlus { No, } -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub(super) enum RecoverQPath { Yes, No, } +#[derive(PartialEq, Clone, Copy)] pub(super) enum RecoverQuestionMark { Yes, No, } +#[derive(PartialEq, Clone, Copy)] +pub(super) enum RecoverAnonEnum { + Yes, + No, +} + /// Signals whether parsing a type should recover `->`. /// /// More specifically, when parsing a function like: @@ -86,7 +94,7 @@ impl RecoverReturnSign { } // Is `...` (`CVarArgs`) legal at this level of type parsing? -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] enum AllowCVariadic { Yes, No, @@ -111,6 +119,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -125,6 +134,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, Some(ty_params), RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -139,6 +149,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::Yes, ) } @@ -156,6 +167,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -169,6 +181,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::No, + RecoverAnonEnum::No, ) } @@ -180,6 +193,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::Yes, None, RecoverQuestionMark::No, + RecoverAnonEnum::No, ) } @@ -192,6 +206,7 @@ impl<'a> Parser<'a> { RecoverReturnSign::OnlyFatArrow, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::No, ) } @@ -211,6 +226,7 @@ impl<'a> Parser<'a> { recover_return_sign, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::Yes, )?; FnRetTy::Ty(ty) } else if recover_return_sign.can_recover(&self.token.kind) { @@ -232,6 +248,7 @@ impl<'a> Parser<'a> { recover_return_sign, None, RecoverQuestionMark::Yes, + RecoverAnonEnum::Yes, )?; FnRetTy::Ty(ty) } else { @@ -247,6 +264,7 @@ impl<'a> Parser<'a> { recover_return_sign: RecoverReturnSign, ty_generics: Option<&Generics>, recover_question_mark: RecoverQuestionMark, + recover_anon_enum: RecoverAnonEnum, ) -> PResult<'a, P<Ty>> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); @@ -325,14 +343,55 @@ impl<'a> Parser<'a> { let mut ty = self.mk_ty(span, kind); // Try to recover from use of `+` with incorrect priority. - if matches!(allow_plus, AllowPlus::Yes) { + if allow_plus == AllowPlus::Yes { self.maybe_recover_from_bad_type_plus(&ty)?; } else { self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty); } - if let RecoverQuestionMark::Yes = recover_question_mark { + if RecoverQuestionMark::Yes == recover_question_mark { ty = self.maybe_recover_from_question_mark(ty); } + if recover_anon_enum == RecoverAnonEnum::Yes + && self.check_noexpect(&token::BinOp(token::Or)) + && self.look_ahead(1, |t| t.can_begin_type()) + { + let mut pipes = vec![self.token.span]; + let mut types = vec![ty]; + loop { + if !self.eat(&token::BinOp(token::Or)) { + break; + } + pipes.push(self.prev_token.span); + types.push(self.parse_ty_common( + allow_plus, + allow_c_variadic, + recover_qpath, + recover_return_sign, + ty_generics, + recover_question_mark, + RecoverAnonEnum::No, + )?); + } + let mut err = self.struct_span_err(pipes, "anonymous enums are not supported"); + for ty in &types { + err.span_label(ty.span, ""); + } + err.help(&format!( + "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}", + types + .iter() + .enumerate() + .map(|(i, t)| format!( + " Variant{}({}),", + i + 1, // Lets not confuse people with zero-indexing :) + pprust::to_string(|s| s.print_type(&t)), + )) + .collect::<Vec<_>>() + .join("\n"), + )); + err.emit(); + return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err)); + } if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } @@ -989,7 +1048,7 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(bounds, true)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let sp = vec![lo, self.prev_token.span]; - let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect(); + let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())]; self.struct_span_err(sp, "incorrect braces around trait bounds") .multipart_suggestion( "remove the parentheses", diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 7b016cadac3..a6dfcd29762 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -16,7 +16,6 @@ pub use Alignment::*; pub use Count::*; -pub use Flag::*; pub use Piece::*; pub use Position::*; @@ -111,8 +110,14 @@ pub struct FormatSpec<'a> { pub fill: Option<char>, /// Optionally specified alignment. pub align: Alignment, - /// Packed version of various flags provided. - pub flags: u32, + /// The `+` or `-` flag. + pub sign: Option<Sign>, + /// The `#` flag. + pub alternate: bool, + /// The `0` flag. + pub zero_pad: bool, + /// The `x` or `X` flag. (Only for `Debug`.) + pub debug_hex: Option<DebugHex>, /// The integer precision to use. pub precision: Count<'a>, /// The span of the precision formatting flag (for diagnostics). @@ -162,24 +167,22 @@ pub enum Alignment { AlignUnknown, } -/// Various flags which can be applied to format strings. The meaning of these -/// flags is defined by the formatters themselves. +/// Enum for the sign flags. #[derive(Copy, Clone, Debug, PartialEq)] -pub enum Flag { - /// A `+` will be used to denote positive numbers. - FlagSignPlus, - /// A `-` will be used to denote negative numbers. This is the default. - FlagSignMinus, - /// An alternate form will be used for the value. In the case of numbers, - /// this means that the number will be prefixed with the supplied string. - FlagAlternate, - /// For numbers, this means that the number will be padded with zeroes, - /// and the sign (`+` or `-`) will precede them. - FlagSignAwareZeroPad, - /// For Debug / `?`, format integers in lower-case hexadecimal. - FlagDebugLowerHex, - /// For Debug / `?`, format integers in upper-case hexadecimal. - FlagDebugUpperHex, +pub enum Sign { + /// The `+` flag. + Plus, + /// The `-` flag. + Minus, +} + +/// Enum for the debug hex flags. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum DebugHex { + /// The `x` flag in `{:x?}`. + Lower, + /// The `X` flag in `{:X?}`. + Upper, } /// A count is used for the precision and width parameters of an integer, and @@ -597,7 +600,10 @@ impl<'a> Parser<'a> { let mut spec = FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, precision_span: None, width: CountImplied, @@ -626,13 +632,13 @@ impl<'a> Parser<'a> { } // Sign flags if self.consume('+') { - spec.flags |= 1 << (FlagSignPlus as u32); + spec.sign = Some(Sign::Plus); } else if self.consume('-') { - spec.flags |= 1 << (FlagSignMinus as u32); + spec.sign = Some(Sign::Minus); } // Alternate marker if self.consume('#') { - spec.flags |= 1 << (FlagAlternate as u32); + spec.alternate = true; } // Width and precision let mut havewidth = false; @@ -647,7 +653,7 @@ impl<'a> Parser<'a> { spec.width_span = Some(self.span(end - 1, end + 1)); havewidth = true; } else { - spec.flags |= 1 << (FlagSignAwareZeroPad as u32); + spec.zero_pad = true; } } @@ -678,14 +684,14 @@ impl<'a> Parser<'a> { // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { - spec.flags |= 1 << (FlagDebugLowerHex as u32); + spec.debug_hex = Some(DebugHex::Lower); spec.ty = "?"; } else { spec.ty = "x"; } } else if self.consume('X') { if self.consume('?') { - spec.flags |= 1 << (FlagDebugUpperHex as u32); + spec.debug_hex = Some(DebugHex::Upper); spec.ty = "?"; } else { spec.ty = "X"; @@ -708,7 +714,10 @@ impl<'a> Parser<'a> { let mut spec = FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, precision_span: None, width: CountImplied, diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index 2992ba845ab..45314e2fb55 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -10,7 +10,10 @@ fn fmtdflt() -> FormatSpec<'static> { return FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -126,7 +129,10 @@ fn format_type() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -147,7 +153,10 @@ fn format_align_fill() { format: FormatSpec { fill: None, align: AlignRight, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -165,7 +174,10 @@ fn format_align_fill() { format: FormatSpec { fill: Some('0'), align: AlignLeft, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -183,7 +195,10 @@ fn format_align_fill() { format: FormatSpec { fill: Some('*'), align: AlignLeft, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -204,7 +219,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, precision_span: None, width: CountIs(10), @@ -222,7 +240,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIs(10), precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(10), @@ -240,7 +261,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIs(10), precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(0), @@ -258,7 +282,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIsStar(0), precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, @@ -276,7 +303,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIsParam(10), width: CountImplied, precision_span: Some(InnerSpan::new(3, 7)), @@ -294,7 +324,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIsName("b", InnerSpan { start: 6, end: 7 }), precision_span: Some(InnerSpan { start: 5, end: 8 }), width: CountIsName("a", InnerSpan { start: 3, end: 4 }), @@ -312,7 +345,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIs(4), precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, @@ -333,7 +369,10 @@ fn format_flags() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: (1 << FlagSignMinus as u32), + sign: Some(Sign::Minus), + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -351,7 +390,10 @@ fn format_flags() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32), + sign: Some(Sign::Plus), + alternate: true, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -374,7 +416,10 @@ fn format_mixture() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f9f9799d3e4..25cc65ba04c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -6,11 +6,12 @@ use crate::errors::{ self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr, - OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint, + OnlyHasEffectOn, ProcMacroDiffArguments, ProcMacroInvalidAbi, ProcMacroMissingArguments, + ProcMacroTypeError, ProcMacroUnsafe, TransparentIncompatible, UnrecognizedReprHint, }; use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{fluent, Applicability, MultiSpan}; +use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan}; use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -19,11 +20,12 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; -use rustc_hir::{MethodKind, Target}; +use rustc_hir::{MethodKind, Target, Unsafety}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ParamEnv, TyCtxt}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; @@ -31,6 +33,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use std::cell::Cell; use std::collections::hash_map::Entry; pub(crate) fn target_from_impl_item<'tcx>( @@ -62,8 +65,29 @@ enum ItemLike<'tcx> { ForeignItem, } +#[derive(Copy, Clone)] +pub(crate) enum ProcMacroKind { + FunctionLike, + Derive, + Attribute, +} + +impl IntoDiagnosticArg for ProcMacroKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + match self { + ProcMacroKind::Attribute => "attribute proc macro", + ProcMacroKind::Derive => "derive proc macro", + ProcMacroKind::FunctionLike => "function-like proc macro", + } + .into_diagnostic_arg() + } +} + struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, + + // Whether or not this visitor should abort after finding errors + abort: Cell<bool>, } impl CheckAttrVisitor<'_> { @@ -173,7 +197,7 @@ impl CheckAttrVisitor<'_> { sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod), sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target), sym::macro_export => self.check_macro_export(hir_id, attr, target), - sym::ignore | sym::should_panic | sym::proc_macro_derive => { + sym::ignore | sym::should_panic => { self.check_generic_attr(hir_id, attr, target, Target::Fn) } sym::automatically_derived => { @@ -183,6 +207,16 @@ impl CheckAttrVisitor<'_> { self.check_generic_attr(hir_id, attr, target, Target::Mod) } sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id), + sym::proc_macro => { + self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) + } + sym::proc_macro_attribute => { + self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); + } + sym::proc_macro_derive => { + self.check_generic_attr(hir_id, attr, target, Target::Fn); + self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) + } _ => {} } @@ -419,7 +453,9 @@ impl CheckAttrVisitor<'_> { /// Debugging aid for `object_lifetime_default` query. fn check_object_lifetime_default(&self, hir_id: HirId) { let tcx = self.tcx; - if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) { + if let Some(owner_id) = hir_id.as_owner() + && let Some(generics) = tcx.hir().get_generics(owner_id.def_id) + { for p in generics.params { let hir::GenericParamKind::Type { .. } = p.kind else { continue }; let default = tcx.object_lifetime_default(p.def_id); @@ -1909,7 +1945,7 @@ impl CheckAttrVisitor<'_> { ) -> bool { match target { Target::Fn | Target::Method(_) - if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id).to_def_id()) => + if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => { true } @@ -2063,6 +2099,104 @@ impl CheckAttrVisitor<'_> { errors::Unused { attr_span: attr.span, note }, ); } + + /// A best effort attempt to create an error for a mismatching proc macro signature. + /// + /// If this best effort goes wrong, it will just emit a worse error later (see #102923) + fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) { + let expected_input_count = match kind { + ProcMacroKind::Attribute => 2, + ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1, + }; + + let expected_signature = match kind { + ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream", + ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream", + }; + + let tcx = self.tcx; + if target == Target::Fn { + let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return}; + let tokenstream = tcx.type_of(tokenstream); + + let id = hir_id.expect_owner(); + let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap(); + + let sig = + tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id).subst_identity()); + let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig); + + // We don't currently require that the function signature is equal to + // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to + // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments. + // + // Properly checking this means pulling in additional `rustc` crates, so we don't. + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }; + + if sig.abi != Abi::Rust { + tcx.sess.emit_err(ProcMacroInvalidAbi { span: hir_sig.span, abi: sig.abi.name() }); + self.abort.set(true); + } + + if sig.unsafety == Unsafety::Unsafe { + tcx.sess.emit_err(ProcMacroUnsafe { span: hir_sig.span }); + self.abort.set(true); + } + + let output = sig.output(); + + // Typecheck the output + if !drcx.types_may_unify(output, tokenstream) { + tcx.sess.emit_err(ProcMacroTypeError { + span: hir_sig.decl.output.span(), + found: output, + kind, + expected_signature, + }); + self.abort.set(true); + } + + if sig.inputs().len() < expected_input_count { + tcx.sess.emit_err(ProcMacroMissingArguments { + expected_input_count, + span: hir_sig.span, + kind, + expected_signature, + }); + self.abort.set(true); + } + + // Check that the inputs are correct, if there are enough. + if sig.inputs().len() >= expected_input_count { + for (arg, input) in + sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count) + { + if !drcx.types_may_unify(*arg, tokenstream) { + tcx.sess.emit_err(ProcMacroTypeError { + span: input.span, + found: *arg, + kind, + expected_signature, + }); + self.abort.set(true); + } + } + } + + // Check that there are not too many arguments + let body_id = tcx.hir().body_owned_by(id.def_id); + let excess = tcx.hir().body(body_id).params.get(expected_input_count..); + if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess { + tcx.sess.emit_err(ProcMacroDiffArguments { + span: begin.span.to(end.span), + count: excess.len(), + kind, + expected_signature, + }); + self.abort.set(true); + } + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { @@ -2225,12 +2359,15 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) } fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - let check_attr_visitor = &mut CheckAttrVisitor { tcx }; + let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) }; tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor); if module_def_id.is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); } + if check_attr_visitor.abort.get() { + tcx.sess.abort_if_errors() + } } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index aa726d6cd92..dd8c646a43c 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -48,7 +48,7 @@ impl NonConstExpr { Self::Match(TryDesugar) => &[sym::const_try], // All other expressions are allowed. - Self::Loop(Loop | While) | Self::Match(Normal) => &[], + Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[], }; Some(gates) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 94171b4b0c8..83adfeb6b10 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -451,47 +451,40 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { // referenced by it should be considered as used. let in_pat = mem::replace(&mut self.in_pat, false); - self.live_symbols.insert(self.tcx.hir().local_def_id(c.hir_id)); + self.live_symbols.insert(c.def_id); intravisit::walk_anon_const(self, c); self.in_pat = in_pat; } } -fn has_allow_dead_code_or_lang_attr_helper( - tcx: TyCtxt<'_>, - id: hir::HirId, - lint: &'static lint::Lint, -) -> bool { - let attrs = tcx.hir().attrs(id); - if tcx.sess.contains_name(attrs, sym::lang) { - return true; +fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.has_attr(def_id.to_def_id(), sym::lang) + // Stable attribute for #[lang = "panic_impl"] + || tcx.has_attr(def_id.to_def_id(), sym::panic_handler) } - // Stable attribute for #[lang = "panic_impl"] - if tcx.sess.contains_name(attrs, sym::panic_handler) { - return true; + fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow } - let def_id = tcx.hir().local_def_id(id); - if tcx.def_kind(def_id).has_codegen_attrs() { - let cg_attrs = tcx.codegen_fn_attrs(def_id); + fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.def_kind(def_id).has_codegen_attrs() && { + let cg_attrs = tcx.codegen_fn_attrs(def_id); - // #[used], #[no_mangle], #[export_name], etc also keeps the item alive - // forcefully, e.g., for placing it in a specific section. - if cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - return true; + // #[used], #[no_mangle], #[export_name], etc also keeps the item alive + // forcefully, e.g., for placing it in a specific section. + cg_attrs.contains_extern_indicator() + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } } - tcx.lint_level_at_node(lint, id).0 == lint::Allow -} - -fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { - has_allow_dead_code_or_lang_attr_helper(tcx, id, lint::builtin::DEAD_CODE) + has_allow_dead_code(tcx, def_id) + || has_used_like_attr(tcx, def_id) + || has_lang_attr(tcx, def_id) } // These check_* functions seeds items that @@ -513,7 +506,7 @@ fn check_item<'tcx>( struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>, id: hir::ItemId, ) { - let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id()); + let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id); if allow_dead_code { worklist.push(id.owner_id.def_id); } @@ -548,9 +541,7 @@ fn check_item<'tcx>( // And we access the Map here to get HirId from LocalDefId for id in local_def_ids { - if of_trait.is_some() - || has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id)) - { + if of_trait.is_some() || has_allow_dead_code_or_lang_attr(tcx, id) { worklist.push(id); } } @@ -558,9 +549,9 @@ fn check_item<'tcx>( DefKind::Struct => { let item = tcx.hir().item(id); if let hir::ItemKind::Struct(ref variant_data, _) = item.kind - && let Some(ctor_hir_id) = variant_data.ctor_hir_id() + && let Some(ctor_def_id) = variant_data.ctor_def_id() { - struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id); + struct_constructors.insert(ctor_def_id, item.owner_id.def_id); } } DefKind::GlobalAsm => { @@ -576,7 +567,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::Tr if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) - && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id()) + && has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { worklist.push(trait_item.owner_id.def_id); } @@ -585,7 +576,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::Tr fn check_foreign_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::ForeignItemId) { if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn) - && has_allow_dead_code_or_lang_attr(tcx, id.hir_id()) + && has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id) { worklist.push(id.owner_id.def_id); } @@ -806,8 +797,7 @@ impl<'tcx> DeadVisitor<'tcx> { if self.live_symbols.contains(&def_id) { return; } - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - if has_allow_dead_code_or_lang_attr(self.tcx, hir_id) { + if has_allow_dead_code_or_lang_attr(self.tcx, def_id) { return; } let Some(name) = self.tcx.opt_item_name(def_id.to_def_id()) else { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9c6519ea4bb..9e05ad22e62 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -12,6 +12,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{Span, Symbol, DUMMY_SP}; +use crate::check_attr::ProcMacroKind; use crate::lang_items::Duplicate; #[derive(Diagnostic)] @@ -1515,3 +1516,52 @@ pub struct ChangeFieldsToBeOfUnitType { #[suggestion_part(code = "()")] pub spans: Vec<Span>, } + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_typeerror)] +#[note] +pub(crate) struct ProcMacroTypeError<'tcx> { + #[primary_span] + #[label] + pub span: Span, + pub found: Ty<'tcx>, + pub kind: ProcMacroKind, + pub expected_signature: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_diff_arg_count)] +pub(crate) struct ProcMacroDiffArguments { + #[primary_span] + #[label] + pub span: Span, + pub count: usize, + pub kind: ProcMacroKind, + pub expected_signature: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_missing_args)] +pub(crate) struct ProcMacroMissingArguments { + #[primary_span] + #[label] + pub span: Span, + pub expected_input_count: usize, + pub kind: ProcMacroKind, + pub expected_signature: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_invalid_abi)] +pub(crate) struct ProcMacroInvalidAbi { + #[primary_span] + pub span: Span, + pub abi: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_proc_macro_unsafe)] +pub(crate) struct ProcMacroUnsafe { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index b86d2316820..51a19c8e3c0 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -12,6 +12,7 @@ use rustc_hir::HirId; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; use rustc_middle::util::common::to_readable_str; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -363,7 +364,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fd: &'v hir::FnDecl<'v>, b: hir::BodyId, _: Span, - id: hir::HirId, + id: LocalDefId, ) { self.record("FnDecl", Id::None, fd); hir_visit::walk_fn(self, fk, fd, b, id) @@ -567,7 +568,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, - InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err + InlineAsm, FormatArgs, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err ] ); ast_visit::walk_expr(self, e) diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 9a40b847d85..fdd0e5dab70 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -15,9 +15,9 @@ use crate::weak_lang_items; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::{extract, GenericRequirement}; -use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_hir::{LangItem, LanguageItems, Target}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; use rustc_span::{symbol::kw::Empty, Span}; @@ -40,13 +40,13 @@ impl<'tcx> LanguageItemCollector<'tcx> { LanguageItemCollector { tcx, items: LanguageItems::new() } } - fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { - let attrs = self.tcx.hir().attrs(hir_id); + fn check_for_lang(&mut self, actual_target: Target, def_id: LocalDefId) { + let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); if let Some((name, span)) = extract(&attrs) { match LangItem::from_name(name) { // Known lang item with attribute on correct target. Some(lang_item) if actual_target == lang_item.target() => { - self.collect_item_extended(lang_item, hir_id, span); + self.collect_item_extended(lang_item, def_id, span); } // Known lang item with attribute on incorrect target. Some(lang_item) => { @@ -142,8 +142,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { // Like collect_item() above, but also checks whether the lang item is declared // with the right number of generic arguments. - fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) { - let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); + fn collect_item_extended(&mut self, lang_item: LangItem, item_def_id: LocalDefId, span: Span) { let name = lang_item.name(); // Now check whether the lang_item has the expected number of generic @@ -154,7 +153,8 @@ impl<'tcx> LanguageItemCollector<'tcx> { // Some other types like Box and various functions like drop_in_place // have minimum requirements. - if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = self.tcx.hir().get(hir_id) + if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = + self.tcx.hir().get_by_def_id(item_def_id) { let (actual_num, generics_span) = match kind.generics() { Some(generics) => (generics.params.len(), generics.span), @@ -191,7 +191,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { } } - self.collect_item(lang_item, item_def_id); + self.collect_item(lang_item, item_def_id.to_def_id()); } } @@ -211,13 +211,14 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id()); + collector + .check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.owner_id.def_id); if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(def, ..) = &item.kind { for variant in def.variants { - collector.check_for_lang(Target::Variant, variant.hir_id); + collector.check_for_lang(Target::Variant, variant.def_id); } } } @@ -226,13 +227,13 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { // FIXME: avoid calling trait_item() when possible for id in crate_items.trait_items() { let item = tcx.hir().trait_item(id); - collector.check_for_lang(Target::from_trait_item(item), item.hir_id()) + collector.check_for_lang(Target::from_trait_item(item), item.owner_id.def_id) } // FIXME: avoid calling impl_item() when possible for id in crate_items.impl_items() { let item = tcx.hir().impl_item(id); - collector.check_for_lang(target_from_impl_item(tcx, item), item.hir_id()) + collector.check_for_lang(target_from_impl_item(tcx, item), item.owner_id.def_id) } // Extract out the found lang items. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 34e1abb78b2..0bde7502e39 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -855,7 +855,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { /// See issue #94972 for details on why this is a special case fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // Get the LocalDefId so we can lookup the item to check the kind. - let Some(def_id) = tcx.hir().opt_local_def_id(id) else { return false; }; + let Some(owner) = id.as_owner() else { return false; }; + let def_id = owner.def_id; let Some(stab) = tcx.stability().local_stability(def_id) else { return false; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9a5d3cceb91..43552861532 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; @@ -198,7 +198,8 @@ where // Something like `fn() -> Priv {my_func}` is considered a private type even if // `my_func` is public, so we need to visit signatures. if let ty::FnDef(..) = ty.kind() { - tcx.fn_sig(def_id).visit_with(self)?; + // FIXME: this should probably use `substs` from `FnDef` + tcx.fn_sig(def_id).subst_identity().visit_with(self)?; } // Inherent static methods don't have self type in substs. // Something like `fn() {my_method}` type of the method @@ -270,7 +271,8 @@ where | ty::FnPtr(..) | ty::Param(..) | ty::Error(_) - | ty::GeneratorWitness(..) => {} + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) => {} ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) } @@ -1877,7 +1879,7 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { struct PrivateItemsInPublicInterfacesChecker<'tcx> { tcx: TyCtxt<'tcx>, - old_error_set_ancestry: LocalDefIdSet, + old_error_set_ancestry: HirIdSet, } impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { @@ -1890,7 +1892,9 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { tcx: self.tcx, item_def_id: def_id, required_visibility, - has_old_errors: self.old_error_set_ancestry.contains(&def_id), + has_old_errors: self + .old_error_set_ancestry + .contains(&self.tcx.hir().local_def_id_to_hir_id(def_id)), in_assoc_ty: false, } } @@ -2156,15 +2160,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { } // Check for private types and traits in public interfaces. - let mut checker = PrivateItemsInPublicInterfacesChecker { - tcx, - // Only definition IDs are ever searched in `old_error_set_ancestry`, - // so we can filter away all non-definition IDs at this point. - old_error_set_ancestry: old_error_set_ancestry - .into_iter() - .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id)) - .collect(), - }; + let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, old_error_set_ancestry }; for id in tcx.hir().items() { checker.check_item(id); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6d448433ee6..37beff37c1f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -227,20 +227,27 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt() && let Some(items) = self.diagnostic_metadata.current_impl_items && let Some(item) = items.iter().find(|i| { - if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name + if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind + && i.ident.name == item_str.name { debug!(?item_str.name); return true } false }) - && let AssocItemKind::Fn(fn_) = &item.kind { - debug!(?fn_); - let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" }; + let self_sugg = match &item.kind { + AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.", + _ => "Self::", + }; + Some(( item_span.shrink_to_lo(), - "consider using the associated function", + match &item.kind { + AssocItemKind::Fn(..) => "consider using the associated function", + AssocItemKind::Const(..) => "consider using the associated constant", + _ => unreachable!("item kind was filtered above"), + }, self_sugg.to_string() )) } else { diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index a5f09de1c40..3982111e38e 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -211,7 +211,7 @@ impl<'tcx> DumpVisitor<'tcx> { None => continue, }; if !self.span.filter_generated(ident.span) { - let id = id_from_hir_id(hir_id, &self.save_ctxt); + let id = id_from_hir_id(hir_id); let span = self.span_from_span(ident.span); self.dumper.dump_def( @@ -240,17 +240,17 @@ impl<'tcx> DumpVisitor<'tcx> { &mut self, sig: &'tcx hir::FnSig<'tcx>, body: Option<hir::BodyId>, - def_id: LocalDefId, + owner_id: hir::OwnerId, ident: Ident, generics: &'tcx hir::Generics<'tcx>, span: Span, ) { - debug!("process_method: {:?}:{}", def_id, ident); + debug!("process_method: {:?}:{}", owner_id, ident); let map = self.tcx.hir(); - let hir_id = map.local_def_id_to_hir_id(def_id); - self.nest_typeck_results(def_id, |v| { - if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) { + let hir_id: hir::HirId = owner_id.into(); + self.nest_typeck_results(owner_id.def_id, |v| { + if let Some(mut method_data) = v.save_ctxt.get_method_data(owner_id, ident, span) { if let Some(body) = body { v.process_formals(map.body(body).params, &method_data.qualname); } @@ -258,9 +258,10 @@ impl<'tcx> DumpVisitor<'tcx> { method_data.value = fn_to_string(sig.decl, sig.header, Some(ident.name), generics, &[], None); - method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt); + method_data.sig = + sig::method_signature(owner_id, ident, generics, sig, &v.save_ctxt); - v.dumper.dump_def(&access_from!(v.save_ctxt, def_id), method_data); + v.dumper.dump_def(&access_from!(v.save_ctxt, owner_id.def_id), method_data); } // walk arg and return types @@ -282,14 +283,11 @@ impl<'tcx> DumpVisitor<'tcx> { fn process_struct_field_def( &mut self, field: &'tcx hir::FieldDef<'tcx>, - parent_id: hir::HirId, + parent_id: LocalDefId, ) { let field_data = self.save_ctxt.get_field_data(field, parent_id); if let Some(field_data) = field_data { - self.dumper.dump_def( - &access_from!(self.save_ctxt, self.tcx.hir().local_def_id(field.hir_id)), - field_data, - ); + self.dumper.dump_def(&access_from!(self.save_ctxt, field.def_id), field_data); } } @@ -309,7 +307,7 @@ impl<'tcx> DumpVisitor<'tcx> { // Append $id to name to make sure each one is unique. let qualname = format!("{}::{}${}", prefix, name, id); if !self.span.filter_generated(param_ss) { - let id = id_from_hir_id(param.hir_id, &self.save_ctxt); + let id = id_from_def_id(param.def_id.to_def_id()); let span = self.span_from_span(param_ss); self.dumper.dump_def( @@ -387,25 +385,24 @@ impl<'tcx> DumpVisitor<'tcx> { fn process_assoc_const( &mut self, - def_id: LocalDefId, + owner_id: hir::OwnerId, ident: Ident, typ: &'tcx hir::Ty<'tcx>, expr: Option<&'tcx hir::Expr<'tcx>>, parent_id: DefId, attrs: &'tcx [ast::Attribute], ) { - let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(owner_id.to_def_id())); if !self.span.filter_generated(ident.span) { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt); + let sig = sig::assoc_const_signature(owner_id, ident.name, typ, expr, &self.save_ctxt); let span = self.span_from_span(ident.span); self.dumper.dump_def( - &access_from!(self.save_ctxt, def_id), + &access_from!(self.save_ctxt, owner_id.def_id), Def { kind: DefKind::Const, - id: id_from_hir_id(hir_id, &self.save_ctxt), + id: id_from_def_id(owner_id.to_def_id()), span, name: ident.name.to_string(), qualname, @@ -421,7 +418,7 @@ impl<'tcx> DumpVisitor<'tcx> { } // walk type and init value - self.nest_typeck_results(def_id, |v| { + self.nest_typeck_results(owner_id.def_id, |v| { v.visit_ty(typ); if let Some(expr) = expr { v.visit_expr(expr); @@ -456,8 +453,7 @@ impl<'tcx> DumpVisitor<'tcx> { if include_priv_fields { return Some(f.ident.to_string()); } - let def_id = self.save_ctxt.tcx.hir().local_def_id(f.hir_id); - if self.save_ctxt.tcx.visibility(def_id).is_public() { + if self.save_ctxt.tcx.visibility(f.def_id).is_public() { Some(f.ident.to_string()) } else { None @@ -466,7 +462,7 @@ impl<'tcx> DumpVisitor<'tcx> { .collect::<Vec<_>>() .join(", "); let value = format!("{} {{ {} }}", name, fields_str); - (value, fields.iter().map(|f| id_from_hir_id(f.hir_id, &self.save_ctxt)).collect()) + (value, fields.iter().map(|f| id_from_def_id(f.def_id.to_def_id())).collect()) } _ => (String::new(), vec![]), }; @@ -495,7 +491,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.nest_typeck_results(item.owner_id.def_id, |v| { for field in def.fields() { - v.process_struct_field_def(field, item.hir_id()); + v.process_struct_field_def(field, item.owner_id.def_id); v.visit_ty(&field.ty); } @@ -529,7 +525,7 @@ impl<'tcx> DumpVisitor<'tcx> { let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_hir_id(variant.hir_id, &self.save_ctxt); + let id = id_from_def_id(variant.def_id.to_def_id()); let parent = Some(id_from_def_id(item.owner_id.to_def_id())); let attrs = self.tcx.hir().attrs(variant.hir_id); @@ -567,7 +563,7 @@ impl<'tcx> DumpVisitor<'tcx> { } if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_hir_id(variant.hir_id, &self.save_ctxt); + let id = id_from_def_id(variant.def_id.to_def_id()); let parent = Some(id_from_def_id(item.owner_id.to_def_id())); let attrs = self.tcx.hir().attrs(variant.hir_id); @@ -593,7 +589,7 @@ impl<'tcx> DumpVisitor<'tcx> { } for field in variant.data.fields() { - self.process_struct_field_def(field, variant.hir_id); + self.process_struct_field_def(field, variant.def_id); self.visit_ty(field.ty); } } @@ -883,7 +879,7 @@ impl<'tcx> DumpVisitor<'tcx> { // Rust uses the id of the pattern for var lookups, so we'll use it too. if !self.span.filter_generated(ident.span) { let qualname = format!("{}${}", ident, hir_id); - let id = id_from_hir_id(hir_id, &self.save_ctxt); + let id = id_from_hir_id(hir_id); let span = self.span_from_span(ident.span); self.dumper.dump_def( @@ -983,7 +979,7 @@ impl<'tcx> DumpVisitor<'tcx> { let body = body.map(|b| self.tcx.hir().body(b).value); let attrs = self.tcx.hir().attrs(trait_item.hir_id()); self.process_assoc_const( - trait_item.owner_id.def_id, + trait_item.owner_id, trait_item.ident, &ty, body, @@ -997,7 +993,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_method( sig, body, - trait_item.owner_id.def_id, + trait_item.owner_id, trait_item.ident, &trait_item.generics, trait_item.span, @@ -1028,7 +1024,7 @@ impl<'tcx> DumpVisitor<'tcx> { decl_id: None, docs: self.save_ctxt.docs_for_attrs(attrs), sig: sig::assoc_type_signature( - trait_item.hir_id(), + trait_item.owner_id, trait_item.ident, Some(bounds), default_ty.as_deref(), @@ -1053,7 +1049,7 @@ impl<'tcx> DumpVisitor<'tcx> { let body = self.tcx.hir().body(body); let attrs = self.tcx.hir().attrs(impl_item.hir_id()); self.process_assoc_const( - impl_item.owner_id.def_id, + impl_item.owner_id, impl_item.ident, &ty, Some(&body.value), @@ -1065,7 +1061,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_method( sig, Some(body), - impl_item.owner_id.def_id, + impl_item.owner_id, impl_item.ident, &impl_item.generics, impl_item.span, @@ -1081,18 +1077,16 @@ impl<'tcx> DumpVisitor<'tcx> { } pub(crate) fn process_crate(&mut self) { - let id = hir::CRATE_HIR_ID; - let qualname = - format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(CRATE_DEF_ID.to_def_id())); let sm = self.tcx.sess.source_map(); let krate_mod = self.tcx.hir().root_module(); let filename = sm.span_to_filename(krate_mod.spans.inner_span); - let data_id = id_from_hir_id(id, &self.save_ctxt); + let data_id = id_from_def_id(CRATE_DEF_ID.to_def_id()); let children = krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect(); let span = self.span_from_span(krate_mod.spans.inner_span); - let attrs = self.tcx.hir().attrs(id); + let attrs = self.tcx.hir().attrs(hir::CRATE_HIR_ID); self.dumper.dump_def( &Access { public: true, reachable: true }, @@ -1319,7 +1313,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // output the inferred type here? :shrug: hir::ArrayLen::Infer(..) => {} hir::ArrayLen::Body(anon_const) => self - .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + .nest_typeck_results(anon_const.def_id, |v| { v.visit_expr(&map.body(anon_const.body).value) }), } @@ -1361,7 +1355,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } } } - hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, def_id, .. }) => { let id = format!("${}", ex.hir_id); // walk arg and return types @@ -1375,7 +1369,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // walk the body let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(ex.hir_id), |v| { + self.nest_typeck_results(def_id, |v| { let body = map.body(body); v.process_formals(body.params, &id); v.visit_expr(&body.value) @@ -1389,7 +1383,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // output the inferred type here? :shrug: hir::ArrayLen::Infer(..) => {} hir::ArrayLen::Body(anon_const) => self - .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + .nest_typeck_results(anon_const.def_id, |v| { v.visit_expr(&map.body(anon_const.body).value) }), } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index a8d82de02b7..a9a92cc4f62 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -21,7 +21,7 @@ use rustc_ast::util::comments::beautify_doc_string; use rustc_ast_pretty::pprust::attribute_to_string; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; @@ -318,7 +318,7 @@ impl<'tcx> SaveContext<'tcx> { qualname, value, parent: None, - children: def.variants.iter().map(|v| id_from_hir_id(v.hir_id, self)).collect(), + children: def.variants.iter().map(|v| id_from_def_id(v.def_id.to_def_id())).collect(), decl_id: None, docs: self.docs_for_attrs(attrs), sig: sig::item_signature(item, self), @@ -379,12 +379,11 @@ impl<'tcx> SaveContext<'tcx> { } } - pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: hir::HirId) -> Option<Def> { + pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: LocalDefId) -> Option<Def> { let name = field.ident.to_string(); - let scope_def_id = self.tcx.hir().local_def_id(scope).to_def_id(); - let qualname = format!("::{}::{}", self.tcx.def_path_str(scope_def_id), field.ident); + let qualname = format!("::{}::{}", self.tcx.def_path_str(scope.to_def_id()), field.ident); filter!(self.span_utils, field.ident.span); - let field_def_id = self.tcx.hir().local_def_id(field.hir_id).to_def_id(); + let field_def_id = field.def_id.to_def_id(); let typ = self.tcx.type_of(field_def_id).to_string(); let id = id_from_def_id(field_def_id); @@ -398,7 +397,7 @@ impl<'tcx> SaveContext<'tcx> { name, qualname, value: typ, - parent: Some(id_from_def_id(scope_def_id)), + parent: Some(id_from_def_id(scope.to_def_id())), children: vec![], decl_id: None, docs: self.docs_for_attrs(attrs), @@ -409,12 +408,11 @@ impl<'tcx> SaveContext<'tcx> { // FIXME would be nice to take a MethodItem here, but the ast provides both // trait and impl flavours, so the caller must do the disassembly. - pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> Option<Def> { + pub fn get_method_data(&self, owner_id: hir::OwnerId, ident: Ident, span: Span) -> Option<Def> { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); let (qualname, parent_scope, decl_id, docs, attributes) = - match self.tcx.impl_of_method(def_id) { + match self.tcx.impl_of_method(owner_id.to_def_id()) { Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) { Some(Node::Item(item)) => match item.kind { hir::ItemKind::Impl(hir::Impl { ref self_ty, .. }) => { @@ -427,8 +425,8 @@ impl<'tcx> SaveContext<'tcx> { let trait_id = self.tcx.trait_id_of_impl(impl_id); let mut docs = String::new(); let mut attrs = vec![]; - if let Some(Node::ImplItem(_)) = hir.find(hir_id) { - attrs = self.tcx.hir().attrs(hir_id).to_vec(); + if let Some(Node::ImplItem(_)) = hir.find(owner_id.into()) { + attrs = self.tcx.hir().attrs(owner_id.into()).to_vec(); docs = self.docs_for_attrs(&attrs); } @@ -452,29 +450,29 @@ impl<'tcx> SaveContext<'tcx> { _ => { span_bug!( span, - "Container {:?} for method {} not an impl?", + "Container {:?} for method {:?} not an impl?", impl_id, - hir_id + owner_id, ); } }, r => { span_bug!( span, - "Container {:?} for method {} is not a node item {:?}", + "Container {:?} for method {:?} is not a node item {:?}", impl_id, - hir_id, + owner_id, r ); } }, - None => match self.tcx.trait_of_item(def_id) { + None => match self.tcx.trait_of_item(owner_id.to_def_id()) { Some(def_id) => { let mut docs = String::new(); let mut attrs = vec![]; - if let Some(Node::TraitItem(_)) = self.tcx.hir().find(hir_id) { - attrs = self.tcx.hir().attrs(hir_id).to_vec(); + if let Some(Node::TraitItem(_)) = self.tcx.hir().find(owner_id.into()) { + attrs = self.tcx.hir().attrs(owner_id.into()).to_vec(); docs = self.docs_for_attrs(&attrs); } @@ -487,7 +485,7 @@ impl<'tcx> SaveContext<'tcx> { ) } None => { - debug!("could not find container for method {} at {:?}", hir_id, span); + debug!("could not find container for method {:?} at {:?}", owner_id, span); // This is not necessarily a bug, if there was a compilation error, // the typeck results we need might not exist. return None; @@ -501,7 +499,7 @@ impl<'tcx> SaveContext<'tcx> { Some(Def { kind: DefKind::Method, - id: id_from_def_id(def_id), + id: id_from_def_id(owner_id.to_def_id()), span: self.span_from_span(ident.span), name: ident.name.to_string(), qualname, @@ -669,7 +667,7 @@ impl<'tcx> SaveContext<'tcx> { match res { Res::Local(id) => { - Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id, self) }) + Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id) }) } Res::Def(HirDefKind::Trait, def_id) if fn_type(path_seg) => { Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) }) @@ -1033,18 +1031,15 @@ fn id_from_def_id(id: DefId) -> rls_data::Id { rls_data::Id { krate: id.krate.as_u32(), index: id.index.as_u32() } } -fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_>) -> rls_data::Id { - let def_id = scx.tcx.hir().opt_local_def_id(id); - def_id.map(|id| id_from_def_id(id.to_def_id())).unwrap_or_else(|| { - // Create a *fake* `DefId` out of a `HirId` by combining the owner - // `local_def_index` and the `local_id`. - // This will work unless you have *billions* of definitions in a single - // crate (very unlikely to actually happen). - rls_data::Id { - krate: LOCAL_CRATE.as_u32(), - index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(), - } - }) +fn id_from_hir_id(id: hir::HirId) -> rls_data::Id { + // Create a *fake* `DefId` out of a `HirId` by combining the owner + // `local_def_index` and the `local_id`. + // This will work unless you have *billions* of definitions in a single + // crate (very unlikely to actually happen). + rls_data::Id { + krate: LOCAL_CRATE.as_u32(), + index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(), + } } fn null_id() -> rls_data::Id { diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 5a1bcb8fdc8..979305547c1 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -25,7 +25,7 @@ // // FIXME where clauses need implementing, defs/refs in generics are mostly missing. -use crate::{id_from_def_id, id_from_hir_id, SaveContext}; +use crate::{id_from_def_id, SaveContext}; use rls_data::{SigElement, Signature}; @@ -34,6 +34,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir_pretty::id_to_string; use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string}; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> { @@ -71,7 +72,7 @@ pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> O } pub fn method_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, generics: &hir::Generics<'_>, m: &hir::FnSig<'_>, @@ -84,7 +85,7 @@ pub fn method_signature( } pub fn assoc_const_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Symbol, ty: &hir::Ty<'_>, default: Option<&hir::Expr<'_>>, @@ -97,7 +98,7 @@ pub fn assoc_const_signature( } pub fn assoc_type_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, bounds: Option<hir::GenericBounds<'_>>, default: Option<&hir::Ty<'_>>, @@ -112,7 +113,8 @@ pub fn assoc_type_signature( type Result = std::result::Result<Signature, &'static str>; trait Sig { - fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result; + type Parent; + fn make(&self, offset: usize, id: Option<Self::Parent>, scx: &SaveContext<'_>) -> Result; } fn extend_sig( @@ -148,6 +150,7 @@ fn text_sig(text: String) -> Signature { } impl<'hir> Sig for hir::Ty<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let id = Some(self.hir_id); match self.kind { @@ -326,6 +329,7 @@ impl<'hir> Sig for hir::Ty<'hir> { } impl<'hir> Sig for hir::Item<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let id = Some(self.hir_id()); @@ -391,7 +395,7 @@ impl<'hir> Sig for hir::Item<'hir> { text.push_str("fn "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push('('); for i in decl.inputs { @@ -441,7 +445,7 @@ impl<'hir> Sig for hir::Item<'hir> { hir::ItemKind::TyAlias(ref ty, ref generics) => { let text = "type ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" = "); let ty = ty.make(offset + sig.text.len(), id, scx)?; @@ -453,21 +457,21 @@ impl<'hir> Sig for hir::Item<'hir> { hir::ItemKind::Enum(_, ref generics) => { let text = "enum ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" {}"); Ok(sig) } hir::ItemKind::Struct(_, ref generics) => { let text = "struct ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" {}"); Ok(sig) } hir::ItemKind::Union(_, ref generics) => { let text = "union ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" {}"); Ok(sig) } @@ -483,7 +487,7 @@ impl<'hir> Sig for hir::Item<'hir> { } text.push_str("trait "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; if !bounds.is_empty() { sig.text.push_str(": "); @@ -498,7 +502,7 @@ impl<'hir> Sig for hir::Item<'hir> { let mut text = String::new(); text.push_str("trait "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; if !bounds.is_empty() { sig.text.push_str(" = "); @@ -532,7 +536,8 @@ impl<'hir> Sig for hir::Item<'hir> { text.push_str(" const"); } - let generics_sig = generics.make(offset + text.len(), id, scx)?; + let generics_sig = + generics.make(offset + text.len(), Some(self.owner_id.def_id), scx)?; text.push_str(&generics_sig.text); text.push(' '); @@ -575,6 +580,7 @@ impl<'hir> Sig for hir::Item<'hir> { } impl<'hir> Sig for hir::Path<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let res = scx.get_path_res(id.ok_or("Missing id for Path")?); @@ -609,7 +615,8 @@ impl<'hir> Sig for hir::Path<'hir> { // This does not cover the where clause, which must be processed separately. impl<'hir> Sig for hir::Generics<'hir> { - fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { + type Parent = LocalDefId; + fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result { if self.params.is_empty() { return Ok(text_sig(String::new())); } @@ -624,7 +631,7 @@ impl<'hir> Sig for hir::Generics<'hir> { } param_text.push_str(param.name.ident().as_str()); defs.push(SigElement { - id: id_from_hir_id(param.hir_id, scx), + id: id_from_def_id(param.def_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + param_text.as_str().len(), }); @@ -646,12 +653,13 @@ impl<'hir> Sig for hir::Generics<'hir> { } impl<'hir> Sig for hir::FieldDef<'hir> { - fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { + type Parent = LocalDefId; + fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result { let mut text = String::new(); text.push_str(&self.ident.to_string()); let defs = Some(SigElement { - id: id_from_hir_id(self.hir_id, scx), + id: id_from_def_id(self.def_id.to_def_id()), start: offset, end: offset + text.len(), }); @@ -666,13 +674,14 @@ impl<'hir> Sig for hir::FieldDef<'hir> { } impl<'hir> Sig for hir::Variant<'hir> { - fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { + type Parent = LocalDefId; + fn make(&self, offset: usize, parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result { let mut text = self.ident.to_string(); match self.data { hir::VariantData::Struct(fields, r) => { let id = parent_id.ok_or("Missing id for Variant's parent")?; let name_def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: offset, end: offset + text.len(), }; @@ -693,9 +702,9 @@ impl<'hir> Sig for hir::Variant<'hir> { text.push('}'); Ok(Signature { text, defs, refs }) } - hir::VariantData::Tuple(fields, id, _) => { + hir::VariantData::Tuple(fields, _, def_id) => { let name_def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(def_id.to_def_id()), start: offset, end: offset + text.len(), }; @@ -703,7 +712,7 @@ impl<'hir> Sig for hir::Variant<'hir> { let mut defs = vec![name_def]; let mut refs = vec![]; for f in fields { - let field_sig = f.make(offset + text.len(), Some(id), scx)?; + let field_sig = f.make(offset + text.len(), Some(def_id), scx)?; text.push_str(&field_sig.text); text.push_str(", "); defs.extend(field_sig.defs.into_iter()); @@ -712,9 +721,9 @@ impl<'hir> Sig for hir::Variant<'hir> { text.push(')'); Ok(Signature { text, defs, refs }) } - hir::VariantData::Unit(id, _) => { + hir::VariantData::Unit(_, def_id) => { let name_def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(def_id.to_def_id()), start: offset, end: offset + text.len(), }; @@ -725,6 +734,7 @@ impl<'hir> Sig for hir::Variant<'hir> { } impl<'hir> Sig for hir::ForeignItem<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let id = Some(self.hir_id()); match self.kind { @@ -733,7 +743,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> { text.push_str("fn "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push('('); for i in decl.inputs { @@ -797,25 +807,25 @@ fn name_and_generics( mut text: String, offset: usize, generics: &hir::Generics<'_>, - id: hir::HirId, + id: hir::OwnerId, name: Ident, scx: &SaveContext<'_>, ) -> Result { let name = name.to_string(); let def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }; text.push_str(&name); - let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; + let generics: Signature = generics.make(offset + text.len(), Some(id.def_id), scx)?; // FIXME where clause let text = format!("{}{}", text, generics.text); Ok(extend_sig(generics, text, vec![def], vec![])) } fn make_assoc_type_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, bounds: Option<hir::GenericBounds<'_>>, default: Option<&hir::Ty<'_>>, @@ -824,7 +834,7 @@ fn make_assoc_type_signature( let mut text = "type ".to_owned(); let name = ident.to_string(); let mut defs = vec![SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: text.len(), end: text.len() + name.len(), }]; @@ -837,7 +847,7 @@ fn make_assoc_type_signature( } if let Some(default) = default { text.push_str(" = "); - let ty_sig = default.make(text.len(), Some(id), scx)?; + let ty_sig = default.make(text.len(), Some(id.into()), scx)?; text.push_str(&ty_sig.text); defs.extend(ty_sig.defs.into_iter()); refs.extend(ty_sig.refs.into_iter()); @@ -847,7 +857,7 @@ fn make_assoc_type_signature( } fn make_assoc_const_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Symbol, ty: &hir::Ty<'_>, default: Option<&hir::Expr<'_>>, @@ -856,7 +866,7 @@ fn make_assoc_const_signature( let mut text = "const ".to_owned(); let name = ident.to_string(); let mut defs = vec![SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: text.len(), end: text.len() + name.len(), }]; @@ -864,7 +874,7 @@ fn make_assoc_const_signature( text.push_str(&name); text.push_str(": "); - let ty_sig = ty.make(text.len(), Some(id), scx)?; + let ty_sig = ty.make(text.len(), Some(id.into()), scx)?; text.push_str(&ty_sig.text); defs.extend(ty_sig.defs.into_iter()); refs.extend(ty_sig.refs.into_iter()); @@ -878,7 +888,7 @@ fn make_assoc_const_signature( } fn make_method_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, generics: &hir::Generics<'_>, m: &hir::FnSig<'_>, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 586454f7657..c49c5fa9904 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -864,18 +864,6 @@ pub enum CrateType { ProcMacro, } -impl CrateType { - /// When generated, is this crate type an archive? - pub fn is_archive(&self) -> bool { - match *self { - CrateType::Rlib | CrateType::Staticlib => true, - CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => { - false - } - } - } -} - #[derive(Clone, Hash, Debug, PartialEq, Eq)] pub enum Passes { Some(Vec<String>), @@ -957,6 +945,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { if sess.target.has_thread_local { ret.insert((sym::target_thread_local, None)); } + let mut has_atomic = false; for (i, align) in [ (8, layout.i8_align.abi), (16, layout.i16_align.abi), @@ -965,6 +954,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { (128, layout.i128_align.abi), ] { if i >= min_atomic_width && i <= max_atomic_width { + has_atomic = true; let mut insert_atomic = |s, align: Align| { ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); if atomic_cas { @@ -981,6 +971,12 @@ fn default_configuration(sess: &Session) -> CrateConfig { } } } + if sess.is_nightly_build() && has_atomic { + ret.insert((sym::target_has_atomic_load_store, None)); + if atomic_cas { + ret.insert((sym::target_has_atomic, None)); + } + } let panic_strategy = sess.panic_strategy(); ret.insert((sym::panic, Some(panic_strategy.desc_symbol()))); @@ -2577,6 +2573,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "hir,typed" => Hir(PpHirMode::Typed), "hir-tree" => HirTree, "thir-tree" => ThirTree, + "thir-flat" => ThirFlat, "mir" => Mir, "mir-cfg" => MirCFG, name => early_error( @@ -2585,7 +2582,8 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ - `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}" + `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \ + `mir-cfg`; got {name}" ), ), }; @@ -2740,6 +2738,8 @@ pub enum PpMode { HirTree, /// `-Zunpretty=thir-tree` ThirTree, + /// `-Zunpretty=`thir-flat` + ThirFlat, /// `-Zunpretty=mir` Mir, /// `-Zunpretty=mir-cfg` @@ -2758,6 +2758,7 @@ impl PpMode { | Hir(_) | HirTree | ThirTree + | ThirFlat | Mir | MirCFG => true, } @@ -2767,13 +2768,13 @@ impl PpMode { match *self { Source(_) | AstTree(_) => false, - Hir(_) | HirTree | ThirTree | Mir | MirCFG => true, + Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, } } pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Mir | MirCFG | ThirTree) + matches!(*self, Mir | MirCFG | ThirTree | ThirFlat) } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7b5fd6cc2a8..0db4d85ff4b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1290,6 +1290,8 @@ options! { (default: no)"), drop_tracking: bool = (false, parse_bool, [TRACKED], "enables drop tracking in generators (default: no)"), + drop_tracking_mir: bool = (false, parse_bool, [TRACKED], + "enables drop tracking on MIR in generators (default: no)"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1616,6 +1618,8 @@ options! { "measure time of each LLVM pass (default: no)"), time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), + tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED], + "sets a tiny, non-configurable limit for const eval; useful for compiler tests"), #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED], "choose the TLS model to use (`rustc --print tls-models` for details)"), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7597b8d126a..f1119214be4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -288,6 +288,7 @@ symbols! { Target, ToOwned, ToString, + TokenStream, Try, TryCaptureGeneric, TryCapturePrintable, @@ -723,11 +724,17 @@ symbols! { forbid, forget, format, + format_alignment, format_args, format_args_capture, format_args_macro, format_args_nl, + format_argument, + format_arguments, + format_count, format_macro, + format_placeholder, + format_unsafe_arg, freeze, freg, frem_fast, @@ -948,6 +955,7 @@ symbols! { mul, mul_assign, mul_with_overflow, + multiple_supertrait_upcastable, must_not_suspend, must_use, naked, diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 0759b95bd94..c9b4ab0a38d 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -640,6 +640,7 @@ fn encode_ty<'tcx>( ty::Bound(..) | ty::Error(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Infer(..) | ty::Alias(..) | ty::Param(..) @@ -793,6 +794,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty::Bound(..) | ty::Error(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Infer(..) | ty::Alias(..) | ty::Param(..) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0d446d654dc..00d1ff5ceed 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -490,6 +490,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { } ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), + ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"), } // Only cache types that do not refer to an enclosing diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs index 4a2d39cc700..247256f076b 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/abi/call/loongarch.rs @@ -39,7 +39,7 @@ where { match arg_layout.abi { Abi::Scalar(scalar) => match scalar.primitive() { - abi::Int(..) | abi::Pointer => { + abi::Int(..) | abi::Pointer(_) => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 3b8c867d35b..a0730fbb650 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -346,7 +346,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { // The primitive for this algorithm. Abi::Scalar(scalar) => { let kind = match scalar.primitive() { - abi::Int(..) | abi::Pointer => RegKind::Integer, + abi::Int(..) | abi::Pointer(_) => RegKind::Integer, abi::F32 | abi::F64 => RegKind::Float, }; Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 34280d38e34..d90dce2a087 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -45,7 +45,7 @@ where { match arg_layout.abi { Abi::Scalar(scalar) => match scalar.primitive() { - abi::Int(..) | abi::Pointer => { + abi::Int(..) | abi::Pointer(_) => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index c8b6ac5ae25..cbed5b4afc1 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -20,7 +20,7 @@ where { let dl = cx.data_layout(); - if !scalar.primitive().is_float() { + if !matches!(scalar.primitive(), abi::F32 | abi::F64) { return data; } @@ -83,11 +83,11 @@ where (abi::F32, _) => offset += Reg::f32().size, (_, abi::F64) => offset += Reg::f64().size, (abi::Int(i, _signed), _) => offset += i.size(), - (abi::Pointer, _) => offset += Reg::i64().size, + (abi::Pointer(_), _) => offset += Reg::i64().size, _ => {} } - if (offset.bytes() % 4) != 0 && scalar2.primitive().is_float() { + if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) { offset += Size::from_bytes(4 - (offset.bytes() % 4)); } data = arg_scalar(cx, scalar2, offset, data); diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index c0c071a614f..9427f27d1b7 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -50,7 +50,7 @@ where Abi::Uninhabited => return Ok(()), Abi::Scalar(scalar) => match scalar.primitive() { - abi::Int(..) | abi::Pointer => Class::Int, + abi::Int(..) | abi::Pointer(_) => Class::Int, abi::F32 | abi::F64 => Class::Sse, }, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 88a0a1f8ecf..39761baf1bc 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -129,7 +129,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { C: HasDataLayout, { match self.abi { - Abi::Scalar(scalar) => scalar.primitive().is_float(), + Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64), Abi::Aggregate { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_fp_element(cx) diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs index 2b00cda44b5..4d03747d016 100644 --- a/compiler/rustc_target/src/spec/bpf_base.rs +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -6,7 +6,7 @@ pub fn opts(endian: Endian) -> TargetOptions { allow_asm: true, endian, linker_flavor: LinkerFlavor::Bpf, - atomic_cas: true, + atomic_cas: false, dynamic_linking: true, no_builtins: true, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index cdb72d49834..e44fd82ba22 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,6 +1,8 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; +#[cfg(doc)] +use super::trait_goals::structural_traits::*; use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; @@ -76,7 +78,7 @@ pub(super) enum CandidateSource { /// let _y = x.clone(); /// } /// ``` - AliasBound(usize), + AliasBound, } pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { @@ -98,41 +100,79 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; + // A type implements an `auto trait` if its components do as well. These components + // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A type is `Copy` or `Clone` if its components are `Sized`. These components + // are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These + // components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A type is `PointerSized` if we can compute its layout, and that layout + // matches the layout of `usize`. fn consider_builtin_pointer_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>` + // family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, ) -> QueryResult<'tcx>; + // `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + // `Pointee` is always implemented. + // + // See the projection implementation for the `Metadata` types for all of + // the built-in types. For structs, the metadata type is given by the struct + // tail. + fn consider_builtin_pointee_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + // A generator (that comes from an `async` desugaring) is known to implement + // `Future<Output = O>`, where `O` is given by the generator's return type + // that was computed during type-checking. + fn consider_builtin_future_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + // A generator (that doesn't come from an `async` desugaring) is known to + // implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield, + // and return types of the generator computed during type-checking. + fn consider_builtin_generator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -202,8 +242,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type - // could be normalized to yet another projection with different item bounds. let normalized_candidates = self.assemble_and_evaluate_candidates(goal); for mut normalized_candidate in normalized_candidates { normalized_candidate.result = @@ -259,6 +297,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if lang_items.tuple_trait() == Some(trait_def_id) { G::consider_builtin_tuple_candidate(self, goal) + } else if lang_items.pointee_trait() == Some(trait_def_id) { + G::consider_builtin_pointee_candidate(self, goal) + } else if lang_items.future_trait() == Some(trait_def_id) { + G::consider_builtin_future_candidate(self, goal) + } else if lang_items.gen_trait() == Some(trait_def_id) { + G::consider_builtin_generator_candidate(self, goal) } else { Err(NoSolution) }; @@ -310,25 +354,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Param(_) | ty::Placeholder(..) - | ty::Infer(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, - ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), ty::Alias(_, alias_ty) => alias_ty, }; - for (i, (assumption, _)) in self + for (assumption, _) in self .tcx() .bound_explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(self.tcx(), alias_ty.substs) - .enumerate() { match G::consider_assumption(self, goal, assumption) { Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) + candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } Err(NoSolution) => (), } @@ -360,13 +405,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Param(_) | ty::Placeholder(..) - | ty::Infer(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, - ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), ty::Dynamic(bounds, ..) => bounds, }; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 40b9bedc84f..a2c15123b4f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,14 +1,14 @@ use std::mem; -use rustc_infer::{ - infer::InferCtxt, - traits::{ - query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation, - SelectionError, TraitEngine, - }, +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::{ + query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, + PredicateObligation, SelectionError, TraitEngine, }; +use rustc_middle::ty; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use super::{search_graph, Certainty, EvalCtxt}; +use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. /// @@ -40,12 +40,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations.push(obligation); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - let errors = self.select_where_possible(infcx); - if !errors.is_empty() { - return errors; - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { self.obligations .drain(..) .map(|obligation| FulfillmentError { @@ -66,16 +61,60 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let search_graph = &mut search_graph::SearchGraph::new(infcx.tcx); - let mut ecx = EvalCtxt::new_outside_solver(infcx, search_graph); - let (changed, certainty) = match ecx.evaluate_goal(goal) { + let (changed, certainty) = match infcx.evaluate_root_goal(goal) { Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), + code: match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { + FulfillmentErrorCode::CodeProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.replace_bound_vars_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.replace_bound_vars_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::ConstEquate(a, b) => { + let (a, b) = infcx.replace_bound_vars_with_placeholders( + goal.predicate.kind().rebind((a, b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::CodeConstEquateError( + expected_found, + TypeError::ConstMismatch(expected_found), + ) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::WellFormed(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(_, _, _) + | ty::PredicateKind::ConstEvaluatable(_) + | ty::PredicateKind::TypeWellFormedFromEnv(_) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ) + } + }, root_obligation: obligation, }); continue; @@ -100,4 +139,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { self.obligations.clone() } + + fn drain_unstalled_obligations( + &mut self, + _: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + unimplemented!() + } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index da2a1a19957..dd16672cc7a 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -13,14 +13,12 @@ // preserves universes and creates a unique var (in the highest universe) for each // appearance of a region. -// FIXME: `CanonicalVarValues` should be interned and `Copy`. - // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. use std::mem; use rustc_hir::def_id::DefId; -use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues}; +use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; @@ -141,14 +139,33 @@ type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; /// solver, merge the two responses again. pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; -pub trait TyCtxtExt<'tcx> { - fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx>; +pub trait InferCtxtEvalExt<'tcx> { + /// Evaluates a goal from **outside** of the trait solver. + /// + /// Using this while inside of the solver is wrong as it uses a new + /// search graph which would break cycle detection. + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution>; } -impl<'tcx> TyCtxtExt<'tcx> for TyCtxt<'tcx> { - fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> { - let mut search_graph = search_graph::SearchGraph::new(self); - EvalCtxt::evaluate_canonical_goal(self, &mut search_graph, goal) +impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { + fn evaluate_root_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(bool, Certainty), NoSolution> { + let mut search_graph = search_graph::SearchGraph::new(self.tcx); + + let result = EvalCtxt { + search_graph: &mut search_graph, + infcx: self, + var_values: CanonicalVarValues::dummy(), + } + .evaluate_goal(goal); + + assert!(search_graph.is_empty()); + result } } @@ -164,18 +181,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.infcx.tcx } - /// Creates a new evaluation context outside of the trait solver. + /// The entry point of the solver. /// - /// With this solver making a canonical response doesn't make much sense. - /// The `search_graph` for this solver has to be completely empty. - fn new_outside_solver( - infcx: &'a InferCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph<'tcx>, - ) -> EvalCtxt<'a, 'tcx> { - assert!(search_graph.is_empty()); - EvalCtxt { infcx, var_values: CanonicalVarValues::dummy(), search_graph } - } - + /// This function deals with (coinductive) cycles, overflow, and caching + /// and then calls [`EvalCtxt::compute_goal`] which contains the actual + /// logic of the solver. + /// + /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] + /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're + /// outside of it. #[instrument(level = "debug", skip(tcx, search_graph), ret)] fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, @@ -209,7 +223,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let external_constraints = take_external_constraints(self.infcx)?; Ok(self.infcx.canonicalize_response(Response { - var_values: self.var_values.clone(), + var_values: self.var_values, external_constraints, certainty, })) @@ -259,12 +273,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { param_env, predicate: (def_id, substs, kind), }), + ty::PredicateKind::ObjectSafe(trait_def_id) => { + self.compute_object_safe_goal(trait_def_id) + } + ty::PredicateKind::WellFormed(arg) => { + self.compute_well_formed_goal(Goal { param_env, predicate: arg }) + } ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS), // FIXME: implement these predicates :) - ty::PredicateKind::WellFormed(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ConstEvaluatable(_) - | ty::PredicateKind::ConstEquate(_, _) => { + ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => { self.make_canonical_response(Certainty::Yes) } ty::PredicateKind::TypeWellFormedFromEnv(..) => { @@ -316,15 +333,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // That won't actually reflect in the query response, so it seems moot. self.make_canonical_response(Certainty::AMBIGUOUS) } else { - self.infcx.probe(|_| { - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), goal.param_env) - .sub(goal.predicate.a, goal.predicate.b)?; - self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|pred| pred.into()).collect(), - ) - }) + let InferOk { value: (), obligations } = self + .infcx + .at(&ObligationCause::dummy(), goal.param_env) + .sub(goal.predicate.a, goal.predicate.b)?; + self.evaluate_all_and_make_canonical_response( + obligations.into_iter().map(|pred| pred.into()).collect(), + ) } } @@ -344,9 +359,35 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Err(NoSolution) } } + + fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { + if self.tcx().check_is_object_safe(trait_def_id) { + self.make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } + + fn compute_well_formed_goal( + &mut self, + goal: Goal<'tcx, ty::GenericArg<'tcx>>, + ) -> QueryResult<'tcx> { + match crate::traits::wf::unnormalized_obligations( + self.infcx, + goal.param_env, + goal.predicate, + ) { + Some(obligations) => self.evaluate_all_and_make_canonical_response( + obligations.into_iter().map(|o| o.into()).collect(), + ), + None => self.make_canonical_response(Certainty::AMBIGUOUS), + } + } } impl<'tcx> EvalCtxt<'_, 'tcx> { + // Recursively evaluates a list of goals to completion, returning the certainty + // of all of the goals. fn evaluate_all( &mut self, mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, @@ -383,6 +424,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + // Recursively evaluates a list of goals to completion, making a query response. + // + // This is just a convenient way of calling [`EvalCtxt::evaluate_all`], + // then [`EvalCtxt::make_canonical_response`]. fn evaluate_all_and_make_canonical_response( &mut self, goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, @@ -436,32 +481,11 @@ pub(super) fn response_no_constraints<'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(); - Ok(Canonical { max_universe: goal.max_universe, variables: goal.variables, value: Response { - var_values: CanonicalVarValues { var_values }, + var_values: CanonicalVarValues::make_identity(tcx, goal.variables), external_constraints: Default::default(), certainty, }, diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 32e15f03998..b175a6dde17 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -7,6 +7,7 @@ use super::{Certainty, EvalCtxt, Goal, QueryResult}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; @@ -15,7 +16,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor}; use rustc_middle::ty::{ToPredicate, TypeVisitable}; -use rustc_span::DUMMY_SP; +use rustc_span::{sym, DUMMY_SP}; use std::iter; use std::ops::ControlFlow; @@ -27,8 +28,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // To only compute normalization once for each projection we only // normalize if the expected term is an unconstrained inference variable. // - // E.g. for `<T as Trait>::Assoc = u32` we recursively compute the goal - // `exists<U> <T as Trait>::Assoc = U` and then take the resulting type for + // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal + // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for // `U` and equate it with `u32`. This means that we don't need a separate // projection cache in the solver. if self.term_is_fully_unconstrained(goal) { @@ -92,24 +93,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if t.needs_infer() { if ty::Term::from(t) == self.term { - ControlFlow::BREAK + ControlFlow::Break(()) } else { t.super_visit_with(self) } } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if c.needs_infer() { if ty::Term::from(c) == self.term { - ControlFlow::BREAK + ControlFlow::Break(()) } else { c.super_visit_with(self) } } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -170,7 +171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::BuiltinImpl, _) - | (CandidateSource::AliasBound(_), _) => unimplemented!(), + | (CandidateSource::AliasBound, _) => unimplemented!(), } } } @@ -295,7 +296,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() + && poly_projection_pred.projection_def_id() == goal.predicate.def_id() + { ecx.infcx.probe(|_| { let assumption_projection_pred = ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred); @@ -391,6 +394,166 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ) -> QueryResult<'tcx> { bug!("`Tuple` does not have an associated type: {:?}", goal); } + + fn consider_builtin_pointee_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); + ecx.infcx.probe(|_| { + let metadata_ty = match goal.predicate.self_ty().kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Foreign(..) => tcx.types.unit, + + ty::Error(e) => tcx.ty_error_with_guaranteed(*e), + + ty::Str | ty::Slice(_) => tcx.types.usize, + + ty::Dynamic(_, _, _) => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + tcx.bound_type_of(dyn_metadata) + .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) + } + + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { + // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. + let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref( + LangItem::Sized, + [ty::GenericArg::from(goal.predicate.self_ty())], + )); + + let mut nested_goals = ecx.infcx.eq( + goal.param_env, + goal.predicate.term.ty().unwrap(), + tcx.types.unit, + )?; + nested_goals.push(goal.with(tcx, sized_predicate)); + + return ecx.evaluate_all_and_make_canonical_response(nested_goals); + } + + ty::Adt(def, substs) if def.is_struct() => { + match def.non_enum_variant().fields.last() { + None => tcx.types.unit, + Some(field_def) => { + let self_ty = field_def.ty(tcx, substs); + let new_goal = goal.with( + tcx, + ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), + ); + return ecx.evaluate_all_and_make_canonical_response(vec![new_goal]); + } + } + } + ty::Adt(_, _) => tcx.types.unit, + + ty::Tuple(elements) => match elements.last() { + None => tcx.types.unit, + Some(&self_ty) => { + let new_goal = goal.with( + tcx, + ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), + ); + return ecx.evaluate_all_and_make_canonical_response(vec![new_goal]); + } + }, + + ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) + | ty::Bound(..) => bug!( + "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", + goal.predicate.self_ty() + ), + }; + + let nested_goals = + ecx.infcx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), metadata_ty)?; + ecx.evaluate_all_and_make_canonical_response(nested_goals) + }) + } + + fn consider_builtin_future_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let self_ty = goal.predicate.self_ty(); + let ty::Generator(def_id, substs, _) = *self_ty.kind() else { + return Err(NoSolution); + }; + + // Generators are not futures unless they come from `async` desugaring + let tcx = ecx.tcx(); + if !tcx.generator_is_async(def_id) { + return Err(NoSolution); + } + + let term = substs.as_generator().return_ty().into(); + + Self::consider_assumption( + ecx, + goal, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]), + term, + }) + .to_predicate(tcx), + ) + } + + fn consider_builtin_generator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let self_ty = goal.predicate.self_ty(); + let ty::Generator(def_id, substs, _) = *self_ty.kind() else { + return Err(NoSolution); + }; + + // `async`-desugared generators do not implement the generator trait + let tcx = ecx.tcx(); + if tcx.generator_is_async(def_id) { + return Err(NoSolution); + } + + let generator = substs.as_generator(); + + let name = tcx.associated_item(goal.predicate.def_id()).name; + let term = if name == sym::Return { + generator.return_ty().into() + } else if name == sym::Yield { + generator.yield_ty().into() + } else { + bug!("unexpected associated item `<{self_ty} as Generator>::{name}`") + }; + + Self::consider_assumption( + ecx, + goal, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: ecx + .tcx() + .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]), + term, + }) + .to_predicate(tcx), + ) + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs index 730a8e61258..80a388b8498 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs @@ -95,6 +95,7 @@ impl<'tcx> ProvisionalCache<'tcx> { } pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> { + // FIXME: Responses should probably be `Copy` as well self.entries[entry_index].response.clone() } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 4b6d673c999..1ea8fb8fd3d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -65,7 +65,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() + && poly_trait_pred.def_id() == goal.predicate.def_id() + { // FIXME: Constness and polarity ecx.infcx.probe(|_| { let assumption_trait_pred = @@ -185,6 +187,57 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) } } + + fn consider_builtin_pointee_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + _goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.make_canonical_response(Certainty::Yes) + } + + fn consider_builtin_future_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + // Generators are not futures unless they come from `async` desugaring + let tcx = ecx.tcx(); + if !tcx.generator_is_async(def_id) { + return Err(NoSolution); + } + + // Async generator unconditionally implement `Future` + ecx.make_canonical_response(Certainty::Yes) + } + + fn consider_builtin_generator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let self_ty = goal.predicate.self_ty(); + let ty::Generator(def_id, substs, _) = *self_ty.kind() else { + return Err(NoSolution); + }; + + // `async`-desugared generators do not implement the generator trait + let tcx = ecx.tcx(); + if tcx.generator_is_async(def_id) { + return Err(NoSolution); + } + + let generator = substs.as_generator(); + Self::consider_assumption( + ecx, + goal, + ty::Binder::dummy( + tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]), + ) + .to_predicate(tcx), + ) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -269,7 +322,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match (candidate.source, other.source) { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound(_), _) + | (CandidateSource::AliasBound, _) | (CandidateSource::BuiltinImpl, _) => unimplemented!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index a11cd13cb08..5007a019e18 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -24,15 +24,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Never | ty::Char => Ok(vec![]), - ty::Placeholder(..) - | ty::Dynamic(..) + ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) | ty::Alias(ty::Projection, ..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) => Err(NoSolution), + | ty::Placeholder(..) => Err(NoSolution), - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected type `{ty}`") + } ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { Ok(vec![element_ty]) @@ -56,6 +57,8 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) } + ty::GeneratorWitnessMIR(..) => todo!(), + // For `PhantomData<T>`, we pass `T`. ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), @@ -87,6 +90,7 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -99,11 +103,12 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Foreign(..) | ty::Alias(..) | ty::Param(_) - | ty::Infer(ty::TyVar(_)) => Err(NoSolution), + | ty::Placeholder(..) => Err(NoSolution), - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected type `{ty}`") + } ty::Tuple(tys) => Ok(tys.to_vec()), @@ -148,11 +153,12 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Adt(_, _) | ty::Alias(_, _) | ty::Param(_) - | ty::Infer(ty::TyVar(_)) => Err(NoSolution), + | ty::Placeholder(..) => Err(NoSolution), - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected type `{ty}`") + } ty::Tuple(tys) => Ok(tys.to_vec()), @@ -170,9 +176,12 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::GeneratorWitness(types) => { Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) } + + ty::GeneratorWitnessMIR(..) => todo!(), } } +// Returns a binder of the tupled inputs types and output type from a builtin callable type. pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>, @@ -180,7 +189,7 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( ) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> { match *self_ty.kind() { ty::FnDef(def_id, substs) => Ok(Some( - tcx.bound_fn_sig(def_id) + tcx.fn_sig(def_id) .subst(tcx, substs) .map_bound(|sig| (tcx.mk_tup(sig.inputs().iter()), sig.output())), )), @@ -211,13 +220,18 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( | ty::Dynamic(_, _, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Alias(_, _) | ty::Param(_) - | ty::Placeholder(_) - | ty::Bound(_, _) - | ty::Infer(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected type `{self_ty}`") + } } } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 61d09189798..e26bef0b8b7 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -40,15 +40,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.obligations.insert(obligation); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - { - let errors = self.select_where_possible(infcx); - - if !errors.is_empty() { - return errors; - } - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { // any remaining obligations are errors self.obligations .iter() @@ -143,6 +135,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { errors } + fn drain_unstalled_obligations( + &mut self, + _: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + unimplemented!() + } + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { self.obligations.iter().cloned().collect() } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 225c1050c7c..61f508a7a07 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,7 +17,6 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; @@ -382,18 +381,14 @@ fn resolve_negative_obligation<'tcx>( return false; } - let (body_id, body_def_id) = if let Some(body_def_id) = body_def_id.as_local() { - (tcx.hir().local_def_id_to_hir_id(body_def_id), body_def_id) - } else { - (CRATE_HIR_ID, CRATE_DEF_ID) - }; + let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID); let ocx = ObligationCtxt::new(&infcx); let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id); let outlives_env = OutlivesEnvironment::with_bounds( param_env, Some(&infcx), - infcx.implied_bounds_tys(param_env, body_id, wf_tys), + infcx.implied_bounds_tys(param_env, body_def_id, wf_tys), ); infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); @@ -701,7 +696,9 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { // This should only be created when checking whether we have to check whether some // auto trait impl applies. There will never be multiple impls, so we can just // act as if it were a local type here. - ty::GeneratorWitness(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } ty::Alias(ty::Opaque, ..) => { // This merits some explanation. // Normally, opaque types are not involved when performing diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 369f80139a8..a2ddd91546c 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -190,8 +190,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { let tcx = self.infcx.tcx; let assumed_wf_types = tcx.assumed_wf_types(def_id); let mut implied_bounds = FxIndexSet::default(); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let cause = ObligationCause::misc(span, hir_id); + let cause = ObligationCause::misc(span, def_id); for ty in assumed_wf_types { // FIXME(@lcnr): rustc currently does not check wf for types // pre-normalization, meaning that implied bounds are sometimes diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 0419bb3f724..6bf453c3ff0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -81,7 +81,7 @@ pub fn recompute_applicable_impls<'tcx>( ); let predicates = - tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx); + tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) { let kind = obligation.predicate.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 52971486c55..e9842b2cba5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -101,6 +101,18 @@ pub trait InferCtxtExt<'tcx> { } pub trait TypeErrCtxtExt<'tcx> { + fn build_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + T: fmt::Display + + TypeFoldable<'tcx> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + fn report_overflow_error<T>( &self, predicate: &T, @@ -484,6 +496,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, { + let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit); + mutate(&mut err); + err.emit(); + + self.tcx.sess.abort_if_errors(); + bug!(); + } + + fn build_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + T: fmt::Display + + TypeFoldable<'tcx> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + { let predicate = self.resolve_vars_if_possible(predicate.clone()); let mut pred_str = predicate.to_string(); @@ -511,11 +543,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - mutate(&mut err); - - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); + err } /// Reports that an overflow has occurred and halts compilation. We @@ -839,14 +867,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note(s.as_str()); } if let Some(ref s) = parent_label { - let body = tcx - .hir() - .opt_local_def_id(obligation.cause.body_id) - .unwrap_or_else(|| { - tcx.hir().body_owner_def_id(hir::BodyId { - hir_id: obligation.cause.body_id, - }) - }); + let body = obligation.cause.body_id; err.span_label(tcx.def_span(body), s); } @@ -934,6 +955,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } + let body_hir_id = + self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); // Try to report a help message if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( @@ -1014,7 +1037,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if !self.report_similar_impl_candidates( impl_candidates, trait_ref, - obligation.cause.body_id, + body_hir_id, &mut err, true, ) { @@ -1050,7 +1073,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.report_similar_impl_candidates( impl_candidates, trait_ref, - obligation.cause.body_id, + body_hir_id, &mut err, true, ); @@ -1896,6 +1919,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Generator(..) => Some(16), ty::Foreign(..) => Some(17), ty::GeneratorWitness(..) => Some(18), + ty::GeneratorWitnessMIR(..) => Some(19), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } @@ -2305,10 +2329,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate.to_opt_poly_trait_pred().unwrap(), ); if impl_candidates.len() < 10 { + let hir = + self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); self.report_similar_impl_candidates( impl_candidates, trait_ref, - body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id), + body_id.map(|id| id.hir_id).unwrap_or(hir), &mut err, false, ); @@ -2828,7 +2854,7 @@ pub struct FindExprBySpan<'hir> { } impl<'hir> FindExprBySpan<'hir> { - fn new(span: Span) -> Self { + pub fn new(span: Span) -> Self { Self { span, result: None, ty_result: None } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 18d308f7123..a3209d35e58 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -149,10 +149,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs)); let trait_ref = trait_ref.skip_binder(); - let mut flags = vec![( - sym::ItemContext, - self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), - )]; + let body_hir = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); + let mut flags = + vec![(sym::ItemContext, self.describe_enclosure(body_hir).map(|s| s.to_owned()))]; match obligation.cause.code() { ObligationCauseCode::BuiltinDerivedObligation(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 39e50b2accf..b35b9d62759 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -9,7 +9,6 @@ use crate::infer::InferCtxt; use crate::traits::{NormalizeExt, ObligationCtxt}; use hir::def::CtorOf; -use hir::{Expr, HirId}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -22,6 +21,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; +use rustc_hir::{Expr, HirId}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime}; @@ -34,6 +34,7 @@ use rustc_middle::ty::{ IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeckResults, }; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -179,7 +180,7 @@ pub trait TypeErrCtxtExt<'tcx> { err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_item: Option<(&'static str, Ty<'tcx>)>, - body_id: hir::HirId, + body_id: LocalDefId, ); fn suggest_dereferences( @@ -398,7 +399,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// param for cleaner code. fn suggest_restriction<'tcx>( tcx: TyCtxt<'tcx>, - hir_id: HirId, + item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, msg: &str, err: &mut Diagnostic, @@ -417,7 +418,6 @@ fn suggest_restriction<'tcx>( { return; } - let Some(item_id) = hir_id.as_owner() else { return; }; let generics = tcx.generics_of(item_id); // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... if let Some((param, bound_str, fn_sig)) = @@ -522,7 +522,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, - body_id: hir::HirId, + mut body_id: LocalDefId, ) { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); @@ -535,8 +535,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. - let mut hir_id = body_id; - while let Some(node) = self.tcx.hir().find(hir_id) { + while let Some(node) = self.tcx.hir().find_by_def_id(body_id) { match node { hir::Node::Item(hir::Item { ident, @@ -547,7 +546,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Restricting `Self` for a single method. suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "`Self`", err, @@ -567,7 +566,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred, + self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred, None, ); return; @@ -589,7 +588,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "the associated type", err, @@ -609,7 +608,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "the associated type", err, @@ -713,8 +712,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => {} } - - hir_id = self.tcx.hir().get_parent_item(hir_id).into(); + body_id = self.tcx.local_parent(body_id); } } @@ -905,8 +903,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred.self_ty(), ); + let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( - obligation.cause.body_id, + body_hir_id, obligation.param_env, self_ty, ) else { return false; }; @@ -1004,8 +1003,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.remove_mark(); } let mut expr_finder = FindExprBySpan::new(span); - let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; }; - expr_finder.visit_expr(&body); + let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; + let body = self.tcx.hir().body(body_id); + expr_finder.visit_expr(body.value); let Some(expr) = expr_finder.result else { return; }; let Some(typeck) = &self.typeck_results else { return; }; let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; }; @@ -1060,8 +1060,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let ty = self.tcx.erase_late_bound_regions(self_ty); - let owner = self.tcx.hir().get_parent_item(obligation.cause.body_id); - let Some(generics) = self.tcx.hir().get_generics(owner.def_id) else { return false }; + let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { return false }; let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; let ty::Param(param) = inner_ty.kind() else { return false }; let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false }; @@ -1104,6 +1103,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Extracts information about a callable type for diagnostics. This is a /// heuristic -- it doesn't necessarily mean that a type is always callable, /// because the callable type must also be well-formed to be called. + // FIXME(vincenzopalazzo): move the HirId to a LocalDefId fn extract_callable_info( &self, hir_id: HirId, @@ -1429,10 +1429,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.remove_mark(); } let mut expr_finder = super::FindExprBySpan::new(span); - let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { + let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; - expr_finder.visit_expr(&body); + let body = self.tcx.hir().body(body_id); + expr_finder.visit_expr(body.value); let mut maybe_suggest = |suggested_ty, count, suggestions| { // Remapping bound vars here let trait_pred_and_suggested_ty = @@ -1670,8 +1671,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let hir = self.tcx.hir(); - let parent_node = hir.parent_id(obligation.cause.body_id); - let node = hir.find(parent_node); + let node = hir.find_by_def_id(obligation.cause.body_id); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind && sig.decl.output.span().overlaps(span) @@ -1707,8 +1707,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { let hir = self.tcx.hir(); - let parent_node = hir.parent_id(obligation.cause.body_id); - let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else { + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find_by_def_id(obligation.cause.body_id) else { return None; }; @@ -1732,8 +1731,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let hir = self.tcx.hir(); - let fn_hir_id = hir.parent_id(obligation.cause.body_id); - let node = hir.find(fn_hir_id); + let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id); + let node = hir.find_by_def_id(obligation.cause.body_id); let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. @@ -1749,7 +1748,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. predicates .principal_def_id() - .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) + .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id)) } // We only want to suggest `impl Trait` to `dyn Trait`s. // For example, `fn foo() -> str` needs to be filtered out. @@ -1806,7 +1805,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { match liberated_sig.output().kind() { ty::Dynamic(predicates, _, ty::Dyn) => { - let cause = ObligationCause::misc(ret_ty.span, fn_hir_id); + let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id); let param_env = ty::ParamEnv::empty(); if !only_never_return { @@ -1944,8 +1943,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let hir = self.tcx.hir(); - let parent_node = hir.parent_id(obligation.cause.body_id); - let node = hir.find(parent_node); + let node = hir.find_by_def_id(obligation.cause.body_id); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = node { @@ -2225,7 +2223,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); match *ty.kind() { - ty::Generator(did, ..) => { + ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => { generator = generator.or(Some(did)); outer_generator = Some(did); } @@ -2255,7 +2253,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); match *ty.kind() { - ty::Generator(did, ..) => { + ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => { generator = generator.or(Some(did)); outer_generator = Some(did); } @@ -2344,6 +2342,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => return false, }; + let generator_within_in_progress_typeck = match &self.typeck_results { + Some(t) => t.hir_owner.to_def_id() == generator_did_root, + _ => false, + }; + let mut interior_or_upvar_span = None; let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches); @@ -2363,6 +2366,35 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { *span, Some((*scope_span, *yield_span, *expr, from_awaited_ty)), )); + + if interior_or_upvar_span.is_none() && generator_data.is_foreign() { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None)); + } + } else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir + // Avoid disclosing internal information to downstream crates. + && generator_did.is_local() + // Try to avoid cycles. + && !generator_within_in_progress_typeck + { + let generator_info = &self.tcx.mir_generator_witnesses(generator_did); + debug!(?generator_info); + + 'find_source: for (variant, source_info) in + generator_info.variant_fields.iter().zip(&generator_info.variant_source_info) + { + debug!(?variant); + for &local in variant { + let decl = &generator_info.field_tys[local]; + debug!(?decl); + if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior( + decl.source_info.span, + Some((None, source_info.span, None, from_awaited_ty)), + )); + break 'find_source; + } + } + } } if interior_or_upvar_span.is_none() { @@ -3011,6 +3043,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } err.note(msg.trim_end_matches(", ")) } + ty::GeneratorWitnessMIR(def_id, substs) => { + use std::fmt::Write; + + // FIXME: this is kind of an unusual format for rustc, can we make it more clear? + // Maybe we should just remove this note altogether? + // FIXME: only print types which don't meet the trait requirement + let mut msg = + "required because it captures the following types: ".to_owned(); + for bty in tcx.generator_hidden_types(*def_id) { + let ty = bty.subst(tcx, substs); + write!(msg, "`{}`, ", ty).unwrap(); + } + err.note(msg.trim_end_matches(", ")) + } ty::Generator(def_id, _, _) => { let sp = self.tcx.def_span(def_id); @@ -3283,12 +3329,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - let body_hir_id = obligation.cause.body_id; - let item_id = self.tcx.hir().parent_id(body_hir_id); - - if let Some(body_id) = - self.tcx.hir().maybe_body_owned_by(self.tcx.hir().local_def_id(item_id)) - { + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { let body = self.tcx.hir().body(body_id); if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); @@ -3727,9 +3768,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { term: ty_var.into(), }, ))); + let body_def_id = self.tcx.hir().enclosing_body_owner(body_id); // Add `<ExprTy as Iterator>::Item = _` obligation. ocx.register_obligation(Obligation::misc( - self.tcx, span, body_id, param_env, projection, + self.tcx, + span, + body_def_id, + param_env, + projection, )); if ocx.select_where_possible().is_empty() { // `ty_var` now holds the type that `Item` is for `ExprTy`. @@ -3758,13 +3804,13 @@ fn hint_missing_borrow<'tcx>( err: &mut Diagnostic, ) { let found_args = match found.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), + ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) } }; let expected_args = match expected.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), + ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) } @@ -3775,12 +3821,12 @@ fn hint_missing_borrow<'tcx>( let args = fn_decl.inputs.iter().map(|ty| ty); - fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { - let mut refs = 0; + fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { + let mut refs = vec![]; - while let ty::Ref(_, new_ty, _) = ty.kind() { + while let ty::Ref(_, new_ty, mutbl) = ty.kind() { ty = *new_ty; - refs += 1; + refs.push(*mutbl); } (ty, refs) @@ -3794,11 +3840,21 @@ fn hint_missing_borrow<'tcx>( let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() { - if found_refs < expected_refs { - to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs))); - } else if found_refs > expected_refs { + // FIXME: This could handle more exotic cases like mutability mismatches too! + if found_refs.len() < expected_refs.len() + && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..] + { + to_borrow.push(( + arg.span.shrink_to_lo(), + expected_refs[..expected_refs.len() - found_refs.len()] + .iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::<Vec<_>>() + .join(""), + )); + } else if found_refs.len() > expected_refs.len() { let mut span = arg.span.shrink_to_lo(); - let mut left = found_refs - expected_refs; + let mut left = found_refs.len() - expected_refs.len(); let mut ty = arg; while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { span = span.with_hi(mut_ty.ty.span.lo()); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5a58d37e183..18d30771035 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -132,14 +132,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - { - let errors = self.select_where_possible(infcx); - if !errors.is_empty() { - return errors; - } - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } @@ -148,6 +141,55 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.select(selcx) } + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx }; + let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor); + assert!(outcome.errors.is_empty()); + return processor.removed_predicates; + + struct DrainProcessor<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + removed_predicates: Vec<PredicateObligation<'tcx>>, + } + + impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> { + type Obligation = PendingPredicateObligation<'tcx>; + type Error = !; + type OUT = Outcome<Self::Obligation, Self::Error>; + + fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { + pending_obligation + .stalled_on + .iter() + .any(|&var| self.infcx.ty_or_const_infer_var_changed(var)) + } + + fn process_obligation( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> { + assert!(self.needs_process_obligation(pending_obligation)); + self.removed_predicates.push(pending_obligation.obligation.clone()); + ProcessResult::Changed(vec![]) + } + + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) -> Result<(), !> + where + I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, + { + self.removed_predicates.extend(cycle.map(|c| c.obligation.clone())); + Ok(()) + } + } + } + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } @@ -327,7 +369,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if !self.selcx.tcx().is_object_safe(trait_def_id) { + if !self.selcx.tcx().check_is_object_safe(trait_def_id) { ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { ProcessResult::Changed(vec![]) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3c640cdc503..83458017e00 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -26,12 +26,11 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_span::def_id::{DefId, CRATE_DEF_ID}; use rustc_span::Span; use std::fmt::Debug; @@ -151,7 +150,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // We can use a dummy node-id here because we won't pay any mind // to region obligations that arise (there shouldn't really be any // anyhow). - cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), + cause: ObligationCause::misc(span, CRATE_DEF_ID), recursion_depth: 0, predicate: pred.to_predicate(infcx.tcx), }; @@ -166,14 +165,12 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // that guess. While imperfect, I believe this is sound. // FIXME(@lcnr): this function doesn't seem right. + // // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. let errors = fully_solve_obligation(infcx, obligation); - // Note: we only assume something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. match &errors[..] { [] => true, errors => { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c9121212cd8..565cfca9090 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -62,6 +62,37 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object ) } +fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + let violations = tcx.object_safety_violations(trait_def_id); + + if violations.is_empty() { + return true; + } + + // If the trait contains any other violations, then let the error reporting path + // report it instead of emitting a warning here. + if violations.iter().all(|violation| { + matches!( + violation, + ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _) + ) + }) { + for violation in violations { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation + { + lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); + } + } + return true; + } + + false +} + /// We say a method is *vtable safe* if it can be invoked on a trait /// object. Note that object-safe traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or @@ -93,19 +124,6 @@ fn object_safety_violations_for_trait( object_safety_violation_for_method(tcx, trait_def_id, &item) .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span)) }) - .filter(|violation| { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); - false - } else { - true - } - }) .collect(); // Check the trait itself. @@ -395,7 +413,7 @@ fn virtual_call_violation_for_method<'tcx>( trait_def_id: DefId, method: &ty::AssocItem, ) -> Option<MethodViolationCode> { - let sig = tcx.fn_sig(method.def_id); + let sig = tcx.fn_sig(method.def_id).subst_identity(); // The method's first parameter must be named `self` if !method.fn_has_self_parameter { @@ -866,5 +884,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { object_safety_violations, ..*providers }; + *providers = + ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index f2c5f730b31..6cb64ad574f 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -3,9 +3,8 @@ use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::query::NoSolution; use crate::traits::ObligationCause; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir as hir; -use rustc_hir::HirId; use rustc_middle::ty::{self, ParamEnv, Ty}; +use rustc_span::def_id::LocalDefId; pub use rustc_middle::traits::query::OutlivesBound; @@ -14,14 +13,14 @@ pub trait InferCtxtExt<'a, 'tcx> { fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>>; fn implied_bounds_tys( &'a self, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx>; } @@ -50,10 +49,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, ty: Ty<'tcx>, ) -> Vec<OutlivesBound<'tcx>> { - let span = self.tcx.hir().span(body_id); + let span = self.tcx.def_span(body_id); let result = param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) .fully_perform(self); @@ -102,7 +101,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { fn implied_bounds_tys( &'a self, param_env: ParamEnv<'tcx>, - body_id: HirId, + body_id: LocalDefId, tys: FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx> { tys.into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fbc7eccedc8..a11c5e81969 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1605,6 +1605,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(..) // Integers and floats always have `u8` as their discriminant. @@ -1654,6 +1655,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never // Extern types have unit metadata, according to RFC 2850 | ty::Foreign(_) diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 0f21813bc40..455b53bfb7d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -31,6 +31,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::Str diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 09b58894d30..f183248f2d0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,7 +1,9 @@ use rustc_middle::ty; +use rustc_session::config::TraitSolver; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; +use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause}; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; pub trait InferCtxtExt<'tcx> { @@ -77,12 +79,38 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { _ => obligation.param_env.without_const(), }; - let c_pred = self - .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values); - // Run canonical query. If overflow occurs, rerun from scratch but this time - // in standard trait query mode so that overflow is handled appropriately - // within `SelectionContext`. - self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + let c_pred = self.canonicalize_query_keep_static( + param_env.and(obligation.predicate), + &mut _orig_values, + ); + self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + } else { + self.probe(|snapshot| { + if let Ok((_, certainty)) = + self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate)) + { + match certainty { + Certainty::Yes => { + if self.opaque_types_added_in_snapshot(snapshot) { + Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) + } else if self.region_constraints_added_in_snapshot(snapshot).is_some() + { + Ok(EvaluationResult::EvaluatedToOkModuloRegions) + } else { + Ok(EvaluationResult::EvaluatedToOk) + } + } + Certainty::Maybe(MaybeCause::Ambiguity) => { + Ok(EvaluationResult::EvaluatedToAmbig) + } + Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical), + } + } else { + Ok(EvaluationResult::EvaluatedToErr) + } + }) + } } // Helper function that canonicalizes and runs the query. If an @@ -92,6 +120,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { + // Run canonical query. If overflow occurs, rerun from scratch but this time + // in standard trait query mode so that overflow is handled appropriately + // within `SelectionContext`. match self.evaluate_obligation(obligation) { Ok(result) => result, Err(OverflowError::Canonical) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 27247271d1f..1b2533a5cf6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -216,12 +216,16 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let substs = substs.try_fold_with(self)?; let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { - self.infcx.err_ctxt().report_overflow_error( - &ty, - self.cause.span, - true, - |_| {}, - ); + // A closure or generator may have itself as in its upvars. + // This should be checked handled by the recursion check for opaque + // types, but we may end up here before that check can happen. + // In that case, we delay a bug to mark the trip, and continue without + // revealing the opaque. + self.infcx + .err_ctxt() + .build_overflow_error(&ty, self.cause.span, true) + .delay_as_bug(); + return ty.try_super_fold_with(self); } let generic_ty = self.tcx().bound_type_of(def_id); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2733d9643fd..7b7abcf552a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -174,8 +174,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter_map(|p| p.to_opt_poly_trait_pred()) - .filter(|p| !p.references_error()); + .filter(|p| !p.references_error()) + .filter_map(|p| p.to_opt_poly_trait_pred()); // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = @@ -466,7 +466,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(principal) = data.principal() { if !self.infcx.tcx.features().object_safe_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { + } else if self.tcx().check_is_object_safe(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) } else { return; @@ -765,7 +765,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::Tuple(_) - | ty::GeneratorWitness(_) => { + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) => { // These are built-in, and cannot have a custom `impl const Destruct`. candidates.vec.push(ConstDestructCandidate(None)); } @@ -826,6 +827,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Alias(..) | ty::Param(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 82a59831be3..89a8fdbac1c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,12 +8,11 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::{ - self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, - ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, + self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, + TraitRef, Ty, TyCtxt, TypeVisitable, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -1009,7 +1008,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `T` -> `Trait` (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { + if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); } @@ -1064,51 +1063,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct<T>` -> `Struct<U>` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(p) => Some(p.index), - _ => None, - }, - - // Lifetimes aren't allowed to change during unsizing. - GenericArgKind::Lifetime(_) => None, - - GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Param(p) => Some(p.index), - _ => None, - }, - }; - - // FIXME(eddyb) cache this (including computing `unsizing_params`) - // by putting it in a query; it would only need the `DefId` as it - // looks at declared field types, not anything substituted. - - // The last field of the structure has to exist and contain type/const parameters. - let (tail_field, prefix_fields) = - def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; - let tail_field_ty = tcx.bound_type_of(tail_field.did); - - let mut unsizing_params = GrowableBitSet::new_empty(); - for arg in tail_field_ty.0.walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.insert(i); - } - } - - // Ensure none of the other fields mention the parameters used - // in unsizing. - for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.remove(i); - } - } - } - + let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { return Err(Unimplemented); } + let tail_field = def + .non_enum_variant() + .fields + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.bound_type_of(tail_field.did); + // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`, // normalizing in the process, since `type_of` returns something directly from // astconv (which means it's un-normalized). @@ -1285,6 +1251,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::GeneratorWitness(tys) => { stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); } + ty::GeneratorWitnessMIR(def_id, substs) => { + let tcx = self.tcx(); + stack.extend(tcx.generator_hidden_types(def_id).map(|bty| { + let ty = bty.subst(tcx, substs); + debug_assert!(!ty.has_late_bound_regions()); + ty + })) + } // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f90da95d516..b8f5aeee2d5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -38,6 +38,8 @@ use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::TraitEngineExt; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -47,6 +49,7 @@ use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_session::config::TraitSolver; use rustc_span::symbol::sym; use std::cell::{Cell, RefCell}; @@ -544,10 +547,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { self.evaluation_probe(|this| { - this.evaluate_predicate_recursively( - TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), - obligation.clone(), - ) + if this.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + this.evaluate_predicate_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + obligation.clone(), + ) + } else { + this.evaluate_predicates_recursively_in_new_solver([obligation.clone()]) + } }) } @@ -586,18 +593,40 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug, { - let mut result = EvaluatedToOk; - for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - if let EvaluatedToErr = eval { - // fast-path - EvaluatedToErr is the top of the lattice, - // so we don't need to look on the other predicates. - return Ok(EvaluatedToErr); - } else { - result = cmp::max(result, eval); + if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + let mut result = EvaluatedToOk; + for obligation in predicates { + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + if let EvaluatedToErr = eval { + // fast-path - EvaluatedToErr is the top of the lattice, + // so we don't need to look on the other predicates. + return Ok(EvaluatedToErr); + } else { + result = cmp::max(result, eval); + } } + Ok(result) + } else { + self.evaluate_predicates_recursively_in_new_solver(predicates) } - Ok(result) + } + + /// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled + fn evaluate_predicates_recursively_in_new_solver( + &mut self, + predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>, + ) -> Result<EvaluationResult, OverflowError> { + let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); + fulfill_cx.register_predicate_obligations(self.infcx, predicates); + // True errors + if !fulfill_cx.select_where_possible(self.infcx).is_empty() { + return Ok(EvaluatedToErr); + } + if !fulfill_cx.select_all_or_error(self.infcx).is_empty() { + return Ok(EvaluatedToAmbig); + } + // Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot + Ok(EvaluatedToOk) } #[instrument( @@ -768,7 +797,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { + if self.tcx().check_is_object_safe(trait_def_id) { Ok(EvaluatedToOk) } else { Ok(EvaluatedToErr) @@ -2037,6 +2066,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2153,6 +2183,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) } + ty::GeneratorWitnessMIR(def_id, ref substs) => { + let hidden_types = bind_generator_hidden_types_above( + self.infcx, + def_id, + substs, + obligation.predicate.bound_vars(), + ); + Where(hidden_types) + } + ty::Closure(_, substs) => { // (*) binder moved here let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); @@ -2250,6 +2290,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { types.map_bound(|types| types.to_vec()) } + ty::GeneratorWitnessMIR(def_id, ref substs) => { + bind_generator_hidden_types_above(self.infcx, def_id, substs, t.bound_vars()) + } + // For `PhantomData<T>`, we pass `T`. ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), @@ -2892,3 +2936,56 @@ pub enum ProjectionMatchesProjection { Ambiguous, No, } + +/// Replace all regions inside the generator interior with late bound regions. +/// Note that each region slot in the types gets a new fresh late bound region, which means that +/// none of the regions inside relate to any other, even if typeck had previously found constraints +/// that would cause them to be related. +#[instrument(level = "trace", skip(infcx), ret)] +fn bind_generator_hidden_types_above<'tcx>( + infcx: &InferCtxt<'tcx>, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, + bound_vars: &ty::List<ty::BoundVariableKind>, +) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { + let tcx = infcx.tcx; + let mut seen_tys = FxHashSet::default(); + + let considering_regions = infcx.considering_regions; + + let num_bound_variables = bound_vars.len() as u32; + let mut counter = num_bound_variables; + + let hidden_types: Vec<_> = tcx + .generator_hidden_types(def_id) + // Deduplicate tys to avoid repeated work. + .filter(|bty| seen_tys.insert(*bty)) + .map(|bty| { + let mut ty = bty.subst(tcx, substs); + + // Only remap erased regions if we use them. + if considering_regions { + ty = tcx.fold_regions(ty, |mut r, current_depth| { + if let ty::ReErased = r.kind() { + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(counter), + kind: ty::BrAnon(counter, None), + }; + counter += 1; + r = tcx.mk_region(ty::ReLateBound(current_depth, br)); + } + r + }) + } + + ty + }) + .collect(); + if considering_regions { + debug_assert!(!hidden_types.has_erased_regions()); + } + let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.iter().chain( + (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))), + )); + ty::Binder::bind_with_vars(hidden_types, bound_vars) +} diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index f398fb06c18..69b965f3a38 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -101,7 +101,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Closure(..) => { return ControlFlow::Break(ty); } - ty::Generator(..) | ty::GeneratorWitness(..) => { + ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => { return ControlFlow::Break(ty); } ty::FnDef(..) => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 12d4cb4fc69..7c5e147a950 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1,11 +1,11 @@ use crate::infer::InferCtxt; use crate::traits; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; -use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_span::{Span, DUMMY_SP}; use std::iter; /// Returns the set of obligations needed to make `arg` well-formed. @@ -17,7 +17,7 @@ use std::iter; pub fn obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, recursion_depth: usize, arg: GenericArg<'tcx>, span: Span, @@ -75,6 +75,34 @@ pub fn obligations<'tcx>( Some(result) } +/// Compute the predicates that are required for a type to be well-formed. +/// +/// This is only intended to be used in the new solver, since it does not +/// take into account recursion depth or proper error-reporting spans. +pub fn unnormalized_obligations<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + arg: GenericArg<'tcx>, +) -> Option<Vec<traits::PredicateObligation<'tcx>>> { + if let ty::GenericArgKind::Lifetime(..) = arg.unpack() { + return Some(vec![]); + } + + debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); + + let mut wf = WfPredicates { + tcx: infcx.tcx, + param_env, + body_id: CRATE_DEF_ID, + span: DUMMY_SP, + out: vec![], + recursion_depth: 0, + item: None, + }; + wf.compute(arg); + Some(wf.out) +} + /// Returns the obligations that make this trait reference /// well-formed. For example, if there is a trait `Set` defined like /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF @@ -82,7 +110,7 @@ pub fn obligations<'tcx>( pub fn trait_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, trait_pred: &ty::TraitPredicate<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, @@ -105,7 +133,7 @@ pub fn trait_obligations<'tcx>( pub fn predicate_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, predicate: ty::Predicate<'tcx>, span: Span, ) -> Vec<traits::PredicateObligation<'tcx>> { @@ -167,7 +195,7 @@ pub fn predicate_obligations<'tcx>( struct WfPredicates<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + body_id: LocalDefId, span: Span, out: Vec<traits::PredicateObligation<'tcx>>, recursion_depth: usize, @@ -523,6 +551,7 @@ impl<'tcx> WfPredicates<'tcx> { | ty::Error(_) | ty::Str | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Param(_) | ty::Bound(..) diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index f146de3966b..84f7e836208 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -269,7 +269,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let where_clauses = self.where_clauses_for(def_id, bound_vars); - let sig = self.interner.tcx.bound_fn_sig(def_id); + let sig = self.interner.tcx.fn_sig(def_id); let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( self.interner, self.interner.tcx, @@ -580,7 +580,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t } fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool { - self.interner.tcx.is_object_safe(trait_id.0) + self.interner.tcx.check_is_object_safe(trait_id.0) } fn hidden_opaque_type( diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9712abb708f..3a254105162 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -343,6 +343,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { substs.lower_into(interner), ), ty::GeneratorWitness(_) => unimplemented!(), + ty::GeneratorWitnessMIR(..) => unimplemented!(), ty::Never => chalk_ir::TyKind::Never, ty::Tuple(types) => { chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner)) diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index f76386fa720..13d83b92689 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -8,13 +8,10 @@ pub(crate) mod lowering; use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::IndexVec; - use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; use rustc_middle::traits::ChalkRustInterner; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{self, ParamTy, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_infer::infer::canonical::{ Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, @@ -100,11 +97,13 @@ pub(crate) fn evaluate_goal<'tcx>( binders: chalk_ir::CanonicalVarKinds<_>| { use rustc_middle::infer::canonical::CanonicalVarInfo; - let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new(); let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params); - subst.as_slice(interner).iter().for_each(|p| { - var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor)); - }); + let var_values = tcx.mk_substs( + subst + .as_slice(interner) + .iter() + .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)), + ); let variables: Vec<_> = binders .iter(interner) .map(|var| { @@ -159,8 +158,7 @@ pub(crate) fn evaluate_goal<'tcx>( max_universe: ty::UniverseIndex::from_usize(0), variables: obligation.variables, value: QueryResponse { - var_values: CanonicalVarValues { var_values: IndexVec::new() } - .make_identity(tcx), + var_values: CanonicalVarValues::dummy(), region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Ambiguous, opaque_types: vec![], diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index c0da8a8169e..6f81d343e0f 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -4,7 +4,7 @@ // general routines. use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_infer::traits::FulfillmentErrorCode; +use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 481b56e111e..8b7f8033bfa 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -164,7 +164,8 @@ fn dtorck_constraint_for_ty<'tcx>( | ty::Ref(..) | ty::FnDef(..) | ty::FnPtr(_) - | ty::GeneratorWitness(..) => { + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) => { // these types never have a destructor } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 7d2d8433c93..fe633d687d9 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -2,13 +2,13 @@ //! Do not call this query directory. See //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`]. -use rustc_hir as hir; use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; @@ -67,9 +67,8 @@ fn compute_implied_outlives_bounds<'tcx>( // FIXME(@lcnr): It's not really "always fine", having fewer implied // bounds can be backward incompatible, e.g. #101951 was caused by // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = - wf::obligations(ocx.infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); + let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) + .unwrap_or_default(); // While these predicates should all be implied by other parts of // the program, they are still relevant as they may constrain diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index f35c5e44882..27dc1625992 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; @@ -76,7 +77,6 @@ fn relate_mir_and_user_ty<'tcx>( // FIXME(#104764): We should check well-formedness before normalization. let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); - Ok(()) } @@ -111,7 +111,7 @@ fn relate_mir_and_user_substs<'tcx>( let span = if span == DUMMY_SP { predicate_span } else { span }; let cause = ObligationCause::new( span, - hir::CRATE_HIR_ID, + CRATE_DEF_ID, ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), ); let instantiated_predicate = @@ -126,7 +126,6 @@ fn relate_mir_and_user_substs<'tcx>( let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 91a505a72fa..1c74aeca5ab 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -41,7 +41,7 @@ fn fn_sig_for_fn_abi<'tcx>( // We normalize the `fn_sig` again after substituting at a later point. let mut sig = match *ty.kind() { ty::FnDef(def_id, substs) => tcx - .bound_fn_sig(def_id) + .fn_sig(def_id) .map_bound(|fn_sig| { tcx.normalize_erasing_regions(tcx.param_env(def_id), fn_sig) }) @@ -244,7 +244,7 @@ fn adjust_for_rust_scalar<'tcx>( } // Only pointer types handled below. - let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; + let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return }; if !valid_range.contains(0) { attrs.set(ArgAttribute::NonNull); @@ -479,7 +479,7 @@ fn fn_abi_adjust_for_abi<'tcx>( } let size = arg.layout.size; - if arg.layout.is_unsized() || size > Pointer.size(cx) { + if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) { arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 7a24645803c..961c04974e5 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -9,12 +9,12 @@ pub fn provide(providers: &mut ty::query::Providers) { fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { match tcx.def_kind(def_id) { DefKind::Fn => { - let sig = tcx.fn_sig(def_id); + let sig = tcx.fn_sig(def_id).subst_identity(); let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); liberated_sig.inputs_and_output } DefKind::AssocFn => { - let sig = tcx.fn_sig(def_id); + let sig = tcx.fn_sig(def_id).subst_identity(); let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig); let mut assumed_wf_types: Vec<_> = tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into(); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 6aa016133ca..378cd5a99ed 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -134,7 +134,7 @@ fn layout_of_uncached<'tcx>( ty::FloatTy::F64 => F64, }), ty::FnPtr(_) => { - let mut ptr = scalar_unit(Pointer); + let mut ptr = scalar_unit(Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; tcx.intern_layout(LayoutS::scalar(cx, ptr)) } @@ -144,7 +144,7 @@ fn layout_of_uncached<'tcx>( // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let mut data_ptr = scalar_unit(Pointer); + let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA)); if !ty.is_unsafe_ptr() { data_ptr.valid_range_mut().start = 1; } @@ -178,7 +178,7 @@ fn layout_of_uncached<'tcx>( } ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), ty::Dynamic(..) => { - let mut vtable = scalar_unit(Pointer); + let mut vtable = scalar_unit(Pointer(AddressSpace::DATA)); vtable.valid_range_mut().start = 1; vtable } @@ -195,7 +195,7 @@ fn layout_of_uncached<'tcx>( ty::Dynamic(_, _, ty::DynStar) => { let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false)); data.valid_range_mut().start = 0; - let mut vtable = scalar_unit(Pointer); + let mut vtable = scalar_unit(Pointer(AddressSpace::DATA)); vtable.valid_range_mut().start = 1; tcx.intern_layout(cx.scalar_pair(data, vtable)) } @@ -470,7 +470,10 @@ fn layout_of_uncached<'tcx>( return Err(LayoutError::Unknown(ty)); } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } @@ -640,7 +643,7 @@ fn generator_layout<'tcx>( let promoted_layouts = ineligible_locals .iter() - .map(|local| subst_field(info.field_tys[local])) + .map(|local| subst_field(info.field_tys[local].ty)) .map(|ty| tcx.mk_maybe_uninit(ty)) .map(|ty| cx.layout_of(ty)); let prefix_layouts = substs @@ -710,7 +713,7 @@ fn generator_layout<'tcx>( Assigned(_) => bug!("assignment does not match variant"), Ineligible(_) => false, }) - .map(|local| subst_field(info.field_tys[*local])); + .map(|local| subst_field(info.field_tys[*local].ty)); let mut variant = univariant_uninterned( cx, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 0df060fc5fb..cd1475391a4 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -109,6 +109,13 @@ where for component in components { match *component.kind() { + // The information required to determine whether a generator has drop is + // computed on MIR, while this very method is used to build MIR. + // To avoid cycles, we consider that generators always require drop. + ty::Generator(..) if tcx.sess.opts.unstable_opts.drop_tracking_mir => { + return Some(Err(AlwaysRequiresDrop)); + } + _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), ty::Closure(_, substs) => { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index eb5454bf263..b5005c1d8d8 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,8 +1,9 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_index::bit_set::BitSet; use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; use rustc_session::config::TraitSolver; +use rustc_span::def_id::{DefId, CRATE_DEF_ID}; use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( @@ -16,7 +17,13 @@ fn sized_constraint_for_ty<'tcx>( Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], - Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => { + Str + | Dynamic(..) + | Slice(_) + | Foreign(..) + | Error(_) + | GeneratorWitness(..) + | GeneratorWitnessMIR(..) => { // these are never sized - return the target type vec![ty] } @@ -208,14 +215,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { constness, ); - let body_id = - local_did.and_then(|id| tcx.hir().maybe_body_owned_by(id).map(|body| body.hir_id)); - let body_id = match body_id { - Some(id) => id, - None if hir_id.is_some() => hir_id.unwrap(), - _ => hir::CRATE_HIR_ID, - }; - + let body_id = local_did.unwrap_or(CRATE_DEF_ID); let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) } @@ -306,7 +306,7 @@ fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Predica // In an fn, we assume that the arguments and all their constituents are // well-formed. NodeKind::Fn => { - let fn_sig = tcx.fn_sig(def_id); + let fn_sig = tcx.fn_sig(def_id).subst_identity(); let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); @@ -407,6 +407,56 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) } +fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32> { + let def = tcx.adt_def(def_id); + let num_params = tcx.generics_of(def_id).count(); + + let maybe_unsizing_param_idx = |arg: ty::GenericArg<'tcx>| match arg.unpack() { + ty::GenericArgKind::Type(ty) => match ty.kind() { + ty::Param(p) => Some(p.index), + _ => None, + }, + + // We can't unsize a lifetime + ty::GenericArgKind::Lifetime(_) => None, + + ty::GenericArgKind::Const(ct) => match ct.kind() { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, + }; + + // FIXME(eddyb) cache this (including computing `unsizing_params`) + // by putting it in a query; it would only need the `DefId` as it + // looks at declared field types, not anything substituted. + + // The last field of the structure has to exist and contain type/const parameters. + let Some((tail_field, prefix_fields)) = + def.non_enum_variant().fields.split_last() else + { + return BitSet::new_empty(num_params); + }; + + let mut unsizing_params = BitSet::new_empty(num_params); + for arg in tcx.bound_type_of(tail_field.did).subst_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); + } + } + + // Ensure none of the other fields mention the parameters used + // in unsizing. + for field in prefix_fields { + for arg in tcx.bound_type_of(field.did).subst_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.remove(i); + } + } + } + + unsizing_params +} + pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, @@ -416,6 +466,7 @@ pub fn provide(providers: &mut ty::query::Providers) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, + unsizing_params_for_adt, ..*providers }; } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 44004cb0be1..d5de457a82c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -265,6 +265,9 @@ bitflags! { /// Does this value have `InferConst::Fresh`? const HAS_CT_FRESH = 1 << 21; + + /// Does this have `Generator` or `GeneratorWitness`? + const HAS_TY_GENERATOR = 1 << 22; } } diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 5f29588ae4d..e7bb3055373 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -160,6 +160,32 @@ pub enum TyKind<I: Interner> { /// ``` GeneratorWitness(I::BinderListTy), + /// A type representing the types stored inside a generator. + /// This should only appear as part of the `GeneratorSubsts`. + /// + /// Unlike upvars, the witness can reference lifetimes from + /// inside of the generator itself. To deal with them in + /// the type of the generator, we convert them to higher ranked + /// lifetimes bound by the witness itself. + /// + /// This variant is only using when `drop_tracking_mir` is set. + /// This contains the `DefId` and the `SubstRef` of the generator. + /// The actual witness types are computed on MIR by the `mir_generator_witnesses` query. + /// + /// Looking at the following example, the witness for this generator + /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`: + /// + /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?) + /// #![feature(generators)] + /// |a| { + /// let x = &vec![3]; + /// yield a; + /// yield x[0]; + /// } + /// # ; + /// ``` + GeneratorWitnessMIR(I::DefId, I::SubstsRef), + /// The never type `!`. Never, @@ -241,6 +267,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize { Placeholder(_) => 23, Infer(_) => 24, Error(_) => 25, + GeneratorWitnessMIR(_, _) => 26, } } @@ -266,6 +293,7 @@ impl<I: Interner> Clone for TyKind<I> { Closure(d, s) => Closure(d.clone(), s.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), GeneratorWitness(g) => GeneratorWitness(g.clone()), + GeneratorWitnessMIR(d, s) => GeneratorWitnessMIR(d.clone(), s.clone()), Never => Never, Tuple(t) => Tuple(t.clone()), Alias(k, p) => Alias(*k, p.clone()), @@ -303,6 +331,10 @@ impl<I: Interner> PartialEq for TyKind<I> { a_d == b_d && a_s == b_s && a_m == b_m } (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, + ( + &GeneratorWitnessMIR(ref a_d, ref a_s), + &GeneratorWitnessMIR(ref b_d, ref b_s), + ) => a_d == b_d && a_s == b_s, (Tuple(a_t), Tuple(b_t)) => a_t == b_t, (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p, (Param(a_p), Param(b_p)) => a_p == b_p, @@ -360,6 +392,13 @@ impl<I: Interner> Ord for TyKind<I> { a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m))) } (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g), + ( + &GeneratorWitnessMIR(ref a_d, ref a_s), + &GeneratorWitnessMIR(ref b_d, ref b_s), + ) => match Ord::cmp(a_d, b_d) { + Ordering::Equal => Ord::cmp(a_s, b_s), + cmp => cmp, + }, (Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t), (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i.cmp(b_i).then_with(|| a_p.cmp(b_p)), (Param(a_p), Param(b_p)) => a_p.cmp(b_p), @@ -421,6 +460,10 @@ impl<I: Interner> hash::Hash for TyKind<I> { m.hash(state) } GeneratorWitness(g) => g.hash(state), + GeneratorWitnessMIR(d, s) => { + d.hash(state); + s.hash(state); + } Tuple(t) => t.hash(state), Alias(i, p) => { i.hash(state); @@ -461,6 +504,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> { Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), + GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s), Never => f.write_str("Never"), Tuple(t) => f.debug_tuple_field1_finish("Tuple", t), Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a), @@ -559,6 +603,10 @@ where GeneratorWitness(b) => e.emit_enum_variant(disc, |e| { b.encode(e); }), + GeneratorWitnessMIR(def_id, substs) => e.emit_enum_variant(disc, |e| { + def_id.encode(e); + substs.encode(e); + }), Never => e.emit_enum_variant(disc, |_| {}), Tuple(substs) => e.emit_enum_variant(disc, |e| { substs.encode(e); @@ -641,6 +689,7 @@ where 23 => Placeholder(Decodable::decode(d)), 24 => Infer(Decodable::decode(d)), 25 => Error(Decodable::decode(d)), + 26 => GeneratorWitnessMIR(Decodable::decode(d), Decodable::decode(d)), _ => panic!( "{}", format!( @@ -742,6 +791,10 @@ where GeneratorWitness(b) => { b.hash_stable(__hcx, __hasher); } + GeneratorWitnessMIR(def_id, substs) => { + def_id.hash_stable(__hcx, __hasher); + substs.hash_stable(__hcx, __hasher); + } Never => {} Tuple(substs) => { substs.hash_stable(__hcx, __hasher); diff --git a/config.toml.example b/config.toml.example index 5e1d2f2e314..85f058f3664 100644 --- a/config.toml.example +++ b/config.toml.example @@ -233,6 +233,9 @@ changelog-seen = 2 # and generated in already-minified form from the beginning. #docs-minification = true +# Flag to specify whether private items should be included in the library docs. +#library-docs-private-items = false + # Indicate whether the compiler should be documented in addition to the standard # library and facade crates. #compiler-docs = false @@ -285,11 +288,24 @@ changelog-seen = 2 # be built if `extended = true`. #extended = false -# Installs chosen set of extended tools if `extended = true`. By default builds -# all extended tools except `rust-demangler`, unless the target is also being -# built with `profiler = true`. If chosen tool failed to build the installation -# fails. If `extended = false`, this option is ignored. -#tools = ["cargo", "rls", "clippy", "rustfmt", "analysis", "src"] # + "rust-demangler" if `profiler` +# Set of tools to be included in the installation. +# +# If `extended = false`, the only one of these built by default is rustdoc. +# +# If `extended = true`, they're all included, with the exception of +# rust-demangler which additionally requires `profiler = true` to be set. +# +# If any enabled tool fails to build, the installation fails. +#tools = [ +# "cargo", +# "clippy", +# "rustdoc", +# "rustfmt", +# "rust-analyzer", +# "analysis", +# "src", +# "rust-demangler", # if profiler = true +#] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose #verbose = 0 diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index c1a82e452f6..ad48315fd70 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -48,7 +48,7 @@ unsafe impl<T: ?Sized + Sync> Sync for ThinBox<T> {} #[unstable(feature = "thin_box", issue = "92791")] impl<T> ThinBox<T> { - /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on + /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on /// the stack. /// /// # Examples @@ -59,6 +59,8 @@ impl<T> ThinBox<T> { /// /// let five = ThinBox::new(5); /// ``` + /// + /// [`Metadata`]: core::ptr::Pointee::Metadata #[cfg(not(no_global_oom_handling))] pub fn new(value: T) -> Self { let meta = ptr::metadata(&value); @@ -69,7 +71,7 @@ impl<T> ThinBox<T> { #[unstable(feature = "thin_box", issue = "92791")] impl<Dyn: ?Sized> ThinBox<Dyn> { - /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on + /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on /// the stack. /// /// # Examples @@ -80,6 +82,8 @@ impl<Dyn: ?Sized> ThinBox<Dyn> { /// /// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]); /// ``` + /// + /// [`Metadata`]: core::ptr::Pointee::Metadata #[cfg(not(no_global_oom_handling))] pub fn new_unsize<T>(value: T) -> Self where diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs index 016f139a501..000b9bd0fab 100644 --- a/library/alloc/src/collections/btree/borrow.rs +++ b/library/alloc/src/collections/btree/borrow.rs @@ -41,6 +41,28 @@ impl<'a, T> DormantMutRef<'a, T> { // SAFETY: our own safety conditions imply this reference is again unique. unsafe { &mut *self.ptr.as_ptr() } } + + /// Borrows a new mutable reference from the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn reborrow(&mut self) -> &'a mut T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &mut *self.ptr.as_ptr() } + } + + /// Borrows a new shared reference from the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn reborrow_shared(&self) -> &'a T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &*self.ptr.as_ptr() } + } } #[cfg(test)] diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 1d9c4460ec9..386cd1a1657 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -6,7 +6,7 @@ use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; -use core::ops::{Index, RangeBounds}; +use core::ops::{Bound, Index, RangeBounds}; use core::ptr; use crate::alloc::{Allocator, Global}; @@ -15,7 +15,7 @@ use super::borrow::DormantMutRef; use super::dedup_sorted_iter::DedupSortedIter; use super::navigate::{LazyLeafRange, LeafRange}; use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root}; -use super::search::SearchResult::*; +use super::search::{SearchBound, SearchResult::*}; use super::set_val::SetValZST; mod entry; @@ -2422,6 +2422,732 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { pub const fn is_empty(&self) -> bool { self.len() == 0 } + + /// Returns a [`Cursor`] pointing at the first element that is above the + /// given bound. + /// + /// If no such element exists then a cursor pointing at the "ghost" + /// non-element is returned. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first + /// element of the map. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeMap; + /// use std::ops::Bound; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(4, "c"); + /// let cursor = a.lower_bound(Bound::Excluded(&2)); + /// assert_eq!(cursor.key(), Some(&3)); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn lower_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + where + K: Borrow<Q> + Ord, + Q: Ord, + { + let root_node = match self.root.as_ref() { + None => return Cursor { current: None, root: None }, + Some(root) => root.reborrow(), + }; + let edge = root_node.lower_bound(SearchBound::from_range(bound)); + Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() } + } + + /// Returns a [`CursorMut`] pointing at the first element that is above the + /// given bound. + /// + /// If no such element exists then a cursor pointing at the "ghost" + /// non-element is returned. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first + /// element of the map. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeMap; + /// use std::ops::Bound; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(4, "c"); + /// let cursor = a.lower_bound_mut(Bound::Excluded(&2)); + /// assert_eq!(cursor.key(), Some(&3)); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn lower_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + where + K: Borrow<Q> + Ord, + Q: Ord, + { + let (root, dormant_root) = DormantMutRef::new(&mut self.root); + let root_node = match root.as_mut() { + None => { + return CursorMut { + current: None, + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }; + } + Some(root) => root.borrow_mut(), + }; + let edge = root_node.lower_bound(SearchBound::from_range(bound)); + CursorMut { + current: edge.next_kv().ok(), + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + } + } + + /// Returns a [`Cursor`] pointing at the last element that is below the + /// given bound. + /// + /// If no such element exists then a cursor pointing at the "ghost" + /// non-element is returned. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last + /// element of the map. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeMap; + /// use std::ops::Bound; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(4, "c"); + /// let cursor = a.upper_bound(Bound::Excluded(&3)); + /// assert_eq!(cursor.key(), Some(&2)); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn upper_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + where + K: Borrow<Q> + Ord, + Q: Ord, + { + let root_node = match self.root.as_ref() { + None => return Cursor { current: None, root: None }, + Some(root) => root.reborrow(), + }; + let edge = root_node.upper_bound(SearchBound::from_range(bound)); + Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() } + } + + /// Returns a [`CursorMut`] pointing at the last element that is below the + /// given bound. + /// + /// If no such element exists then a cursor pointing at the "ghost" + /// non-element is returned. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last + /// element of the map. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeMap; + /// use std::ops::Bound; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(4, "c"); + /// let cursor = a.upper_bound_mut(Bound::Excluded(&3)); + /// assert_eq!(cursor.key(), Some(&2)); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn upper_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + where + K: Borrow<Q> + Ord, + Q: Ord, + { + let (root, dormant_root) = DormantMutRef::new(&mut self.root); + let root_node = match root.as_mut() { + None => { + return CursorMut { + current: None, + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + }; + } + Some(root) => root.borrow_mut(), + }; + let edge = root_node.upper_bound(SearchBound::from_range(bound)); + CursorMut { + current: edge.next_back_kv().ok(), + root: dormant_root, + length: &mut self.length, + alloc: &mut *self.alloc, + } + } +} + +/// A cursor over a `BTreeMap`. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. +/// +/// Cursors always point to an element in the tree, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and +/// first elements of the tree. +/// +/// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct Cursor<'a, K: 'a, V: 'a> { + current: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>, + root: Option<&'a node::Root<K, V>>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl<K, V> Clone for Cursor<'_, K, V> { + fn clone(&self) -> Self { + let Cursor { current, root } = *self; + Cursor { current, root } + } +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl<K: Debug, V: Debug> Debug for Cursor<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Cursor").field(&self.key_value()).finish() + } +} + +/// A cursor over a `BTreeMap` with editing operations. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the tree during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying tree. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always point to an element in the tree, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and +/// first elements of the tree. +/// +/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`] +/// methods. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct CursorMut< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A = Global, +> { + current: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>, + root: DormantMutRef<'a, Option<node::Root<K, V>>>, + length: &'a mut usize, + alloc: &'a mut A, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl<K: Debug, V: Debug, A> Debug for CursorMut<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CursorMut").field(&self.key_value()).finish() + } +} + +impl<'a, K, V> Cursor<'a, K, V> { + /// Moves the cursor to the next element of the `BTreeMap`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `BTreeMap`. If it is pointing to the last + /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn move_next(&mut self) { + match self.current.take() { + None => { + self.current = self.root.and_then(|root| { + root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok() + }); + } + Some(current) => { + self.current = current.next_leaf_edge().next_kv().ok(); + } + } + } + + /// Moves the cursor to the previous element of the `BTreeMap`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `BTreeMap`. If it is pointing to the first + /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn move_prev(&mut self) { + match self.current.take() { + None => { + self.current = self.root.and_then(|root| { + root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok() + }); + } + Some(current) => { + self.current = current.next_back_leaf_edge().next_back_kv().ok(); + } + } + } + + /// Returns a reference to the key of the element that the cursor is + /// currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn key(&self) -> Option<&'a K> { + self.current.as_ref().map(|current| current.into_kv().0) + } + + /// Returns a reference to the value of the element that the cursor is + /// currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn value(&self) -> Option<&'a V> { + self.current.as_ref().map(|current| current.into_kv().1) + } + + /// Returns a reference to the key and value of the element that the cursor + /// is currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn key_value(&self) -> Option<(&'a K, &'a V)> { + self.current.as_ref().map(|current| current.into_kv()) + } + + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `BTreeMap`. If it is pointing to the last + /// element of the `BTreeMap` then this returns `None`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_next(&self) -> Option<(&'a K, &'a V)> { + let mut next = self.clone(); + next.move_next(); + next.current.as_ref().map(|current| current.into_kv()) + } + + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `BTreeMap`. If it is pointing to the first + /// element of the `BTreeMap` then this returns `None`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> { + let mut prev = self.clone(); + prev.move_prev(); + prev.current.as_ref().map(|current| current.into_kv()) + } +} + +impl<'a, K, V, A> CursorMut<'a, K, V, A> { + /// Moves the cursor to the next element of the `BTreeMap`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `BTreeMap`. If it is pointing to the last + /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn move_next(&mut self) { + match self.current.take() { + None => { + // SAFETY: The previous borrow of root has ended. + self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| { + root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok() + }); + } + Some(current) => { + self.current = current.next_leaf_edge().next_kv().ok(); + } + } + } + + /// Moves the cursor to the previous element of the `BTreeMap`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `BTreeMap`. If it is pointing to the first + /// element of the `BTreeMap` then this will move it to the "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn move_prev(&mut self) { + match self.current.take() { + None => { + // SAFETY: The previous borrow of root has ended. + self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| { + root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok() + }); + } + Some(current) => { + self.current = current.next_back_leaf_edge().next_back_kv().ok(); + } + } + } + + /// Returns a reference to the key of the element that the cursor is + /// currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn key(&self) -> Option<&K> { + self.current.as_ref().map(|current| current.reborrow().into_kv().0) + } + + /// Returns a reference to the value of the element that the cursor is + /// currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn value(&self) -> Option<&V> { + self.current.as_ref().map(|current| current.reborrow().into_kv().1) + } + + /// Returns a reference to the key and value of the element that the cursor + /// is currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn key_value(&self) -> Option<(&K, &V)> { + self.current.as_ref().map(|current| current.reborrow().into_kv()) + } + + /// Returns a mutable reference to the value of the element that the cursor + /// is currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn value_mut(&mut self) -> Option<&mut V> { + self.current.as_mut().map(|current| current.kv_mut().1) + } + + /// Returns a reference to the key and mutable reference to the value of the + /// element that the cursor is currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> { + self.current.as_mut().map(|current| { + let (k, v) = current.kv_mut(); + (&*k, v) + }) + } + + /// Returns a mutable reference to the of the element that the cursor is + /// currently pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + /// + /// # Safety + /// + /// This can be used to modify the key, but you must ensure that the + /// `BTreeMap` invariants are maintained. Specifically: + /// + /// * The key must remain unique within the tree. + /// * The key must remain in sorted order with regards to other elements in + /// the tree. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> { + self.current.as_mut().map(|current| current.kv_mut().0) + } + + /// Returns a reference to the key and value of the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `BTreeMap`. If it is pointing to the last + /// element of the `BTreeMap` then this returns `None`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_next(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = match self.current { + None => { + // SAFETY: The previous borrow of root has ended. + unsafe { self.root.reborrow() } + .as_mut()? + .borrow_mut() + .first_leaf_edge() + .next_kv() + .ok()? + .into_kv_valmut() + } + // SAFETY: We're not using this to mutate the tree. + Some(ref mut current) => { + unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut() + } + }; + Some((k, v)) + } + + /// Returns a reference to the key and value of the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `BTreeMap`. If it is pointing to the first + /// element of the `BTreeMap` then this returns `None`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> { + let (k, v) = match self.current.as_mut() { + None => { + // SAFETY: The previous borrow of root has ended. + unsafe { self.root.reborrow() } + .as_mut()? + .borrow_mut() + .first_leaf_edge() + .next_kv() + .ok()? + .into_kv_valmut() + } + Some(current) => { + // SAFETY: We're not using this to mutate the tree. + unsafe { current.reborrow_mut() } + .next_back_leaf_edge() + .next_back_kv() + .ok()? + .into_kv_valmut() + } + }; + Some((k, v)) + } + + /// Returns a read-only cursor pointing to the current element. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn as_cursor(&self) -> Cursor<'_, K, V> { + Cursor { + // SAFETY: The tree is immutable while the cursor exists. + root: unsafe { self.root.reborrow_shared().as_ref() }, + current: self.current.as_ref().map(|current| current.reborrow()), + } + } +} + +// Now the tree editing operations +impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { + /// Inserts a new element into the `BTreeMap` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the front of the `BTreeMap`. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) { + let edge = match self.current.take() { + None => { + // SAFETY: We have no other reference to the tree. + match unsafe { self.root.reborrow() } { + root @ None => { + // Tree is empty, allocate a new root. + let mut node = NodeRef::new_leaf(self.alloc.clone()); + node.borrow_mut().push(key, value); + *root = Some(node.forget_type()); + *self.length += 1; + return; + } + Some(root) => root.borrow_mut().first_leaf_edge(), + } + } + Some(current) => current.next_leaf_edge(), + }; + + let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| { + drop(ins.left); + // SAFETY: The handle to the newly inserted value is always on a + // leaf node, so adding a new root node doesn't invalidate it. + let root = unsafe { self.root.reborrow().as_mut().unwrap() }; + root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) + }); + self.current = handle.left_edge().next_back_kv().ok(); + *self.length += 1; + } + + /// Inserts a new element into the `BTreeMap` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the end of the `BTreeMap`. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) { + let edge = match self.current.take() { + None => { + // SAFETY: We have no other reference to the tree. + match unsafe { self.root.reborrow() } { + root @ None => { + // Tree is empty, allocate a new root. + let mut node = NodeRef::new_leaf(self.alloc.clone()); + node.borrow_mut().push(key, value); + *root = Some(node.forget_type()); + *self.length += 1; + return; + } + Some(root) => root.borrow_mut().last_leaf_edge(), + } + } + Some(current) => current.next_back_leaf_edge(), + }; + + let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| { + drop(ins.left); + // SAFETY: The handle to the newly inserted value is always on a + // leaf node, so adding a new root node doesn't invalidate it. + let root = unsafe { self.root.reborrow().as_mut().unwrap() }; + root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right) + }); + self.current = handle.right_edge().next_kv().ok(); + *self.length += 1; + } + + /// Inserts a new element into the `BTreeMap` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the front of the `BTreeMap`. + /// + /// # Panics + /// + /// This function panics if: + /// - the given key compares less than or equal to the current element (if + /// any). + /// - the given key compares greater than or equal to the next element (if + /// any). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_after(&mut self, key: K, value: V) { + if let Some(current) = self.key() { + if &key <= current { + panic!("key must be ordered above the current element"); + } + } + if let Some((next, _)) = self.peek_prev() { + if &key >= next { + panic!("key must be ordered below the next element"); + } + } + unsafe { + self.insert_after_unchecked(key, value); + } + } + + /// Inserts a new element into the `BTreeMap` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the end of the `BTreeMap`. + /// + /// # Panics + /// + /// This function panics if: + /// - the given key compares greater than or equal to the current element + /// (if any). + /// - the given key compares less than or equal to the previous element (if + /// any). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_before(&mut self, key: K, value: V) { + if let Some(current) = self.key() { + if &key >= current { + panic!("key must be ordered below the current element"); + } + } + if let Some((prev, _)) = self.peek_prev() { + if &key <= prev { + panic!("key must be ordered above the previous element"); + } + } + unsafe { + self.insert_before_unchecked(key, value); + } + } + + /// Removes the current element from the `BTreeMap`. + /// + /// The element that was removed is returned, and the cursor is + /// moved to point to the next element in the `BTreeMap`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. The cursor is not moved in this case. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_current(&mut self) -> Option<(K, V)> { + let current = self.current.take()?; + let mut emptied_internal_root = false; + let (kv, pos) = + current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); + self.current = pos.next_kv().ok(); + *self.length -= 1; + if emptied_internal_root { + // SAFETY: This is safe since current does not point within the now + // empty root node. + let root = unsafe { self.root.reborrow().as_mut().unwrap() }; + root.pop_internal_level(self.alloc.clone()); + } + Some(kv) + } + + /// Removes the current element from the `BTreeMap`. + /// + /// The element that was removed is returned, and the cursor is + /// moved to point to the previous element in the `BTreeMap`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. The cursor is not moved in this case. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> { + let current = self.current.take()?; + let mut emptied_internal_root = false; + let (kv, pos) = + current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone()); + self.current = pos.next_back_kv().ok(); + *self.length -= 1; + if emptied_internal_root { + // SAFETY: This is safe since current does not point within the now + // empty root node. + let root = unsafe { self.root.reborrow().as_mut().unwrap() }; + root.pop_internal_level(self.alloc.clone()); + } + Some(kv) + } } #[cfg(test)] diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 370b58864af..e9366eec9ce 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -347,7 +347,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// assert_eq!(map["poneyland"], 37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(self, value: V) -> &'a mut V { + pub fn insert(mut self, value: V) -> &'a mut V { let out_ptr = match self.handle { None => { // SAFETY: There is no tree yet so no reference to it exists. @@ -358,25 +358,27 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { map.length = 1; val_ptr } - Some(handle) => match handle.insert_recursing(self.key, value, self.alloc.clone()) { - (None, val_ptr) => { - // SAFETY: We have consumed self.handle. - let map = unsafe { self.dormant_map.awaken() }; - map.length += 1; - val_ptr - } - (Some(ins), val_ptr) => { - drop(ins.left); - // SAFETY: We have consumed self.handle and dropped the - // remaining reference to the tree, ins.left. - let map = unsafe { self.dormant_map.awaken() }; - let root = map.root.as_mut().unwrap(); // same as ins.left - root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right); - map.length += 1; - val_ptr - } - }, + Some(handle) => { + let new_handle = + handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| { + drop(ins.left); + // SAFETY: Pushing a new root node doesn't invalidate + // handles to existing nodes. + let map = unsafe { self.dormant_map.reborrow() }; + let root = map.root.as_mut().unwrap(); // same as ins.left + root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right) + }); + + // Get the pointer to the value + let val_ptr = new_handle.into_val_mut(); + + // SAFETY: We have consumed self.handle. + let map = unsafe { self.dormant_map.awaken() }; + map.length += 1; + val_ptr + } }; + // Now that we have finished growing the tree using borrowed references, // dereference the pointer to a part of it, that we picked up along the way. unsafe { &mut *out_ptr } diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 700b1463bfd..76c2f27b466 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2336,3 +2336,52 @@ fn from_array() { let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]); assert_eq!(map, unordered_duplicates); } + +#[test] +fn test_cursor() { + let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]); + + let mut cur = map.lower_bound(Bound::Unbounded); + assert_eq!(cur.key(), Some(&1)); + cur.move_next(); + assert_eq!(cur.key(), Some(&2)); + assert_eq!(cur.peek_next(), Some((&3, &'c'))); + cur.move_prev(); + assert_eq!(cur.key(), Some(&1)); + assert_eq!(cur.peek_prev(), None); + + let mut cur = map.upper_bound(Bound::Excluded(&1)); + assert_eq!(cur.key(), None); + cur.move_next(); + assert_eq!(cur.key(), Some(&1)); + cur.move_prev(); + assert_eq!(cur.key(), None); + assert_eq!(cur.peek_prev(), Some((&3, &'c'))); +} + +#[test] +fn test_cursor_mut() { + let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]); + let mut cur = map.lower_bound_mut(Bound::Excluded(&3)); + assert_eq!(cur.key(), Some(&5)); + cur.insert_before(4, 'd'); + assert_eq!(cur.key(), Some(&5)); + assert_eq!(cur.peek_prev(), Some((&4, &mut 'd'))); + cur.move_next(); + assert_eq!(cur.key(), None); + cur.insert_before(6, 'f'); + assert_eq!(cur.key(), None); + assert_eq!(cur.remove_current(), None); + assert_eq!(cur.key(), None); + cur.insert_after(0, '?'); + assert_eq!(cur.key(), None); + assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')])); + + let mut cur = map.upper_bound_mut(Bound::Included(&5)); + assert_eq!(cur.key(), Some(&5)); + assert_eq!(cur.remove_current(), Some((5, 'e'))); + assert_eq!(cur.key(), Some(&6)); + assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f'))); + assert_eq!(cur.key(), Some(&4)); + assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')])); +} diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 1e33c1e64d6..b890717e50b 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -4,6 +4,7 @@ use core::ops::RangeBounds; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; +use super::search::SearchBound; use crate::alloc::Allocator; // `front` and `back` are always both `None` or both `Some`. @@ -386,7 +387,7 @@ impl<BorrowType: marker::BorrowType, K, V> /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the left side, which is either in the same leaf node or in an ancestor node. /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node. - fn next_back_kv( + pub fn next_back_kv( self, ) -> Result< Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>, @@ -707,7 +708,9 @@ impl<BorrowType: marker::BorrowType, K, V> } /// Returns the leaf edge closest to a KV for backward navigation. - fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> { + pub fn next_back_leaf_edge( + self, + ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> { match self.force() { Leaf(leaf_kv) => leaf_kv.left_edge(), Internal(internal_kv) => { @@ -717,3 +720,51 @@ impl<BorrowType: marker::BorrowType, K, V> } } } + +impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> { + /// Returns the leaf edge corresponding to the first point at which the + /// given bound is true. + pub fn lower_bound<Q: ?Sized>( + self, + mut bound: SearchBound<&Q>, + ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> + where + Q: Ord, + K: Borrow<Q>, + { + let mut node = self; + loop { + let (edge, new_bound) = node.find_lower_bound_edge(bound); + match edge.force() { + Leaf(edge) => return edge, + Internal(edge) => { + node = edge.descend(); + bound = new_bound; + } + } + } + } + + /// Returns the leaf edge corresponding to the last point at which the + /// given bound is true. + pub fn upper_bound<Q: ?Sized>( + self, + mut bound: SearchBound<&Q>, + ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> + where + Q: Ord, + K: Borrow<Q>, + { + let mut node = self; + loop { + let (edge, new_bound) = node.find_upper_bound_edge(bound); + match edge.force() { + Leaf(edge) => return edge, + Internal(edge) => { + node = edge.descend(); + bound = new_bound; + } + } + } + } +} diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 6912466448f..3233a575ecf 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -442,6 +442,24 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { // SAFETY: we have exclusive access to the entire node. unsafe { &mut *ptr } } + + /// Returns a dormant copy of this node with its lifetime erased which can + /// be reawakened later. + pub fn dormant(&self) -> NodeRef<marker::DormantMut, K, V, Type> { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } +} + +impl<K, V, Type> NodeRef<marker::DormantMut, K, V, Type> { + /// Revert to the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn awaken<'a>(self) -> NodeRef<marker::Mut<'a>, K, V, Type> { + NodeRef { height: self.height, node: self.node, _marker: PhantomData } + } } impl<K, V, Type> NodeRef<marker::Dying, K, V, Type> { @@ -798,6 +816,25 @@ impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeT // We can't use Handle::new_kv or Handle::new_edge because we don't know our type Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData } } + + /// Returns a dormant copy of this handle which can be reawakened later. + /// + /// See `DormantMutRef` for more details. + pub fn dormant(&self) -> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> { + Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData } + } +} + +impl<K, V, NodeType, HandleType> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> { + /// Revert to the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn awaken<'a>(self) -> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> { + Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData } + } } impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> { @@ -851,9 +888,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark /// Inserts a new key-value pair between the key-value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. - /// - /// The returned pointer points to the inserted value. - fn insert_fit(&mut self, key: K, val: V) -> *mut V { + unsafe fn insert_fit( + mut self, + key: K, + val: V, + ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> { debug_assert!(self.node.len() < CAPACITY); let new_len = self.node.len() + 1; @@ -862,7 +901,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark slice_insert(self.node.val_area_mut(..new_len), self.idx, val); *self.node.len_mut() = new_len as u16; - self.node.val_area_mut(self.idx).assume_init_mut() + Handle::new_kv(self.node, self.idx) } } } @@ -871,21 +910,26 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark /// Inserts a new key-value pair between the key-value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room. /// - /// The returned pointer points to the inserted value. + /// Returns a dormant handle to the inserted node which can be reawakened + /// once splitting is complete. fn insert<A: Allocator + Clone>( - mut self, + self, key: K, val: V, alloc: A, - ) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) { + ) -> ( + Option<SplitResult<'a, K, V, marker::Leaf>>, + Handle<NodeRef<marker::DormantMut, K, V, marker::Leaf>, marker::KV>, + ) { if self.node.len() < CAPACITY { - let val_ptr = self.insert_fit(key, val); - (None, val_ptr) + // SAFETY: There is enough space in the node for insertion. + let handle = unsafe { self.insert_fit(key, val) }; + (None, handle.dormant()) } else { let (middle_kv_idx, insertion) = splitpoint(self.idx); let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) }; let mut result = middle.split(alloc); - let mut insertion_edge = match insertion { + let insertion_edge = match insertion { LeftOrRight::Left(insert_idx) => unsafe { Handle::new_edge(result.left.reborrow_mut(), insert_idx) }, @@ -893,8 +937,10 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark Handle::new_edge(result.right.borrow_mut(), insert_idx) }, }; - let val_ptr = insertion_edge.insert_fit(key, val); - (Some(result), val_ptr) + // SAFETY: We just split the node, so there is enough space for + // insertion. + let handle = unsafe { insertion_edge.insert_fit(key, val).dormant() }; + (Some(result), handle) } } } @@ -976,21 +1022,31 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark key: K, value: V, alloc: A, - ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) { - let (mut split, val_ptr) = match self.insert(key, value, alloc.clone()) { - (None, val_ptr) => return (None, val_ptr), - (Some(split), val_ptr) => (split.forget_node_type(), val_ptr), + split_root: impl FnOnce(SplitResult<'a, K, V, marker::LeafOrInternal>), + ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> { + let (mut split, handle) = match self.insert(key, value, alloc.clone()) { + // SAFETY: we have finished splitting and can now re-awaken the + // handle to the inserted element. + (None, handle) => return unsafe { handle.awaken() }, + (Some(split), handle) => (split.forget_node_type(), handle), }; loop { split = match split.left.ascend() { Ok(parent) => { match parent.insert(split.kv.0, split.kv.1, split.right, alloc.clone()) { - None => return (None, val_ptr), + // SAFETY: we have finished splitting and can now re-awaken the + // handle to the inserted element. + None => return unsafe { handle.awaken() }, Some(split) => split.forget_node_type(), } } - Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr), + Err(root) => { + split_root(SplitResult { left: root, ..split }); + // SAFETY: we have finished splitting and can now re-awaken the + // handle to the inserted element. + return unsafe { handle.awaken() }; + } }; } } @@ -1043,6 +1099,14 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType> let leaf = self.node.into_leaf_mut(); unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() } } + + pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + debug_assert!(self.idx < self.node.len()); + let leaf = self.node.into_leaf_mut(); + let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() }; + let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }; + (k, v) + } } impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, marker::KV> { @@ -1667,6 +1731,7 @@ pub mod marker { pub enum Owned {} pub enum Dying {} + pub enum DormantMut {} pub struct Immut<'a>(PhantomData<&'a ()>); pub struct Mut<'a>(PhantomData<&'a mut ()>); pub struct ValMut<'a>(PhantomData<&'a mut ()>); @@ -1688,6 +1753,7 @@ pub mod marker { impl<'a> BorrowType for Immut<'a> {} impl<'a> BorrowType for Mut<'a> {} impl<'a> BorrowType for ValMut<'a> {} + impl BorrowType for DormantMut {} pub enum KV {} pub enum Edge {} diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index eadb35cb96d..1da86e1a46a 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -558,7 +558,7 @@ pub use core::fmt::Alignment; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::fmt::{write, ArgumentV1, Arguments}; +pub use core::fmt::{write, Arguments}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ca75c3895f4..76dabfb429d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -87,6 +87,7 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] +#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] // // Library features: #![feature(alloc_layout_extra)] @@ -195,6 +196,7 @@ #![feature(c_unwind)] #![feature(with_negative_coherence)] #![cfg_attr(test, feature(panic_update_hook))] +#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c9aa23fc4af..fd1e3e0f75b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1092,7 +1092,7 @@ impl<T: ?Sized> Rc<T> { /// # Safety /// /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then - /// they must be must not be dereferenced or have active borrows for the duration + /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the /// inner type of this Rc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Rc::new`. diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index fecacc2bb63..093dcbbe8bf 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -782,6 +782,38 @@ impl<T, A: Allocator> BorrowMut<[T]> for Vec<T, A> { } } +// Specializable trait for implementing ToOwned::clone_into. This is +// public in the crate and has the Allocator parameter so that +// vec::clone_from use it too. +#[cfg(not(no_global_oom_handling))] +pub(crate) trait SpecCloneIntoVec<T, A: Allocator> { + fn clone_into(&self, target: &mut Vec<T, A>); +} + +#[cfg(not(no_global_oom_handling))] +impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] { + default fn clone_into(&self, target: &mut Vec<T, A>) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + + // target.len <= self.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = self.split_at(target.len()); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(init); + target.extend_from_slice(tail); + } +} + +#[cfg(not(no_global_oom_handling))] +impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] { + fn clone_into(&self, target: &mut Vec<T, A>) { + target.clear(); + target.extend_from_slice(self); + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone> ToOwned for [T] { @@ -797,16 +829,7 @@ impl<T: Clone> ToOwned for [T] { } fn clone_into(&self, target: &mut Vec<T>) { - // drop anything in target that will not be overwritten - target.truncate(self.len()); - - // target.len <= self.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = self.split_at(target.len()); - - // reuse the contained values' allocations/resources. - target.clone_from_slice(init); - target.extend_from_slice(tail); + SpecCloneIntoVec::clone_into(self, target); } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 9bc9182f7b5..f20486ca9e4 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1733,7 +1733,7 @@ impl<T: ?Sized> Arc<T> { /// # Safety /// /// If any other `Arc` or [`Weak`] pointers to the same allocation exist, then - /// they must be must not be dereferenced or have active borrows for the duration + /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the /// inner type of this Rc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Arc::new`. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 36b0b3c9e7c..a07f3da78d3 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2647,35 +2647,6 @@ impl<T, A: Allocator> ops::DerefMut for Vec<T, A> { } #[cfg(not(no_global_oom_handling))] -trait SpecCloneFrom { - fn clone_from(this: &mut Self, other: &Self); -} - -#[cfg(not(no_global_oom_handling))] -impl<T: Clone, A: Allocator> SpecCloneFrom for Vec<T, A> { - default fn clone_from(this: &mut Self, other: &Self) { - // drop anything that will not be overwritten - this.truncate(other.len()); - - // self.len <= other.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = other.split_at(this.len()); - - // reuse the contained values' allocations/resources. - this.clone_from_slice(init); - this.extend_from_slice(tail); - } -} - -#[cfg(not(no_global_oom_handling))] -impl<T: Copy, A: Allocator> SpecCloneFrom for Vec<T, A> { - fn clone_from(this: &mut Self, other: &Self) { - this.clear(); - this.extend_from_slice(other); - } -} - -#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { #[cfg(not(test))] @@ -2695,7 +2666,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { } fn clone_from(&mut self, other: &Self) { - SpecCloneFrom::clone_from(self, other) + crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self); } } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 129213fde74..7f109491350 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -196,7 +196,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; use crate::mem; -use crate::ops::{CoerceUnsized, Deref, DerefMut}; +use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn}; use crate::ptr::{self, NonNull}; mod lazy; @@ -571,6 +571,16 @@ impl<T: Default> Cell<T> { #[unstable(feature = "coerce_unsized", issue = "18598")] impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {} +// Allow types that wrap `Cell` to also implement `DispatchFromDyn` +// and become object safe method receivers. +// Note that currently `Cell` itself cannot be a method receiver +// because it does not implement Deref. +// In other words: +// `self: Cell<&Self>` won't work +// `self: CellWrapper<Self>` becomes possible +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {} + impl<T> Cell<[T]> { /// Returns a `&[Cell<T>]` from a `&Cell<[T]>` /// @@ -2078,6 +2088,16 @@ impl<T> const From<T> for UnsafeCell<T> { #[unstable(feature = "coerce_unsized", issue = "18598")] impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {} +// Allow types that wrap `UnsafeCell` to also implement `DispatchFromDyn` +// and become object safe method receivers. +// Note that currently `UnsafeCell` itself cannot be a method receiver +// because it does not implement Deref. +// In other words: +// `self: UnsafeCell<&Self>` won't work +// `self: UnsafeCellWrapper<Self>` becomes possible +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {} + /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` @@ -2169,6 +2189,17 @@ impl<T> const From<T> for SyncUnsafeCell<T> { //#[unstable(feature = "sync_unsafe_cell", issue = "95439")] impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {} +// Allow types that wrap `SyncUnsafeCell` to also implement `DispatchFromDyn` +// and become object safe method receivers. +// Note that currently `SyncUnsafeCell` itself cannot be a method receiver +// because it does not implement Deref. +// In other words: +// `self: SyncUnsafeCell<&Self>` won't work +// `self: SyncUnsafeCellWrapper<Self>` becomes possible +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +//#[unstable(feature = "sync_unsafe_cell", issue = "95439")] +impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {} + #[allow(unused)] fn assert_coerce_unsized( a: UnsafeCell<&i32>, diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 7757068a4f2..f74e563f1b9 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -298,3 +298,7 @@ impl<T> const From<T> for OnceCell<T> { OnceCell { inner: UnsafeCell::new(Some(value)) } } } + +// Just like for `Cell<T>` this isn't needed, but results in nicer error messages. +#[unstable(feature = "once_cell", issue = "74465")] +impl<T> !Sync for OnceCell<T> {} diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 7152300abcb..d2fac23ff18 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -28,6 +28,7 @@ use crate::fmt::{Debug, Display}; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] #[rustc_has_incoherent_inherent_impls] +#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 2a7ec544f9e..c9821bf8109 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -267,6 +267,7 @@ extern "C" { /// family of functions. It contains a function to format the given value. At /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. +#[cfg_attr(not(bootstrap), lang = "format_argument")] #[derive(Copy, Clone)] #[allow(missing_debug_implementations)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -279,6 +280,7 @@ pub struct ArgumentV1<'a> { /// This struct represents the unsafety of constructing an `Arguments`. /// It exists, rather than an unsafe function, in order to simplify the expansion /// of `format_args!(..)` and reduce the scope of the `unsafe` block. +#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")] #[allow(missing_debug_implementations)] #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -473,8 +475,8 @@ impl<'a> Arguments<'a> { /// ``` /// /// [`format()`]: ../../std/fmt/fn.format.html +#[cfg_attr(not(bootstrap), lang = "format_arguments")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")] #[derive(Copy, Clone)] pub struct Arguments<'a> { // Format string pieces to print. @@ -489,9 +491,26 @@ pub struct Arguments<'a> { } impl<'a> Arguments<'a> { - /// Get the formatted string, if it has no arguments to be formatted. + /// Get the formatted string, if it has no arguments to be formatted at runtime. /// - /// This can be used to avoid allocations in the most trivial case. + /// This can be used to avoid allocations in some cases. + /// + /// # Guarantees + /// + /// For `format_args!("just a literal")`, this function is guaranteed to + /// return `Some("just a literal")`. + /// + /// For most cases with placeholders, this function will return `None`. + /// + /// However, the compiler may perform optimizations that can cause this + /// function to return `Some(_)` even if the format string contains + /// placeholders. For example, `format_args!("Hello, {}!", "world")` may be + /// optimized to `format_args!("Hello, world!")`, such that `as_str()` + /// returns `Some("Hello, world!")`. + /// + /// The behavior for anything but the trivial case (without placeholders) + /// is not guaranteed, and should not be relied upon for anything other + /// than optimization. /// /// # Examples /// @@ -512,7 +531,7 @@ impl<'a> Arguments<'a> { /// ```rust /// assert_eq!(format_args!("hello").as_str(), Some("hello")); /// assert_eq!(format_args!("").as_str(), Some("")); - /// assert_eq!(format_args!("{}", 1).as_str(), None); + /// assert_eq!(format_args!("{:?}", std::env::current_dir()).as_str(), None); /// ``` #[stable(feature = "fmt_as_str", since = "1.52.0")] #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] diff --git a/library/core/src/fmt/rt/v1.rs b/library/core/src/fmt/rt/v1.rs index 37202b2774d..11a50951a75 100644 --- a/library/core/src/fmt/rt/v1.rs +++ b/library/core/src/fmt/rt/v1.rs @@ -5,7 +5,9 @@ //! these can be statically allocated and are slightly optimized for the runtime #![allow(missing_debug_implementations)] +#[cfg_attr(not(bootstrap), lang = "format_placeholder")] #[derive(Copy, Clone)] +// FIXME: Rename this to Placeholder pub struct Argument { pub position: usize, pub format: FormatSpec, @@ -20,7 +22,22 @@ pub struct FormatSpec { pub width: Count, } +impl Argument { + #[inline(always)] + pub const fn new( + position: usize, + fill: char, + align: Alignment, + flags: u32, + precision: Count, + width: Count, + ) -> Self { + Self { position, format: FormatSpec { fill, align, flags, precision, width } } + } +} + /// Possible alignments that can be requested as part of a formatting directive. +#[cfg_attr(not(bootstrap), lang = "format_alignment")] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { /// Indication that contents should be left-aligned. @@ -34,6 +51,7 @@ pub enum Alignment { } /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. +#[cfg_attr(not(bootstrap), lang = "format_count")] #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index e3157b66902..3d7ccffa173 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -211,13 +211,16 @@ //! //! #### Statements //! - Assign statements work via normal Rust assignment. -//! - [`Retag`] statements have an associated function. +//! - [`Retag`], [`StorageLive`], [`StorageDead`], [`Deinit`] statements have an associated function. //! //! #### Rvalues //! //! - Operands implicitly convert to `Use` rvalues. //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. -//! - [`Discriminant`] has an associated function. +//! - [`Discriminant`] and [`Len`] have associated functions. +//! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. +//! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. +//! - Array repetition syntax (`[foo; 10]`) creates the associated rvalue. //! //! #### Terminators //! @@ -261,6 +264,9 @@ define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: B define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T)); define!("mir_storage_live", fn StorageLive<T>(local: T)); define!("mir_storage_dead", fn StorageDead<T>(local: T)); +define!("mir_deinit", fn Deinit<T>(place: T)); +define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool)); +define!("mir_len", fn Len<T>(place: T) -> usize); define!("mir_retag", fn Retag<T>(place: T)); define!("mir_move", fn Move<T>(place: T) -> T); define!("mir_static", fn Static<T>(s: T) -> &'static T); diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index e0d665c9e12..6bdf53f7fc9 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -99,7 +99,7 @@ where ) -> impl FnMut((), T) -> ControlFlow<B> + '_ { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::CONTINUE, + None => ControlFlow::Continue(()), } } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 307016c2690..b040a0ea901 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -539,7 +539,7 @@ where #[rustc_inherit_overflow_checks] fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> { match iter.advance_by(n) { - Ok(()) => ControlFlow::BREAK, + Ok(()) => ControlFlow::Break(()), Err(advanced) => ControlFlow::Continue(n - advanced), } } @@ -629,7 +629,7 @@ where #[rustc_inherit_overflow_checks] fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> { match iter.advance_back_by(n) { - Ok(()) => ControlFlow::BREAK, + Ok(()) => ControlFlow::Break(()), Err(advanced) => ControlFlow::Continue(n - advanced), } } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index bdf94c792c2..ed23873cdde 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -352,7 +352,7 @@ pub trait DoubleEndedIterator: Iterator { #[inline] fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index a4a665d48d5..5a0b8594104 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2601,10 +2601,10 @@ pub trait Iterator { #[inline] fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> { move |(), x| { - if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } + if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } } } - self.try_fold((), check(f)) == ControlFlow::CONTINUE + self.try_fold((), check(f)) == ControlFlow::Continue(()) } /// Tests if any element of the iterator matches a predicate. @@ -2654,11 +2654,11 @@ pub trait Iterator { #[inline] fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> { move |(), x| { - if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } + if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) } } } - self.try_fold((), check(f)) == ControlFlow::BREAK + self.try_fold((), check(f)) == ControlFlow::Break(()) } /// Searches for an element of an iterator that satisfies a predicate. @@ -2717,7 +2717,7 @@ pub trait Iterator { #[inline] fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow<T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } } } @@ -2749,7 +2749,7 @@ pub trait Iterator { fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> ControlFlow<B> { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::CONTINUE, + None => ControlFlow::Continue(()), } } @@ -2812,7 +2812,7 @@ pub trait Iterator { R: Residual<Option<I>>, { move |(), x| match f(&x).branch() { - ControlFlow::Continue(false) => ControlFlow::CONTINUE, + ControlFlow::Continue(false) => ControlFlow::Continue(()), ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))), ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)), } @@ -3491,7 +3491,7 @@ pub trait Iterator { F: FnMut(X, Y) -> Ordering, { move |x, y| match cmp(x, y) { - Ordering::Equal => ControlFlow::CONTINUE, + Ordering::Equal => ControlFlow::Continue(()), non_eq => ControlFlow::Break(non_eq), } } @@ -3567,7 +3567,7 @@ pub trait Iterator { F: FnMut(X, Y) -> Option<Ordering>, { move |x, y| match partial_cmp(x, y) { - Some(Ordering::Equal) => ControlFlow::CONTINUE, + Some(Ordering::Equal) => ControlFlow::Continue(()), non_eq => ControlFlow::Break(non_eq), } } @@ -3625,7 +3625,7 @@ pub trait Iterator { F: FnMut(X, Y) -> bool, { move |x, y| { - if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } + if eq(x, y) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } } } @@ -3859,7 +3859,7 @@ pub trait Iterator { /// Compares two iterators element-wise using the given function. /// -/// If `ControlFlow::CONTINUE` is returned from the function, the comparison moves on to the next +/// If `ControlFlow::Continue(())` is returned from the function, the comparison moves on to the next /// elements of both iterators. Returning `ControlFlow::Break(x)` short-circuits the iteration and /// returns `ControlFlow::Break(x)`. If one of the iterators runs out of elements, /// `ControlFlow::Continue(ord)` is returned where `ord` is the result of comparing the lengths of diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 8790649abe6..6dfe36e6926 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -95,6 +95,7 @@ #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] +#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] // // Library features: #![feature(const_align_offset)] @@ -235,6 +236,7 @@ #![feature(unsized_fn_params)] #![feature(asm_const)] #![feature(const_transmute_copy)] +#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] // // Target features: #![feature(arm_target_feature)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1326fc9ab09..74055602ec2 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -469,6 +469,62 @@ pub macro Copy($item:item) { #[cfg_attr(not(test), rustc_diagnostic_item = "Sync")] #[lang = "sync"] #[rustc_on_unimplemented( + on( + _Self = "std::cell::OnceCell<T>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" + ), + on( + _Self = "std::cell::Cell<u8>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", + ), + on( + _Self = "std::cell::Cell<u16>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", + ), + on( + _Self = "std::cell::Cell<u32>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", + ), + on( + _Self = "std::cell::Cell<u64>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", + ), + on( + _Self = "std::cell::Cell<usize>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", + ), + on( + _Self = "std::cell::Cell<i8>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", + ), + on( + _Self = "std::cell::Cell<i16>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", + ), + on( + _Self = "std::cell::Cell<i32>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", + ), + on( + _Self = "std::cell::Cell<i64>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", + ), + on( + _Self = "std::cell::Cell<isize>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", + ), + on( + _Self = "std::cell::Cell<bool>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", + ), + on( + _Self = "std::cell::Cell<T>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", + ), + on( + _Self = "std::cell::RefCell<T>", + note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", + ), message = "`{Self}` cannot be shared between threads safely", label = "`{Self}` cannot be shared between threads safely" )] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2cae98b8e49..b59f28193e2 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -5,7 +5,7 @@ macro_rules! int_impl { $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr, $bound_condition:expr) => { /// The smallest value that can be represented by this integer type - #[doc = concat!("(−2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ")")] + #[doc = concat!("(−2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ").")] /// /// # Examples /// @@ -18,7 +18,7 @@ macro_rules! int_impl { pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; /// The largest value that can be represented by this integer type - #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> − 1", $bound_condition, ")")] + #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> − 1", $bound_condition, ").")] /// /// # Examples /// @@ -2574,12 +2574,13 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[rustc_allow_const_fn_unstable(const_cmp)] pub const fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } + // Picking the right way to phrase this is complicated + // (<https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>) + // so delegate it to `Ord` which is already producing -1/0/+1 + // exactly like we need and can be the place to deal with the complexity. + self.cmp(&0) as _ } /// Returns `true` if `self` is positive and `false` if the number is zero or diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index cd183540cd5..117706fb4b2 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -259,46 +259,3 @@ impl<R: ops::Try> ControlFlow<R, R::Output> { } } } - -impl<B> ControlFlow<B, ()> { - /// It's frequently the case that there's no value needed with `Continue`, - /// so this provides a way to avoid typing `(())`, if you prefer it. - /// - /// # Examples - /// - /// ``` - /// #![feature(control_flow_enum)] - /// use std::ops::ControlFlow; - /// - /// let mut partial_sum = 0; - /// let last_used = (1..10).chain(20..25).try_for_each(|x| { - /// partial_sum += x; - /// if partial_sum > 100 { ControlFlow::Break(x) } - /// else { ControlFlow::CONTINUE } - /// }); - /// assert_eq!(last_used.break_value(), Some(22)); - /// ``` - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub const CONTINUE: Self = ControlFlow::Continue(()); -} - -impl<C> ControlFlow<(), C> { - /// APIs like `try_for_each` don't need values with `Break`, - /// so this provides a way to avoid typing `(())`, if you prefer it. - /// - /// # Examples - /// - /// ``` - /// #![feature(control_flow_enum)] - /// use std::ops::ControlFlow; - /// - /// let mut partial_sum = 0; - /// (1..10).chain(20..25).try_for_each(|x| { - /// if partial_sum > 100 { ControlFlow::BREAK } - /// else { partial_sum += x; ControlFlow::CONTINUE } - /// }); - /// assert_eq!(partial_sum, 108); - /// ``` - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub const BREAK: Self = ControlFlow::Break(()); -} diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 7cc00e3f8d1..c43b728022d 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -551,7 +551,7 @@ use crate::marker::Destruct; use crate::panicking::{panic, panic_str}; use crate::pin::Pin; use crate::{ - convert, hint, mem, + cmp, convert, hint, mem, ops::{self, ControlFlow, Deref, DerefMut}, }; @@ -2090,6 +2090,12 @@ impl<T: PartialEq> PartialEq for Option<T> { } } +/// This specialization trait is a workaround for LLVM not currently (2023-01) +/// being able to optimize this itself, even though Alive confirms that it would +/// be legal to do so: <https://github.com/llvm/llvm-project/issues/52622> +/// +/// Once that's fixed, `Option` should go back to deriving `PartialEq`, as +/// it used to do before <https://github.com/rust-lang/rust/pull/103556>. #[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")] #[doc(hidden)] pub trait SpecOptionPartialEq: Sized { @@ -2146,6 +2152,14 @@ impl<T> SpecOptionPartialEq for crate::ptr::NonNull<T> { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl SpecOptionPartialEq for cmp::Ordering { + #[inline] + fn eq(l: &Option<Self>, r: &Option<Self>) -> bool { + l.map_or(2, |x| x as i8) == r.map_or(2, |x| x as i8) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 7b1cb5488bc..16eb726f6f6 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -731,7 +731,7 @@ impl<T: ?Sized> *const T { /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is /// guaranteed to be non-negative. This method is equivalent to - /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`, + /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`, /// but it provides slightly more information to the optimizer, which can /// sometimes allow it to optimize slightly better with some backends. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ed1e3bd4812..0a2f63e3ec6 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -904,7 +904,7 @@ impl<T: ?Sized> *mut T { /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is /// guaranteed to be non-negative. This method is equivalent to - /// `usize::from(self.offset_from(origin)).unwrap_unchecked()`, + /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`, /// but it provides slightly more information to the optimizer, which can /// sometimes allow it to optimize slightly better with some backends. /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 14367eb09bc..818721062d7 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1861,7 +1861,8 @@ macro_rules! if_not_8_bit { ($_:ident, $($tt:tt)*) => { $($tt)* }; } -#[cfg(target_has_atomic_load_store = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))] +#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))] macro_rules! atomic_int { ($cfg_cas:meta, $cfg_align:meta, @@ -2988,7 +2989,8 @@ atomic_int_ptr_sized! { } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, @@ -3030,7 +3032,8 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T { } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_swap`. @@ -3047,7 +3050,8 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_add). #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_add`. @@ -3064,7 +3068,8 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the previous value (like __sync_fetch_and_sub). #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_sub`. @@ -3080,7 +3085,8 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange<T: Copy>( dst: *mut T, @@ -3115,7 +3121,8 @@ unsafe fn atomic_compare_exchange<T: Copy>( } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_compare_exchange_weak<T: Copy>( dst: *mut T, @@ -3150,7 +3157,8 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>( } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_and` @@ -3166,7 +3174,8 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_nand` @@ -3182,7 +3191,8 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_or` @@ -3198,7 +3208,8 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_xor` @@ -3215,7 +3226,8 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (signed comparison) #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_max` @@ -3232,7 +3244,8 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (signed comparison) #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_min` @@ -3249,7 +3262,8 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the max value (unsigned comparison) #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umax` @@ -3266,7 +3280,8 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// returns the min value (unsigned comparison) #[inline] -#[cfg(target_has_atomic = "8")] +#[cfg_attr(not(bootstrap), cfg(target_has_atomic))] +#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_umin` diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index f0e4f5d8a80..938935771d6 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -74,6 +74,7 @@ pub fn is_available() -> bool { /// /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` /// and `#[proc_macro_derive]` definitions. +#[rustc_diagnostic_item = "TokenStream"] #[stable(feature = "proc_macro_lib", since = "1.15.0")] #[derive(Clone)] pub struct TokenStream(Option<bridge::client::TokenStream>); @@ -581,7 +582,7 @@ impl fmt::Debug for Span { /// A line-column pair representing the start or end of a `Span`. #[unstable(feature = "proc_macro_span", issue = "54725")] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct LineColumn { /// The 1-indexed line in the source file on which the span starts or ends (inclusive). #[unstable(feature = "proc_macro_span", issue = "54725")] diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index eb582be012b..839fdc96632 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -12,6 +12,8 @@ use crate::time::{Duration, Instant}; use rand::RngCore; +#[cfg(target_os = "macos")] +use crate::ffi::{c_char, c_int}; #[cfg(unix)] use crate::os::unix::fs::symlink as symlink_dir; #[cfg(unix)] @@ -24,8 +26,6 @@ use crate::os::windows::fs::{symlink_dir, symlink_file}; use crate::sys::fs::symlink_junction; #[cfg(target_os = "macos")] use crate::sys::weak::weak; -#[cfg(target_os = "macos")] -use libc::{c_char, c_int}; macro_rules! check { ($e:expr) => { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 99cc0186310..762f7a7c9a1 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -358,7 +358,6 @@ #![feature(const_ip)] #![feature(const_ipv4)] #![feature(const_ipv6)] -#![feature(const_socketaddr)] #![feature(thread_local_internals)] // #![default_lib_allocator] diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs index 33b0dfa03e0..1264bae809b 100644 --- a/library/std/src/net/socket_addr.rs +++ b/library/std/src/net/socket_addr.rs @@ -133,7 +133,7 @@ impl SocketAddr { /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[must_use] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn new(ip: IpAddr, port: u16) -> SocketAddr { match ip { IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)), @@ -153,7 +153,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "ip_addr", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn ip(&self) -> IpAddr { match *self { SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()), @@ -194,7 +194,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn port(&self) -> u16 { match *self { SocketAddr::V4(ref a) => a.port(), @@ -238,7 +238,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn is_ipv4(&self) -> bool { matches!(*self, SocketAddr::V4(_)) } @@ -260,7 +260,7 @@ impl SocketAddr { /// ``` #[must_use] #[stable(feature = "sockaddr_checker", since = "1.16.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn is_ipv6(&self) -> bool { matches!(*self, SocketAddr::V6(_)) } @@ -280,7 +280,7 @@ impl SocketAddrV4 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { ip, port } } @@ -297,7 +297,7 @@ impl SocketAddrV4 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn ip(&self) -> &Ipv4Addr { &self.ip } @@ -330,7 +330,7 @@ impl SocketAddrV4 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn port(&self) -> u16 { self.port } @@ -371,7 +371,7 @@ impl SocketAddrV6 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 { SocketAddrV6 { ip, port, flowinfo, scope_id } } @@ -388,7 +388,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn ip(&self) -> &Ipv6Addr { &self.ip } @@ -421,7 +421,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn port(&self) -> u16 { self.port } @@ -464,7 +464,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn flowinfo(&self) -> u32 { self.flowinfo } @@ -504,7 +504,7 @@ impl SocketAddrV6 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")] + #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")] pub const fn scope_id(&self) -> u32 { self.scope_id } diff --git a/library/std/src/os/fuchsia/raw.rs b/library/std/src/os/fuchsia/raw.rs index 060d6e86b6c..ea6b94f2f13 100644 --- a/library/std/src/os/fuchsia/raw.rs +++ b/library/std/src/os/fuchsia/raw.rs @@ -24,12 +24,7 @@ pub type pthread_t = c_ulong; #[stable(feature = "raw_ext", since = "1.1.0")] pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; -#[cfg(any( - target_arch = "x86", - target_arch = "le32", - target_arch = "powerpc", - target_arch = "arm" -))] +#[cfg(any(target_arch = "x86", target_arch = "powerpc", target_arch = "arm"))] mod arch { use crate::os::raw::{c_long, c_short, c_uint}; diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs index 699e8be33c8..b3f7439f8cd 100644 --- a/library/std/src/os/l4re/raw.rs +++ b/library/std/src/os/l4re/raw.rs @@ -26,7 +26,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; #[cfg(any( target_arch = "x86", - target_arch = "le32", target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index c73791d1452..f46028c3a96 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -26,7 +26,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; #[cfg(any( target_arch = "x86", - target_arch = "le32", target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs index 5ec267c41e9..b7046dd7c59 100644 --- a/library/std/src/os/net/mod.rs +++ b/library/std/src/os/net/mod.rs @@ -1,4 +1,13 @@ //! OS-specific networking functionality. +// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must +// be special-cased during rustdoc generation. +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] #[cfg(any(target_os = "linux", target_os = "android", doc))] pub(super) mod linux_ext; diff --git a/library/std/src/personality/emcc.rs b/library/std/src/personality/emcc.rs index f942bdf18c1..cb52ae89b19 100644 --- a/library/std/src/personality/emcc.rs +++ b/library/std/src/personality/emcc.rs @@ -1,7 +1,7 @@ //! On Emscripten Rust panics are wrapped in C++ exceptions, so we just forward //! to `__gxx_personality_v0` which is provided by Emscripten. -use libc::c_int; +use crate::ffi::c_int; use unwind as uw; // This is required by the compiler to exist (e.g., it's a lang item), but it's diff --git a/library/std/src/personality/gcc.rs b/library/std/src/personality/gcc.rs index 5fc1b91a1c3..41c0fe725a5 100644 --- a/library/std/src/personality/gcc.rs +++ b/library/std/src/personality/gcc.rs @@ -37,7 +37,8 @@ //! and the last personality routine transfers control to the catch block. use super::dwarf::eh::{self, EHAction, EHContext}; -use libc::{c_int, uintptr_t}; +use crate::ffi::c_int; +use libc::uintptr_t; use unwind as uw; // Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index c1e3e48b044..c6bb09b0417 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -319,19 +319,10 @@ impl<T> Channel<T> { ) -> Result<(), SendTimeoutError<T>> { let token = &mut Token::default(); loop { - // Try sending a message several times. - let backoff = Backoff::new(); - loop { - if self.start_send(token) { - let res = unsafe { self.write(token, msg) }; - return res.map_err(SendTimeoutError::Disconnected); - } - - if backoff.is_completed() { - break; - } else { - backoff.spin_light(); - } + // Try sending a message. + if self.start_send(token) { + let res = unsafe { self.write(token, msg) }; + return res.map_err(SendTimeoutError::Disconnected); } if let Some(d) = deadline { @@ -379,6 +370,7 @@ impl<T> Channel<T> { pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> { let token = &mut Token::default(); loop { + // Try receiving a message. if self.start_recv(token) { let res = unsafe { self.read(token) }; return res.map_err(|_| RecvTimeoutError::Disconnected); diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs index cfe42750d52..d053d69e26e 100644 --- a/library/std/src/sync/mpmc/utils.rs +++ b/library/std/src/sync/mpmc/utils.rs @@ -105,10 +105,8 @@ impl Backoff { /// Backs off using lightweight spinning. /// - /// This method should be used for: - /// - Retrying an operation because another thread made progress. i.e. on CAS failure. - /// - Waiting for an operation to complete by spinning optimistically for a few iterations - /// before falling back to parking the thread (see `Backoff::is_completed`). + /// This method should be used for retrying an operation because another thread made + /// progress. i.e. on CAS failure. #[inline] pub fn spin_light(&self) { let step = self.step.get().min(SPIN_LIMIT); @@ -134,10 +132,4 @@ impl Backoff { self.step.set(self.step.get() + 1); } - - /// Returns `true` if quadratic backoff has completed and parking the thread is advised. - #[inline] - pub fn is_completed(&self) -> bool { - self.step.get() > SPIN_LIMIT - } } diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 3edbe728077..403a5e627f1 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -7,6 +7,7 @@ use crate::ptr; #[cfg(any( target_arch = "x86", target_arch = "arm", + target_arch = "m68k", target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs index c31fb3a48da..236d2f2ee29 100644 --- a/library/std/src/sys/unix/thread_local_dtor.rs +++ b/library/std/src/sys/unix/thread_local_dtor.rs @@ -11,13 +11,7 @@ // Note, however, that we run on lots older linuxes, as well as cross // compiling from a newer linux to an older linux, so we also have a // fallback implementation to use as well. -#[cfg(any( - target_os = "linux", - target_os = "fuchsia", - target_os = "redox", - target_os = "emscripten" -))] -#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten) +#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::mem; use crate::sys_common::thread_local_dtor::register_dtor_fallback; @@ -89,7 +83,8 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { } } -#[cfg(any(target_os = "vxworks", target_os = "horizon"))] +#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))] +#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten) pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::sys_common::thread_local_dtor::register_dtor_fallback; register_dtor_fallback(t, dtor); diff --git a/library/std/src/sys/windows/thread_parking.rs b/library/std/src/sys/windows/thread_parking.rs index 5d43676adbb..eb9167cd855 100644 --- a/library/std/src/sys/windows/thread_parking.rs +++ b/library/std/src/sys/windows/thread_parking.rs @@ -221,7 +221,7 @@ impl Parker { fn keyed_event_handle() -> c::HANDLE { const INVALID: c::HANDLE = ptr::invalid_mut(!0); - static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID); + static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(INVALID); match HANDLE.load(Relaxed) { INVALID => { let mut handle = c::INVALID_HANDLE_VALUE; diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index fad4a63331b..2c38dfecf97 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -14,7 +14,7 @@ use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; -use libc::{c_int, c_void}; +use crate::ffi::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( @@ -47,7 +47,7 @@ cfg_if::cfg_if! { target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "solaris", target_os = "illumos"))] { - use libc::c_uchar; + use crate::ffi::c_uchar; type IpV4MultiCastType = c_uchar; } else { type IpV4MultiCastType = c_int; @@ -127,8 +127,8 @@ fn to_ipv6mr_interface(value: u32) -> c_int { } #[cfg(not(target_os = "android"))] -fn to_ipv6mr_interface(value: u32) -> libc::c_uint { - value as libc::c_uint +fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint { + value as crate::ffi::c_uint } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/time.rs b/library/std/src/time.rs index ecd06ebf743..acf9c29083f 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -1,6 +1,6 @@ //! Temporal quantification. //! -//! # Examples: +//! # Examples //! //! There are multiple ways to create a new [`Duration`]: //! diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 1a2c1255661..bf3c81fcc98 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -120,16 +120,13 @@ fn x86_all() { println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq")); println!("avx512er: {:?}", is_x86_feature_detected!("avx512er")); println!("avx512f: {:?}", is_x86_feature_detected!("avx512f")); - println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni")); println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma")); println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf")); - println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes")); println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2")); println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi")); println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl")); println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni")); println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect")); - println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq")); println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq")); println!("avx: {:?}", is_x86_feature_detected!("avx")); println!("bmi1: {:?}", is_x86_feature_detected!("bmi1")); @@ -138,6 +135,7 @@ fn x86_all() { println!("f16c: {:?}", is_x86_feature_detected!("f16c")); println!("fma: {:?}", is_x86_feature_detected!("fma")); println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); + println!("gfni: {:?}", is_x86_feature_detected!("gfni")); println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); //println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); @@ -154,6 +152,8 @@ fn x86_all() { println!("sse: {:?}", is_x86_feature_detected!("sse")); println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); println!("tbm: {:?}", is_x86_feature_detected!("tbm")); + println!("vaes: {:?}", is_x86_feature_detected!("vaes")); + println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq")); println!("xsave: {:?}", is_x86_feature_detected!("xsave")); println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt")); diff --git a/library/stdarch b/library/stdarch -Subproject 790411f93c4b5eada3c23abb4c9a063fb0b24d9 +Subproject a0c30f3e3c75adcd6ee7efc94014ebcead61c50 diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index 796796e07a9..9d22ebbee87 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -309,7 +309,8 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { // FIXME: Copied from librustc_ast until linkage errors are resolved. Issue #47566 fn is_nightly() -> bool { // Whether this is a feature-staged build, i.e., on the beta or stable channel - let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + let disable_unstable_features = + option_env!("CFG_DISABLE_UNSTABLE_FEATURES").map(|s| s != "0").unwrap_or(false); // Whether we should enable unstable features for bootstrapping let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 24cbe035f2f..1ee68c8540b 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -53,6 +53,7 @@ pub struct ConsoleTestState { pub metrics: MetricMap, pub failures: Vec<(TestDesc, Vec<u8>)>, pub not_failures: Vec<(TestDesc, Vec<u8>)>, + pub ignores: Vec<(TestDesc, Vec<u8>)>, pub time_failures: Vec<(TestDesc, Vec<u8>)>, pub options: Options, } @@ -76,6 +77,7 @@ impl ConsoleTestState { metrics: MetricMap::new(), failures: Vec::new(), not_failures: Vec::new(), + ignores: Vec::new(), time_failures: Vec::new(), options: opts.options, }) @@ -194,7 +196,10 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest) st.passed += 1; st.not_failures.push((test, stdout)); } - TestResult::TrIgnored => st.ignored += 1, + TestResult::TrIgnored => { + st.ignored += 1; + st.ignores.push((test, stdout)); + } TestResult::TrBench(bs) => { st.metrics.insert_metric( test.name.as_slice(), diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 0837ab16905..a431acfbc27 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -254,6 +254,15 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> { self.write_plain("\n\n")?; + // Custom handling of cases where there is only 1 test to execute and that test was ignored. + // We want to show more detailed information(why was the test ignored) for investigation purposes. + if self.total_test_count == 1 && state.ignores.len() == 1 { + let test_desc = &state.ignores[0].0; + if let Some(im) = test_desc.ignore_message { + self.write_plain(format!("test: {}, ignore_message: {}\n\n", test_desc.name, im))?; + } + } + Ok(success) } } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 3a0260f86cf..44776fb0a31 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -790,6 +790,7 @@ fn should_sort_failures_before_printing_them() { failures: vec![(test_b, Vec::new()), (test_a, Vec::new())], options: Options::new(), not_failures: Vec::new(), + ignores: Vec::new(), time_failures: Vec::new(), }; diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index be69f819c64..3856bb64fb3 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -16,12 +16,17 @@ fn main() { let mut build_lock; let _build_lock_guard; if cfg!(any(unix, windows)) { - build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock")))); + let path = config.out.join("lock"); + build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path))); _build_lock_guard = match build_lock.try_write() { Ok(lock) => lock, err => { - println!("warning: build directory locked, waiting for lock"); drop(err); + if let Some(pid) = get_lock_owner(&path) { + println!("warning: build directory locked by process {pid}, waiting for lock"); + } else { + println!("warning: build directory locked, waiting for lock"); + } t!(build_lock.write()) } }; @@ -98,3 +103,30 @@ fn check_version(config: &Config) -> Option<String> { Some(msg) } + +/// Get the PID of the process which took the write lock by +/// parsing `/proc/locks`. +#[cfg(target_os = "linux")] +fn get_lock_owner(f: &std::path::Path) -> Option<u64> { + use std::fs::File; + use std::io::{BufRead, BufReader}; + use std::os::unix::fs::MetadataExt; + + let lock_inode = std::fs::metadata(f).ok()?.ino(); + let lockfile = File::open("/proc/locks").ok()?; + BufReader::new(lockfile).lines().find_map(|line| { + // pid--vvvvvv vvvvvvv--- inode + // 21: FLOCK ADVISORY WRITE 359238 08:02:3719774 0 EOF + let line = line.ok()?; + let parts = line.split_whitespace().collect::<Vec<_>>(); + let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]); + let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?; + if inode == lock_inode { Some(pid) } else { None } + }) +} + +#[cfg(not(target_os = "linux"))] +fn get_lock_owner(_: &std::path::Path) -> Option<u64> { + // FIXME: Implement on other OS's + None +} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 9cf43fc7a21..abdd12127d3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -712,7 +712,7 @@ class RustBuild(object): def build_bootstrap(self, color): """Build bootstrap""" - print("Building rustbuild") + print("Building bootstrap") build_dir = os.path.join(self.build_dir, "bootstrap") if self.clean and os.path.exists(build_dir): shutil.rmtree(build_dir) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index b41d60d51a8..165502b0a41 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -65,6 +65,7 @@ pub struct Config { pub verbose: usize, pub submodules: Option<bool>, pub compiler_docs: bool, + pub library_docs_private_items: bool, pub docs_minification: bool, pub docs: bool, pub locked_deps: bool, @@ -606,6 +607,7 @@ define_config! { rustfmt: Option<PathBuf> = "rustfmt", docs: Option<bool> = "docs", compiler_docs: Option<bool> = "compiler-docs", + library_docs_private_items: Option<bool> = "library-docs-private-items", docs_minification: Option<bool> = "docs-minification", submodules: Option<bool> = "submodules", gdb: Option<String> = "gdb", @@ -965,6 +967,9 @@ impl Config { config.changelog_seen = toml.changelog_seen; let build = toml.build.unwrap_or_default(); + if let Some(file_build) = build.build { + config.build = TargetSelection::from_user(&file_build); + }; set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from))); // NOTE: Bootstrap spawns various commands with different working directories. @@ -1015,6 +1020,7 @@ impl Config { config.submodules = build.submodules; set(&mut config.low_priority, build.low_priority); set(&mut config.compiler_docs, build.compiler_docs); + set(&mut config.library_docs_private_items, build.library_docs_private_items); set(&mut config.docs_minification, build.docs_minification); set(&mut config.docs, build.docs); set(&mut config.locked_deps, build.locked_deps); diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index c30c9131745..681ecbfeb5b 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -19,6 +19,13 @@ fn download_ci_llvm() { assert_eq!(parse_llvm(""), if_available); assert_eq!(parse_llvm("rust.channel = \"dev\""), if_available); assert!(!parse_llvm("rust.channel = \"stable\"")); + assert!(parse_llvm("build.build = \"x86_64-unknown-linux-gnu\"")); + assert!(parse_llvm( + "llvm.assertions = true \r\n build.build = \"x86_64-unknown-linux-gnu\" \r\n llvm.download-ci-llvm = \"if-available\"" + )); + assert!(!parse_llvm( + "llvm.assertions = true \r\n build.build = \"aarch64-apple-darwin\" \r\n llvm.download-ci-llvm = \"if-available\"" + )); } // FIXME: add test for detecting `src` and `out` diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 2e4f753965d..02e35d2436e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -392,19 +392,29 @@ impl Step for Rustc { t!(fs::create_dir_all(image.join("bin"))); builder.cp_r(&src.join("bin"), &image.join("bin")); - builder.install(&builder.rustdoc(compiler), &image.join("bin"), 0o755); + if builder + .config + .tools + .as_ref() + .map_or(true, |tools| tools.iter().any(|tool| tool == "rustdoc")) + { + let rustdoc = builder.rustdoc(compiler); + builder.install(&rustdoc, &image.join("bin"), 0o755); + } - let ra_proc_macro_srv = builder - .ensure(tool::RustAnalyzerProcMacroSrv { + if let Some(ra_proc_macro_srv) = builder.ensure_if_default( + tool::RustAnalyzerProcMacroSrv { compiler: builder.compiler_for( compiler.stage, builder.config.build, compiler.host, ), target: compiler.host, - }) - .expect("rust-analyzer-proc-macro-server always builds"); - builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755); + }, + builder.kind, + ) { + builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755); + } let libdir_relative = builder.libdir_relative(compiler); @@ -952,7 +962,7 @@ impl Step for PlainSourceTarball { "Cargo.toml", "Cargo.lock", ]; - let src_dirs = ["src", "compiler", "library"]; + let src_dirs = ["src", "compiler", "library", "tests"]; copy_src_dirs(builder, &builder.src, &src_dirs, &[], &plain_dst_src); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9bad9046ecc..7f8aa2573dd 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -597,6 +597,9 @@ fn doc_std( .arg("--resource-suffix") .arg(&builder.version) .args(extra_args); + if builder.config.library_docs_private_items { + cargo.arg("--document-private-items").arg("--document-hidden-items"); + } builder.run(&mut cargo.into()); }; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d44b96cfb99..267aa3278d8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -110,7 +110,7 @@ use std::fs::{self, File}; use std::io; use std::io::ErrorKind; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::str; use build_helper::ci::CiEnv; @@ -203,7 +203,6 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] (None, "bootstrap", None), (Some(Mode::Rustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "parallel_compiler", None), - (Some(Mode::ToolRustc), "emulate_second_only_system", None), (Some(Mode::Codegen), "parallel_compiler", None), (Some(Mode::Std), "stdarch_intel_sde", None), (Some(Mode::Std), "no_fp_fmt_parse", None), @@ -214,18 +213,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] (Some(Mode::Std), "backtrace_in_libstd", None), /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx"])), - (Some(Mode::Std), "target_os", Some(&["watchos"])), - ( - Some(Mode::Std), - "target_arch", - Some(&["asmjs", "spirv", "nvptx", "nvptx64", "le32", "xtensa"]), - ), + // (Some(Mode::Std), "target_os", Some(&[])), + (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa"])), /* Extra names used by dependencies */ - // FIXME: Used by rustfmt is their test but is invalid (neither cargo nor bootstrap ever set - // this config) should probably by removed or use a allow attribute. - (Some(Mode::ToolRustc), "release", None), - // FIXME: Used by stdarch in their test, should use a allow attribute instead. - (Some(Mode::Std), "dont_compile_me", None), // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), (Some(Mode::ToolRustc), "no_btreemap_remove_entry", None), @@ -235,8 +225,12 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] // FIXME: Used by proc-macro2, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "span_locations", None), (Some(Mode::ToolRustc), "span_locations", None), - // Can be passed in RUSTFLAGS to prevent direct syscalls in rustix. - (None, "rustix_use_libc", None), + // FIXME: Used by rustix, but we should not be triggering on external dependencies. + (Some(Mode::Rustc), "rustix_use_libc", None), + (Some(Mode::ToolRustc), "rustix_use_libc", None), + // FIXME: Used by filetime, but we should not be triggering on external dependencies. + (Some(Mode::Rustc), "emulate_second_only_system", None), + (Some(Mode::ToolRustc), "emulate_second_only_system", None), ]; /// A structure representing a Rust compiler. @@ -662,12 +656,32 @@ impl Build { // Try passing `--progress` to start, then run git again without if that fails. let update = |progress: bool| { - let mut git = Command::new("git"); + // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, + // even though that has no relation to the upstream for the submodule. + let current_branch = { + let output = self + .config + .git() + .args(["symbolic-ref", "--short", "HEAD"]) + .stderr(Stdio::inherit()) + .output(); + let output = t!(output); + if output.status.success() { + Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) + } else { + None + } + }; + + let mut git = self.config.git(); + if let Some(branch) = current_branch { + git.arg("-c").arg(format!("branch.{branch}.remote=origin")); + } git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]); if progress { git.arg("--progress"); } - git.arg(relative_path).current_dir(&self.config.src); + git.arg(relative_path); git }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. @@ -1431,6 +1445,14 @@ impl Build { return Vec::new(); } + if !stamp.exists() { + eprintln!( + "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?", + stamp.display() + ); + crate::detail_exit(1); + } + let mut paths = Vec::new(); let contents = t!(fs::read(stamp), &stamp); // This is the method we use for extracting paths from the stamp file passed to us. See diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index cb5706ca0a6..3acc2d4b5c4 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -180,43 +180,40 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { // https://doc.rust-lang.org/rustc/platform-support.html#tier-1 let supported_platforms = [ // tier 1 - "aarch64-unknown-linux-gnu", - "i686-pc-windows-gnu", - "i686-pc-windows-msvc", - "i686-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-pc-windows-gnu", - "x86_64-pc-windows-msvc", + ("aarch64-unknown-linux-gnu", false), + ("i686-pc-windows-gnu", false), + ("i686-pc-windows-msvc", false), + ("i686-unknown-linux-gnu", false), + ("x86_64-unknown-linux-gnu", true), + ("x86_64-apple-darwin", true), + ("x86_64-pc-windows-gnu", true), + ("x86_64-pc-windows-msvc", true), // tier 2 with host tools - "aarch64-apple-darwin", - "aarch64-pc-windows-msvc", - "aarch64-unknown-linux-musl", - "arm-unknown-linux-gnueabi", - "arm-unknown-linux-gnueabihf", - "armv7-unknown-linux-gnueabihf", - "mips-unknown-linux-gnu", - "mips64-unknown-linux-gnuabi64", - "mips64el-unknown-linux-gnuabi64", - "mipsel-unknown-linux-gnu", - "powerpc-unknown-linux-gnu", - "powerpc64-unknown-linux-gnu", - "powerpc64le-unknown-linux-gnu", - "riscv64gc-unknown-linux-gnu", - "s390x-unknown-linux-gnu", - "x86_64-unknown-freebsd", - "x86_64-unknown-illumos", - "x86_64-unknown-linux-musl", - "x86_64-unknown-netbsd", + ("aarch64-apple-darwin", false), + ("aarch64-pc-windows-msvc", false), + ("aarch64-unknown-linux-musl", false), + ("arm-unknown-linux-gnueabi", false), + ("arm-unknown-linux-gnueabihf", false), + ("armv7-unknown-linux-gnueabihf", false), + ("mips-unknown-linux-gnu", false), + ("mips64-unknown-linux-gnuabi64", false), + ("mips64el-unknown-linux-gnuabi64", false), + ("mipsel-unknown-linux-gnu", false), + ("powerpc-unknown-linux-gnu", false), + ("powerpc64-unknown-linux-gnu", false), + ("powerpc64le-unknown-linux-gnu", false), + ("riscv64gc-unknown-linux-gnu", false), + ("s390x-unknown-linux-gnu", false), + ("x86_64-unknown-freebsd", false), + ("x86_64-unknown-illumos", false), + ("x86_64-unknown-linux-musl", false), + ("x86_64-unknown-netbsd", false), ]; - if !supported_platforms.contains(&&*config.build.triple) { - return false; - } - let triple = &*config.build.triple; - if (triple == "aarch64-unknown-linux-gnu" || triple.contains("i686")) && asserts { - // No alt builder for aarch64-unknown-linux-gnu today. - return false; + if !supported_platforms.contains(&(&*config.build.triple, asserts)) { + if asserts == true || !supported_platforms.contains(&(&*config.build.triple, true)) { + return false; + } } if CiEnv::is_ci() { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 9a2100c2fb7..ca5f500f93b 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -765,9 +765,15 @@ impl Step for RustAnalyzerProcMacroSrv { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; // Allow building `rust-analyzer-proc-macro-srv` both as part of the `rust-analyzer` and as a stand-alone tool. run.path("src/tools/rust-analyzer") .path("src/tools/rust-analyzer/crates/proc-macro-srv-cli") + .default_condition(builder.config.tools.as_ref().map_or(true, |tools| { + tools + .iter() + .any(|tool| tool == "rust-analyzer" || tool == "rust-analyzer-proc-macro-srv") + })) } fn make_run(run: RunConfig<'_>) { diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 6bdc88e18f5..5feba4e0605 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -81,7 +81,7 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.jemalloc \ --set rust.use-lld=true \ --set rust.lto=thin -ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \ +ENV SCRIPT python3 ../src/ci/stage-build.py python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ build-manifest bootstrap diff --git a/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh b/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh index c6d728eb80d..0b06f5e3623 100755 --- a/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh +++ b/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh @@ -9,11 +9,5 @@ git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git cd rust-toolstate python3 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \ "$(git log --format=%s -n1 HEAD)" "" "" -# Only check maintainers if this build is supposed to publish toolstate. -# Builds that are not supposed to publish don't have the access token. -if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then - TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python3 \ - "../../src/tools/publish_toolstate.py" -fi cd .. rm -rf rust-toolstate diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index a466777dd46..5e676a470a0 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -629,9 +629,7 @@ jobs: - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-gnu - --set llvm.allow-old-toolchain + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-1 # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). @@ -641,9 +639,7 @@ jobs: - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-gnu - --set llvm.allow-old-toolchain + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-2 # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). @@ -657,7 +653,6 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -670,7 +665,6 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -686,7 +680,7 @@ jobs: --enable-full-tools --enable-profiler --set rust.lto=thin - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl @@ -722,7 +716,6 @@ jobs: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -738,7 +731,6 @@ jobs: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 1685fbbbbba..7eccb9b8650 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -2,24 +2,6 @@ # If we need to download a custom MinGW, do so here and set the path # appropriately. # -# Here we also do a pretty heinous thing which is to mangle the MinGW -# installation we just downloaded. Currently, as of this writing, we're using -# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it -# appears to be the first version which contains a fix for #40546, builds -# randomly failing during LLVM due to ar.exe/ranlib.exe failures. -# -# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds -# to contain a regression in gdb (#40184). As a result if we were to use the -# gdb provided (7.11.1) then we would fail all debuginfo tests. -# -# In order to fix spurious failures (pretty high priority) we use 6.3.0. To -# avoid disabling gdb tests we download an *old* version of gdb, specifically -# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb -# with the 6.2.0 gdb to get tests passing. -# -# Note that we don't literally overwrite the gdb.exe binary because it appears -# to just use gdborig.exe, so that's the binary we deal with instead. -# # Otherwise install MinGW through `pacman` set -euo pipefail @@ -27,8 +9,8 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z" -MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z" +MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z" +MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z" if isWindows; then case "${CI_JOB_NAME}" in @@ -66,7 +48,6 @@ if isWindows; then curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null - curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe" ciCommandAddPath "$(pwd)/${mingw_dir}/bin" fi fi diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py new file mode 100644 index 00000000000..c373edfcf46 --- /dev/null +++ b/src/ci/stage-build.py @@ -0,0 +1,663 @@ +#!/usr/bin/env python3 +# ignore-tidy-linelength + +# Compatible with Python 3.6+ + +import contextlib +import getpass +import glob +import logging +import os +import pprint +import shutil +import subprocess +import sys +import time +import traceback +import urllib.request +from collections import OrderedDict +from io import StringIO +from pathlib import Path +from typing import Callable, Dict, Iterable, List, Optional, Union + +PGO_HOST = os.environ["PGO_HOST"] + +LOGGER = logging.getLogger("stage-build") + +LLVM_PGO_CRATES = [ + "syn-1.0.89", + "cargo-0.60.0", + "serde-1.0.136", + "ripgrep-13.0.0", + "regex-1.5.5", + "clap-3.1.6", + "hyper-0.14.18" +] + +RUSTC_PGO_CRATES = [ + "externs", + "ctfe-stress-5", + "cargo-0.60.0", + "token-stream-stress", + "match-stress", + "tuple-stress", + "diesel-1.4.8", + "bitmaps-3.1.0" +] + +LLVM_BOLT_CRATES = LLVM_PGO_CRATES + + +class Pipeline: + # Paths + def checkout_path(self) -> Path: + """ + The root checkout, where the source is located. + """ + raise NotImplementedError + + def downloaded_llvm_dir(self) -> Path: + """ + Directory where the host LLVM is located. + """ + raise NotImplementedError + + def build_root(self) -> Path: + """ + The main directory where the build occurs. + """ + raise NotImplementedError + + def build_artifacts(self) -> Path: + return self.build_root() / "build" / PGO_HOST + + def rustc_stage_0(self) -> Path: + return self.build_artifacts() / "stage0" / "bin" / "rustc" + + def cargo_stage_0(self) -> Path: + return self.build_artifacts() / "stage0" / "bin" / "cargo" + + def rustc_stage_2(self) -> Path: + return self.build_artifacts() / "stage2" / "bin" / "rustc" + + def opt_artifacts(self) -> Path: + raise NotImplementedError + + def llvm_profile_dir_root(self) -> Path: + return self.opt_artifacts() / "llvm-pgo" + + def llvm_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "llvm-pgo.profdata" + + def rustc_perf_dir(self) -> Path: + return self.opt_artifacts() / "rustc-perf" + + def build_rustc_perf(self): + raise NotImplementedError() + + def rustc_profile_dir_root(self) -> Path: + return self.opt_artifacts() / "rustc-pgo" + + def rustc_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "rustc-pgo.profdata" + + def rustc_profile_template_path(self) -> Path: + """ + The profile data is written into a single filepath that is being repeatedly merged when each + rustc invocation ends. Empirically, this can result in some profiling data being lost. That's + why we override the profile path to include the PID. This will produce many more profiling + files, but the resulting profile will produce a slightly faster rustc binary. + """ + return self.rustc_profile_dir_root() / "default_%m_%p.profraw" + + def supports_bolt(self) -> bool: + raise NotImplementedError + + def llvm_bolt_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "bolt.profdata" + + +class LinuxPipeline(Pipeline): + def checkout_path(self) -> Path: + return Path("/checkout") + + def downloaded_llvm_dir(self) -> Path: + return Path("/rustroot") + + def build_root(self) -> Path: + return self.checkout_path() / "obj" + + def opt_artifacts(self) -> Path: + return Path("/tmp/tmp-multistage/opt-artifacts") + + def build_rustc_perf(self): + # /tmp/rustc-perf comes from the Dockerfile + shutil.copytree("/tmp/rustc-perf", self.rustc_perf_dir()) + cmd(["chown", "-R", f"{getpass.getuser()}:", self.rustc_perf_dir()]) + + with change_cwd(self.rustc_perf_dir()): + cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( + RUSTC=str(self.rustc_stage_0()), + RUSTC_BOOTSTRAP="1" + )) + + def supports_bolt(self) -> bool: + return True + + +class WindowsPipeline(Pipeline): + def __init__(self): + self.checkout_dir = Path(os.getcwd()) + + def checkout_path(self) -> Path: + return self.checkout_dir + + def downloaded_llvm_dir(self) -> Path: + return self.checkout_path() / "citools" / "clang-rust" + + def build_root(self) -> Path: + return self.checkout_path() + + def opt_artifacts(self) -> Path: + return self.checkout_path() / "opt-artifacts" + + def rustc_stage_0(self) -> Path: + return super().rustc_stage_0().with_suffix(".exe") + + def cargo_stage_0(self) -> Path: + return super().cargo_stage_0().with_suffix(".exe") + + def rustc_stage_2(self) -> Path: + return super().rustc_stage_2().with_suffix(".exe") + + def build_rustc_perf(self): + # rustc-perf version from 2022-07-22 + perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c" + rustc_perf_zip_path = self.opt_artifacts() / "perf.zip" + + def download_rustc_perf(): + download_file( + f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip", + rustc_perf_zip_path + ) + with change_cwd(self.opt_artifacts()): + unpack_archive(rustc_perf_zip_path) + move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir()) + delete_file(rustc_perf_zip_path) + + retry_action(download_rustc_perf, "Download rustc-perf") + + with change_cwd(self.rustc_perf_dir()): + cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( + RUSTC=str(self.rustc_stage_0()), + RUSTC_BOOTSTRAP="1" + )) + + def rustc_profile_template_path(self) -> Path: + """ + On Windows, we don't have enough space to use separate files for each rustc invocation. + Therefore, we use a single file for the generated profiles. + """ + return self.rustc_profile_dir_root() / "default_%m.profraw" + + def supports_bolt(self) -> bool: + return False + + +class Timer: + def __init__(self): + # We want this dictionary to be ordered by insertion. + # We use `OrderedDict` for compatibility with older Python versions. + self.stages = OrderedDict() + + @contextlib.contextmanager + def stage(self, name: str): + assert name not in self.stages + + start = time.time() + exc = None + try: + LOGGER.info(f"Stage `{name}` starts") + yield + except BaseException as exception: + exc = exception + raise + finally: + end = time.time() + duration = end - start + self.stages[name] = duration + if exc is None: + LOGGER.info(f"Stage `{name}` ended: OK ({duration:.2f}s)") + else: + LOGGER.info(f"Stage `{name}` ended: FAIL ({duration:.2f}s)") + + def print_stats(self): + total_duration = sum(self.stages.values()) + + # 57 is the width of the whole table + divider = "-" * 57 + + with StringIO() as output: + print(divider, file=output) + for (name, duration) in self.stages.items(): + pct = (duration / total_duration) * 100 + name_str = f"{name}:" + print(f"{name_str:<34} {duration:>12.2f}s ({pct:>5.2f}%)", file=output) + + total_duration_label = "Total duration:" + print(f"{total_duration_label:<34} {total_duration:>12.2f}s", file=output) + print(divider, file=output, end="") + LOGGER.info(f"Timer results\n{output.getvalue()}") + + +@contextlib.contextmanager +def change_cwd(dir: Path): + """ + Temporarily change working directory to `dir`. + """ + cwd = os.getcwd() + LOGGER.debug(f"Changing working dir from `{cwd}` to `{dir}`") + os.chdir(dir) + try: + yield + finally: + LOGGER.debug(f"Reverting working dir to `{cwd}`") + os.chdir(cwd) + + +def move_path(src: Path, dst: Path): + LOGGER.info(f"Moving `{src}` to `{dst}`") + shutil.move(src, dst) + + +def delete_file(path: Path): + LOGGER.info(f"Deleting file `{path}`") + os.unlink(path) + + +def delete_directory(path: Path): + LOGGER.info(f"Deleting directory `{path}`") + shutil.rmtree(path) + + +def unpack_archive(archive: Path): + LOGGER.info(f"Unpacking archive `{archive}`") + shutil.unpack_archive(archive) + + +def download_file(src: str, target: Path): + LOGGER.info(f"Downloading `{src}` into `{target}`") + urllib.request.urlretrieve(src, str(target)) + + +def retry_action(action, name: str, max_fails: int = 5): + LOGGER.info(f"Attempting to perform action `{name}` with retry") + for iteration in range(max_fails): + LOGGER.info(f"Attempt {iteration + 1}/{max_fails}") + try: + action() + return + except: + LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}") + + raise Exception(f"Action `{name}` has failed after {max_fails} attempts") + + +def cmd( + args: List[Union[str, Path]], + env: Optional[Dict[str, str]] = None, + output_path: Optional[Path] = None +): + args = [str(arg) for arg in args] + + environment = os.environ.copy() + + cmd_str = "" + if env is not None: + environment.update(env) + cmd_str += " ".join(f"{k}={v}" for (k, v) in (env or {}).items()) + cmd_str += " " + cmd_str += " ".join(args) + if output_path is not None: + cmd_str += f" > {output_path}" + LOGGER.info(f"Executing `{cmd_str}`") + + if output_path is not None: + with open(output_path, "w") as f: + return subprocess.run( + args, + env=environment, + check=True, + stdout=f + ) + return subprocess.run(args, env=environment, check=True) + + +def run_compiler_benchmarks( + pipeline: Pipeline, + profiles: List[str], + scenarios: List[str], + crates: List[str], + env: Optional[Dict[str, str]] = None +): + env = env if env is not None else {} + + # Compile libcore, both in opt-level=0 and opt-level=3 + with change_cwd(pipeline.build_root()): + cmd([ + pipeline.rustc_stage_2(), + "--edition", "2021", + "--crate-type", "lib", + str(pipeline.checkout_path() / "library/core/src/lib.rs"), + "--out-dir", pipeline.opt_artifacts() + ], env=dict(RUSTC_BOOTSTRAP="1", **env)) + + cmd([ + pipeline.rustc_stage_2(), + "--edition", "2021", + "--crate-type", "lib", + "-Copt-level=3", + str(pipeline.checkout_path() / "library/core/src/lib.rs"), + "--out-dir", pipeline.opt_artifacts() + ], env=dict(RUSTC_BOOTSTRAP="1", **env)) + + # Run rustc-perf benchmarks + # Benchmark using profile_local with eprintln, which essentially just means + # don't actually benchmark -- just make sure we run rustc a bunch of times. + with change_cwd(pipeline.rustc_perf_dir()): + cmd([ + pipeline.cargo_stage_0(), + "run", + "-p", "collector", "--bin", "collector", "--", + "profile_local", "eprintln", + pipeline.rustc_stage_2(), + "--id", "Test", + "--cargo", pipeline.cargo_stage_0(), + "--profiles", ",".join(profiles), + "--scenarios", ",".join(scenarios), + "--include", ",".join(crates) + ], env=dict( + RUST_LOG="collector=debug", + RUSTC=str(pipeline.rustc_stage_0()), + RUSTC_BOOTSTRAP="1", + **env + )) + + +# https://stackoverflow.com/a/31631711/1107768 +def format_bytes(size: int) -> str: + """Return the given bytes as a human friendly KiB, MiB or GiB string.""" + KB = 1024 + MB = KB ** 2 # 1,048,576 + GB = KB ** 3 # 1,073,741,824 + TB = KB ** 4 # 1,099,511,627,776 + + if size < KB: + return f"{size} B" + elif KB <= size < MB: + return f"{size / KB:.2f} KiB" + elif MB <= size < GB: + return f"{size / MB:.2f} MiB" + elif GB <= size < TB: + return f"{size / GB:.2f} GiB" + else: + return str(size) + + +# https://stackoverflow.com/a/63307131/1107768 +def count_files(path: Path) -> int: + return sum(1 for p in path.rglob("*") if p.is_file()) + + +def count_files_with_prefix(path: Path) -> int: + return sum(1 for p in glob.glob(f"{path}*") if Path(p).is_file()) + + +# https://stackoverflow.com/a/55659577/1107768 +def get_path_size(path: Path) -> int: + if path.is_dir(): + return sum(p.stat().st_size for p in path.rglob("*")) + return path.stat().st_size + + +def get_path_prefix_size(path: Path) -> int: + """ + Get size of all files beginning with the prefix `path`. + Alternative to shell `du -sh <path>*`. + """ + return sum(Path(p).stat().st_size for p in glob.glob(f"{path}*")) + + +def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None) -> Iterable[Path]: + for file in os.listdir(directory): + path = directory / file + if filter is None or filter(path): + yield path + + +def build_rustc( + pipeline: Pipeline, + args: List[str], + env: Optional[Dict[str, str]] = None +): + arguments = [ + sys.executable, + pipeline.checkout_path() / "x.py", + "build", + "--target", PGO_HOST, + "--host", PGO_HOST, + "--stage", "2", + "library/std" + ] + args + cmd(arguments, env=env) + + +def create_pipeline() -> Pipeline: + if sys.platform == "linux": + return LinuxPipeline() + elif sys.platform in ("cygwin", "win32"): + return WindowsPipeline() + else: + raise Exception(f"Optimized build is not supported for platform {sys.platform}") + + +def gather_llvm_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with PGO instrumented LLVM") + run_compiler_benchmarks( + pipeline, + profiles=["Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_PGO_CRATES + ) + + profile_path = pipeline.llvm_profile_merged_file() + LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") + cmd([ + pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.llvm_profile_dir_root() + ]) + + LOGGER.info("LLVM PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.llvm_profile_dir_root()) + + +def gather_rustc_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with PGO instrumented rustc") + + # Here we're profiling the `rustc` frontend, so we also include `Check`. + # The benchmark set includes various stress tests that put the frontend under pressure. + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["All"], + crates=RUSTC_PGO_CRATES, + env=dict( + LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) + ) + ) + + profile_path = pipeline.rustc_profile_merged_file() + LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") + cmd([ + pipeline.build_artifacts() / "llvm" / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.rustc_profile_dir_root() + ]) + + LOGGER.info("Rustc PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.rustc_profile_dir_root()}: {format_bytes(get_path_size(pipeline.rustc_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.rustc_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.rustc_profile_dir_root()) + + +def gather_llvm_bolt_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with BOLT instrumented LLVM") + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_BOLT_CRATES + ) + + merged_profile_path = pipeline.llvm_bolt_profile_merged_file() + profile_files_path = Path("/tmp/prof.fdata") + LOGGER.info(f"Merging LLVM BOLT profiles to {merged_profile_path}") + + profile_files = sorted(glob.glob(f"{profile_files_path}*")) + cmd([ + "merge-fdata", + *profile_files, + ], output_path=merged_profile_path) + + LOGGER.info("LLVM BOLT statistics") + LOGGER.info(f"{merged_profile_path}: {format_bytes(get_path_size(merged_profile_path))}") + LOGGER.info( + f"{profile_files_path}: {format_bytes(get_path_prefix_size(profile_files_path))}") + LOGGER.info(f"Profile file count: {count_files_with_prefix(profile_files_path)}") + + +def clear_llvm_files(pipeline: Pipeline): + """ + Rustbuild currently doesn't support rebuilding LLVM when PGO options + change (or any other llvm-related options); so just clear out the relevant + directories ourselves. + """ + LOGGER.info("Clearing LLVM build files") + delete_directory(pipeline.build_artifacts() / "llvm") + delete_directory(pipeline.build_artifacts() / "lld") + + +def print_binary_sizes(pipeline: Pipeline): + bin_dir = pipeline.build_artifacts() / "stage2" / "bin" + binaries = get_files(bin_dir) + + lib_dir = pipeline.build_artifacts() / "stage2" / "lib" + libraries = get_files(lib_dir, lambda p: p.suffix == ".so") + + paths = sorted(binaries) + sorted(libraries) + with StringIO() as output: + for path in paths: + path_str = f"{path.name}:" + print(f"{path_str:<30}{format_bytes(path.stat().st_size):>14}", file=output) + LOGGER.info(f"Rustc binary size\n{output.getvalue()}") + + +def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]): + # Clear and prepare tmp directory + shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True) + os.makedirs(pipeline.opt_artifacts(), exist_ok=True) + + pipeline.build_rustc_perf() + + # Stage 1: Build rustc + PGO instrumented LLVM + with timer.stage("Build rustc (LLVM PGO)"): + build_rustc(pipeline, args=[ + "--llvm-profile-generate" + ], env=dict( + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p") + )) + + with timer.stage("Gather profiles (LLVM PGO)"): + gather_llvm_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--llvm-profile-use", + pipeline.llvm_profile_merged_file() + ] + + # Stage 2: Build PGO instrumented rustc + LLVM + with timer.stage("Build rustc (rustc PGO)"): + build_rustc(pipeline, args=[ + "--rust-profile-generate", + pipeline.rustc_profile_dir_root() + ]) + + with timer.stage("Gather profiles (rustc PGO)"): + gather_rustc_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--rust-profile-use", + pipeline.rustc_profile_merged_file() + ] + + # Stage 3: Build rustc + BOLT instrumented LLVM + if pipeline.supports_bolt(): + with timer.stage("Build rustc (LLVM BOLT)"): + build_rustc(pipeline, args=[ + "--llvm-profile-use", + pipeline.llvm_profile_merged_file(), + "--llvm-bolt-profile-generate", + ]) + with timer.stage("Gather profiles (LLVM BOLT)"): + gather_llvm_bolt_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--llvm-bolt-profile-use", + pipeline.llvm_bolt_profile_merged_file() + ] + + # Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM + with timer.stage("Final build"): + cmd(final_build_args) + + +if __name__ == "__main__": + logging.basicConfig( + level=logging.DEBUG, + format="%(name)s %(levelname)-4s: %(message)s", + ) + + LOGGER.info(f"Running multi-stage build using Python {sys.version}") + LOGGER.info(f"Environment values\n{pprint.pformat(dict(os.environ), indent=2)}") + + build_args = sys.argv[1:] + + timer = Timer() + pipeline = create_pipeline() + try: + execute_build_pipeline(timer, pipeline, build_args) + except BaseException as e: + LOGGER.error("The multi-stage build has failed") + raise e + finally: + timer.print_stats() + + print_binary_sizes(pipeline) diff --git a/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md b/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md new file mode 100644 index 00000000000..51c5fd69c63 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/tiny-const-eval-limit.md @@ -0,0 +1,6 @@ +# `tiny-const-eval-limit` + +-------------------- + +The `-Ztiny-const-eval-limit` compiler flag sets a tiny, non-configurable limit for const eval. +This flag should only be used by const eval tests in the rustc test suite. diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index 7a846d44ad6..ff17931115c 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -14,4 +14,4 @@ ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" cd "$ROOT_DIR" -./x test tidy +CARGOFLAGS="--locked" ./x test tidy diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index da300b89a4e..6592692d8b2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -251,7 +251,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean } fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> { - let sig = cx.tcx.fn_sig(did); + let sig = cx.tcx.fn_sig(did).subst_identity(); let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var { ty::BoundVariableKind::Region(ty::BrNamed(_, name)) if name != kw::UnderscoreLifetime => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 34a7068e5da..e2ced191a00 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -15,7 +15,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; use rustc_hir::PredicateOrigin; use rustc_hir_analysis::hir_ty_to_ty; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; @@ -116,7 +116,8 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } }); - Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx) + let kind = ModuleItem(Module { items, span }); + Item::from_def_id_and_parts(doc.def_id.to_def_id(), Some(doc.name), kind, cx) } fn clean_generic_bound<'tcx>( @@ -382,13 +383,10 @@ fn clean_middle_term<'tcx>( fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), - hir::Term::Const(c) => { - let def_id = cx.tcx.hir().local_def_id(c.hir_id); - Term::Constant(clean_middle_const( - ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, def_id)), - cx, - )) - } + hir::Term::Const(c) => Term::Constant(clean_middle_const( + ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, c.def_id)), + cx, + )), } } @@ -523,12 +521,11 @@ fn clean_generic_param<'tcx>( generics: Option<&hir::Generics<'tcx>>, param: &hir::GenericParam<'tcx>, ) -> GenericParamDef { - let did = cx.tcx.hir().local_def_id(param.hir_id); let (name, kind) = match param.kind { hir::GenericParamKind::Lifetime { .. } => { let outlives = if let Some(generics) = generics { generics - .outlives_for_param(did) + .outlives_for_param(param.def_id) .filter(|bp| !bp.in_where_clause) .flat_map(|bp| bp.bounds) .map(|bound| match bound { @@ -544,7 +541,7 @@ fn clean_generic_param<'tcx>( hir::GenericParamKind::Type { ref default, synthetic } => { let bounds = if let Some(generics) = generics { generics - .bounds_for_param(did) + .bounds_for_param(param.def_id) .filter(|bp| bp.origin != PredicateOrigin::WhereClause) .flat_map(|bp| bp.bounds) .filter_map(|x| clean_generic_bound(x, cx)) @@ -555,7 +552,7 @@ fn clean_generic_param<'tcx>( ( param.name.ident().name, GenericParamDefKind::Type { - did: did.to_def_id(), + did: param.def_id.to_def_id(), bounds, default: default.map(|t| clean_ty(t, cx)).map(Box::new), synthetic, @@ -565,12 +562,10 @@ fn clean_generic_param<'tcx>( hir::GenericParamKind::Const { ty, default } => ( param.name.ident().name, GenericParamDefKind::Const { - did: did.to_def_id(), + did: param.def_id.to_def_id(), ty: Box::new(clean_ty(ty, cx)), - default: default.map(|ct| { - let def_id = cx.tcx.hir().local_def_id(ct.hir_id); - Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string()) - }), + default: default + .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), }, ), }; @@ -1230,7 +1225,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } } ty::AssocKind::Fn => { - let sig = tcx.fn_sig(assoc_item.def_id); + let sig = tcx.fn_sig(assoc_item.def_id).subst_identity(); let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var { ty::BoundVariableKind::Region(ty::BrNamed(_, name)) @@ -1547,18 +1542,16 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(lt) = lifetime { - let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id); let cleaned = if !lt.is_anonymous() { clean_lifetime(lt, cx) } else { Lifetime::elided() }; - substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned)); + substs.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned)); } indices.lifetimes += 1; } hir::GenericParamKind::Type { ref default, .. } => { - let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); let mut j = 0; let type_ = generic_args.args.iter().find_map(|arg| match arg { hir::GenericArg::Type(ty) => { @@ -1571,17 +1564,14 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ty) = type_ { - substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); + substs.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); } else if let Some(default) = *default { - substs.insert( - ty_param_def_id.to_def_id(), - SubstParam::Type(clean_ty(default, cx)), - ); + substs + .insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx))); } indices.types += 1; } hir::GenericParamKind::Const { .. } => { - let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); let mut j = 0; let const_ = generic_args.args.iter().find_map(|arg| match arg { hir::GenericArg::Const(ct) => { @@ -1595,7 +1585,7 @@ fn maybe_expand_private_type_alias<'tcx>( }); if let Some(ct) = const_ { substs.insert( - const_param_def_id.to_def_id(), + param.def_id.to_def_id(), SubstParam::Constant(clean_const(ct, cx)), ); } @@ -1623,7 +1613,6 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let length = match length { hir::ArrayLen::Infer(_, _) => "_".to_string(), hir::ArrayLen::Body(anon_const) => { - let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); // NOTE(min_const_generics): We can't use `const_eval_poly` for constants // as we currently do not supply the parent generics to anonymous constants // but do allow `ConstKind::Param`. @@ -1631,8 +1620,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T // `const_eval_poly` tries to first substitute generic parameters which // results in an ICE while manually constructing the constant and using `eval` // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_anon_const(cx.tcx, def_id); - let param_env = cx.tcx.param_env(def_id); + let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id); + let param_env = cx.tcx.param_env(anon_const.def_id); print_const(cx, ct.eval(cx.tcx, param_env)) } }; @@ -1854,6 +1843,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Bound(..) => panic!("Bound"), ty::Placeholder(..) => panic!("Placeholder"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), + ty::GeneratorWitnessMIR(..) => panic!("GeneratorWitnessMIR"), ty::Infer(..) => panic!("Infer"), ty::Error(_) => rustc_errors::FatalError.raise(), } @@ -1928,8 +1918,7 @@ fn clean_middle_opaque_bounds<'tcx>( } pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item { - let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id(); - clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx) + clean_field_with_def_id(field.def_id.to_def_id(), field.ident.name, clean_ty(field.ty, cx), cx) } pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext<'tcx>) -> Item { @@ -1979,10 +1968,8 @@ fn clean_variant_data<'tcx>( disr_expr: &Option<hir::AnonConst>, cx: &mut DocContext<'tcx>, ) -> Variant { - let discriminant = disr_expr.map(|disr| Discriminant { - expr: Some(disr.body), - value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(), - }); + let discriminant = disr_expr + .map(|disr| Discriminant { expr: Some(disr.body), value: disr.def_id.to_def_id() }); let kind = match variant { hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct { @@ -2067,12 +2054,12 @@ struct OneLevelVisitor<'hir> { map: rustc_middle::hir::map::Map<'hir>, item: Option<&'hir hir::Item<'hir>>, looking_for: Ident, - target_hir_id: hir::HirId, + target_def_id: LocalDefId, } impl<'hir> OneLevelVisitor<'hir> { - fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self { - Self { map, item: None, looking_for: Ident::empty(), target_hir_id } + fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self { + Self { map, item: None, looking_for: Ident::empty(), target_def_id } } fn reset(&mut self, looking_for: Ident) { @@ -2092,7 +2079,7 @@ impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> { if self.item.is_none() && item.ident == self.looking_for && matches!(item.kind, hir::ItemKind::Use(_, _)) - || item.hir_id() == self.target_hir_id + || item.owner_id.def_id == self.target_def_id { self.item = Some(item); } @@ -2106,15 +2093,17 @@ impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> { fn get_all_import_attributes<'hir>( mut item: &hir::Item<'hir>, tcx: TyCtxt<'hir>, - target_hir_id: hir::HirId, + target_def_id: LocalDefId, attributes: &mut Vec<ast::Attribute>, ) { let hir_map = tcx.hir(); - let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id); + let mut visitor = OneLevelVisitor::new(hir_map, target_def_id); + let mut visited = FxHashSet::default(); // If the item is an import and has at least a path with two parts, we go into it. while let hir::ItemKind::Use(path, _) = item.kind && path.segments.len() > 1 && - let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res + let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res && + visited.insert(def_id) { if let Some(hir::Node::Item(parent_item)) = hir_map.get_if_local(def_id) { // We add the attributes from this import into the list. @@ -2138,7 +2127,7 @@ fn clean_maybe_renamed_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::Item<'tcx>, renamed: Option<Symbol>, - import_id: Option<hir::HirId>, + import_id: Option<LocalDefId>, ) -> Vec<Item> { use hir::ItemKind; @@ -2183,7 +2172,7 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), - ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx), + ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), // proc macros can have a name set by attributes ItemKind::Fn(ref sig, generics, body_id) => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) @@ -2218,10 +2207,10 @@ fn clean_maybe_renamed_item<'tcx>( let mut extra_attrs = Vec::new(); if let Some(hir::Node::Item(use_node)) = - import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id)) + import_id.and_then(|def_id| cx.tcx.hir().find_by_def_id(def_id)) { // We get all the various imports' attributes. - get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs); + get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs); } if !extra_attrs.is_empty() { @@ -2244,12 +2233,12 @@ fn clean_maybe_renamed_item<'tcx>( fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item { let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx)); - Item::from_hir_id_and_parts(variant.hir_id, Some(variant.ident.name), kind, cx) + Item::from_def_id_and_parts(variant.def_id.to_def_id(), Some(variant.ident.name), kind, cx) } fn clean_impl<'tcx>( impl_: &hir::Impl<'tcx>, - hir_id: hir::HirId, + def_id: LocalDefId, cx: &mut DocContext<'tcx>, ) -> Vec<Item> { let tcx = cx.tcx; @@ -2260,7 +2249,6 @@ fn clean_impl<'tcx>( .iter() .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx)) .collect::<Vec<_>>(); - let def_id = tcx.hir().local_def_id(hir_id); // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. @@ -2289,7 +2277,7 @@ fn clean_impl<'tcx>( ImplKind::Normal }, })); - Item::from_hir_id_and_parts(hir_id, None, kind, cx) + Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, cx) }; if let Some(type_alias) = type_alias { ret.push(make_item(trait_.clone(), type_alias, items.clone())); @@ -2510,8 +2498,8 @@ fn clean_maybe_renamed_foreign_item<'tcx>( hir::ForeignItemKind::Type => ForeignTypeItem, }; - Item::from_hir_id_and_parts( - item.hir_id(), + Item::from_def_id_and_parts( + item.owner_id.def_id.to_def_id(), Some(renamed.unwrap_or(item.ident.name)), kind, cx, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a020ccd53b8..85dd3881593 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -439,17 +439,6 @@ impl Item { self.attrs.doc_value() } - /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts - /// `hir_id` to a [`DefId`] - pub(crate) fn from_hir_id_and_parts( - hir_id: hir::HirId, - name: Option<Symbol>, - kind: ItemKind, - cx: &mut DocContext<'_>, - ) -> Item { - Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx) - } - pub(crate) fn from_def_id_and_parts( def_id: DefId, name: Option<Symbol>, @@ -665,7 +654,7 @@ impl Item { tcx: TyCtxt<'_>, asyncness: hir::IsAsync, ) -> hir::FnHeader { - let sig = tcx.fn_sig(def_id); + let sig = tcx.fn_sig(def_id).skip_binder(); let constness = if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() { hir::Constness::Const @@ -677,7 +666,7 @@ impl Item { let header = match *self.kind { ItemKind::ForeignFunctionItem(_) => { let def_id = self.item_id.as_def_id().unwrap(); - let abi = tcx.fn_sig(def_id).abi(); + let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { unsafety: if abi == Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap()) @@ -2416,10 +2405,7 @@ impl ConstantKind { pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool { match *self { - ConstantKind::TyConst { .. } => false, - ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| { - is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id)) - }), + ConstantKind::TyConst { .. } | ConstantKind::Extern { .. } => false, ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { is_literal_expr(tcx, body.hir_id) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a12f764fa8e..ca3a70c7236 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -29,11 +29,6 @@ mod tests; pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { let module = crate::visit_ast::RustdocVisitor::new(cx).visit(); - for &cnum in cx.tcx.crates(()) { - // Analyze doc-reachability for extern items - crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id()); - } - // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. let mut module = clean_doc_module(&module, cx); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 56b40d8c66b..2c514a0c826 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -509,7 +509,7 @@ impl Options { // these values up both in `dataset` and in the storage API, so it needs to be able // to convert the names back and forth. Despite doing this kebab-case to // StudlyCaps transformation automatically, the JS DOM API does not provide a - // mechanism for doing the just transformation on a string. So we want to avoid + // mechanism for doing just the transformation on a string. So we want to avoid // the StudlyCaps representation in the `dataset` property. // // We solve this by replacing all the `-`s with `_`s. We do that here, when we diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 10b606f425e..0ce43f7db8e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -41,6 +41,7 @@ pub(crate) struct ResolverCaches { pub(crate) traits_in_scope: DefIdMap<Vec<TraitCandidate>>, pub(crate) all_trait_impls: Option<Vec<DefId>>, pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>, + pub(crate) extern_doc_reachable: DefIdSet, } pub(crate) struct DocContext<'tcx> { @@ -363,6 +364,10 @@ pub(crate) fn run_global_ctxt( show_coverage, }; + ctxt.cache + .effective_visibilities + .init(mem::take(&mut ctxt.resolver_caches.extern_doc_reachable)); + // Small hack to force the Sized trait to be present. // // Note that in case of `#![no_core]`, the trait is not available. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c1a652c75f4..37a1005cba1 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -2,10 +2,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError}; -use rustc_hir as hir; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::intravisit; -use rustc_hir::{HirId, CRATE_HIR_ID}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID}; use rustc_interface::interface; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; @@ -140,7 +138,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { }; hir_collector.visit_testable( "".to_string(), - CRATE_HIR_ID, + CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| tcx.hir().walk_toplevel_module(this), ); @@ -1214,11 +1212,11 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { fn visit_testable<F: FnOnce(&mut Self)>( &mut self, name: String, - hir_id: HirId, + def_id: LocalDefId, sp: Span, nested: F, ) { - let ast_attrs = self.tcx.hir().attrs(hir_id); + let ast_attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { if !cfg.matches(&self.sess.parse_sess, Some(self.tcx.features())) { return; @@ -1247,7 +1245,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { self.collector.enable_per_target_ignores, Some(&crate::html::markdown::ExtraInfo::new( self.tcx, - hir_id, + def_id.to_def_id(), span_of_attrs(&attrs).unwrap_or(sp), )), ); @@ -1276,37 +1274,37 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> _ => item.ident.to_string(), }; - self.visit_testable(name, item.hir_id(), item.span, |this| { + self.visit_testable(name, item.owner_id.def_id, item.span, |this| { intravisit::walk_item(this, item); }); } fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) { - self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| { + self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { intravisit::walk_trait_item(this, item); }); } fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) { - self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| { + self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { intravisit::walk_impl_item(this, item); }); } fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) { - self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| { + self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { intravisit::walk_foreign_item(this, item); }); } fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) { - self.visit_testable(v.ident.to_string(), v.hir_id, v.span, |this| { + self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| { intravisit::walk_variant(this, v); }); } fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) { - self.visit_testable(f.ident.to_string(), f.hir_id, f.span, |this| { + self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| { intravisit::walk_field_def(this, f); }); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d3dc4065dfc..33404a76835 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1064,14 +1064,8 @@ fn fmt_type<'cx>( fmt_type(ty, f, use_absolute, cx)?; write!(f, ")") } - clean::Generic(..) => { - primitive_link( - f, - PrimitiveType::Reference, - &format!("{}{}{}", amp, lt, m), - cx, - )?; - fmt_type(ty, f, use_absolute, cx) + clean::Generic(name) => { + primitive_link(f, PrimitiveType::Reference, &format!("{amp}{lt}{m}{name}"), cx) } _ => { write!(f, "{}{}{}", amp, lt, m)?; diff --git a/src/librustdoc/html/length_limit.rs b/src/librustdoc/html/length_limit.rs index bbdc91c8d2e..4c8db2c6784 100644 --- a/src/librustdoc/html/length_limit.rs +++ b/src/librustdoc/html/length_limit.rs @@ -61,14 +61,14 @@ impl HtmlWithLimit { /// and returns [`ControlFlow::Break`]. pub(super) fn push(&mut self, text: &str) -> ControlFlow<(), ()> { if self.len + text.len() > self.limit { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } self.flush_queue(); write!(self.buf, "{}", Escape(text)).unwrap(); self.len += text.len(); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Open an HTML tag. diff --git a/src/librustdoc/html/length_limit/tests.rs b/src/librustdoc/html/length_limit/tests.rs index 2d02b8a16da..2185c034890 100644 --- a/src/librustdoc/html/length_limit/tests.rs +++ b/src/librustdoc/html/length_limit/tests.rs @@ -83,7 +83,7 @@ fn past_the_limit() { buf.push("word#")?; buf.push(&n.to_string())?; buf.close_tag(); - ControlFlow::CONTINUE + ControlFlow::Continue(()) }); buf.close_tag(); assert_eq!( diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4ff67fe1551..00e3f859bfc 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,7 +27,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::HirId; use rustc_middle::ty::TyCtxt; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; @@ -296,7 +295,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; // These characters don't need to be escaped in a URI. - // FIXME: use a library function for percent encoding. + // See https://url.spec.whatwg.org/#query-percent-encode-set + // and https://url.spec.whatwg.org/#urlencoded-parsing + // and https://url.spec.whatwg.org/#url-code-points fn dont_escape(c: u8) -> bool { (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') @@ -304,17 +305,32 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { || c == b'-' || c == b'_' || c == b'.' + || c == b',' || c == b'~' || c == b'!' || c == b'\'' || c == b'(' || c == b')' || c == b'*' + || c == b'/' + || c == b';' + || c == b':' + || c == b'?' + // As described in urlencoded-parsing, the + // first `=` is the one that separates key from + // value. Following `=`s are part of the value. + || c == b'=' } let mut test_escaped = String::new(); for b in test.bytes() { if dont_escape(b) { test_escaped.push(char::from(b)); + } else if b == b' ' { + // URL queries are decoded with + replaced with SP + test_escaped.push('+'); + } else if b == b'%' { + test_escaped.push('%'); + test_escaped.push('%'); } else { write!(test_escaped, "%{:02X}", b).unwrap(); } @@ -784,45 +800,26 @@ pub(crate) fn find_testable_code<T: doctest::Tester>( } pub(crate) struct ExtraInfo<'tcx> { - id: ExtraInfoId, + def_id: DefId, sp: Span, tcx: TyCtxt<'tcx>, } -enum ExtraInfoId { - Hir(HirId), - Def(DefId), -} - impl<'tcx> ExtraInfo<'tcx> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> { - ExtraInfo { id: ExtraInfoId::Hir(hir_id), sp, tcx } - } - - pub(crate) fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> { - ExtraInfo { id: ExtraInfoId::Def(did), sp, tcx } + pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: DefId, sp: Span) -> ExtraInfo<'tcx> { + ExtraInfo { def_id, sp, tcx } } fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) { - let hir_id = match self.id { - ExtraInfoId::Hir(hir_id) => hir_id, - ExtraInfoId::Def(item_did) => { - match item_did.as_local() { - Some(item_did) => self.tcx.hir().local_def_id_to_hir_id(item_did), - None => { - // If non-local, no need to check anything. - return; - } - } - } - }; - self.tcx.struct_span_lint_hir( - crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - hir_id, - self.sp, - msg, - |lint| lint.help(help), - ); + if let Some(def_id) = self.def_id.as_local() { + self.tcx.struct_span_lint_hir( + crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, + self.tcx.hir().local_def_id_to_hir_id(def_id), + self.sp, + msg, + |lint| lint.help(help), + ); + } } } @@ -1191,18 +1188,18 @@ fn markdown_summary_with_limit( Event::Start(tag) => match tag { Tag::Emphasis => buf.open_tag("em"), Tag::Strong => buf.open_tag("strong"), - Tag::CodeBlock(..) => return ControlFlow::BREAK, + Tag::CodeBlock(..) => return ControlFlow::Break(()), _ => {} }, Event::End(tag) => match tag { Tag::Emphasis | Tag::Strong => buf.close_tag(), - Tag::Paragraph | Tag::Heading(..) => return ControlFlow::BREAK, + Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()), _ => {} }, Event::HardBreak | Event::SoftBreak => buf.push(" ")?, _ => {} }; - ControlFlow::CONTINUE + ControlFlow::Continue(()) }); (buf.finish(), stopped_early) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d644293d3ef..be6de231854 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1528,11 +1528,7 @@ fn render_impl( }) }) .map(|item| format!("{}.{}", item.type_(), name)); - write!( - w, - "<section id=\"{}\" class=\"{}{} has-srclink\">", - id, item_type, in_trait_class, - ); + write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,); render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. @@ -1554,11 +1550,7 @@ fn render_impl( kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "<section id=\"{}\" class=\"{}{} has-srclink\">", - id, item_type, in_trait_class - ); + write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class); render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. @@ -1606,11 +1598,7 @@ fn render_impl( clean::AssocTypeItem(tydef, _bounds) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "<section id=\"{}\" class=\"{}{} has-srclink\">", - id, item_type, in_trait_class - ); + write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class); if trait_.is_some() { // Anchors are only used on trait impls. write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id); @@ -1844,7 +1832,7 @@ pub(crate) fn render_impl_summary( } else { format!(" data-aliases=\"{}\"", aliases.join(",")) }; - write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases); + write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases); render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id); write!(w, "<h3 class=\"code-header\">"); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f824c9e3ad2..b0288d55c25 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -391,7 +391,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: }; write!( w, - "<div class=\"item-left {stab}{add}import-item\"{id}>\ + "<div class=\"item-left{add}{stab}\"{id}>\ <code>{vis}{imp}</code>\ </div>\ {stab_tags_before}{stab_tags}{stab_tags_after}", @@ -437,7 +437,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: }; write!( w, - "<div class=\"item-left {stab}{add}module-item\">\ + "<div class=\"item-left{add}{stab}\">\ <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\ {visibility_emoji}\ {unsafety_flag}\ @@ -452,7 +452,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: stab = stab.unwrap_or_default(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), - title = [full_path(cx, myitem), myitem.type_().to_string()] + title = [myitem.type_().to_string(), full_path(cx, myitem)] .iter() .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None }) .collect::<Vec<_>>() @@ -735,7 +735,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); } - write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id); + write!(w, "<section id=\"{}\" class=\"method\">", id); render_rightside(w, cx, m, t, RenderMode::Normal); write!(w, "<h4 class=\"code-header\">"); render_assoc_item( diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 424bbb0ec42..8699508e439 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -533,7 +533,7 @@ ul.block, .block li { .rustdoc .example-wrap > pre { margin: 0; flex-grow: 1; - overflow-x: auto; + overflow: auto hidden; } .rustdoc .example-wrap > pre.example-line-numbers, @@ -977,8 +977,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ 0 -1px 0 black; } -.module-item.unstable, -.import-item.unstable { +.item-left.unstable { opacity: 0.65; } diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 4e9803fe236..c28cefebc8b 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -3,8 +3,7 @@ position: relative; } -.setting-line .radio-line input, -.setting-line .settings-toggle input { +.setting-radio input, .setting-check input { margin-right: 0.3em; height: 1.2rem; width: 1.2rem; @@ -14,21 +13,20 @@ -webkit-appearance: none; cursor: pointer; } -.setting-line .radio-line input { +.setting-radio input { border-radius: 50%; } -.setting-line .settings-toggle input:checked { +.setting-check input:checked { content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\ <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\ <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>'); } -.setting-line .radio-line input + span, -.setting-line .settings-toggle span { +.setting-radio span, .setting-check span { padding-bottom: 1px; } -.radio-line .choice { +.setting-radio { margin-top: 0.1em; margin-bottom: 0.1em; min-width: 3.8em; @@ -37,11 +35,11 @@ align-items: center; cursor: pointer; } -.radio-line .choice + .choice { +.setting-radio + .setting-radio { margin-left: 0.5em; } -.settings-toggle { +.setting-check { position: relative; width: 100%; margin-right: 20px; @@ -50,23 +48,21 @@ cursor: pointer; } -.setting-line .radio-line input:checked { +.setting-radio input:checked { box-shadow: inset 0 0 0 3px var(--main-background-color); background-color: var(--settings-input-color); } -.setting-line .settings-toggle input:checked { +.setting-check input:checked { background-color: var(--settings-input-color); } -.setting-line .radio-line input:focus, -.setting-line .settings-toggle input:focus { +.setting-radio input:focus, .setting-check input:focus { box-shadow: 0 0 1px 1px var(--settings-input-color); } /* In here we combine both `:focus` and `:checked` properties. */ -.setting-line .radio-line input:checked:focus { +.setting-radio input:checked:focus { box-shadow: inset 0 0 0 3px var(--main-background-color), 0 0 2px 2px var(--settings-input-color); } -.setting-line .radio-line input:hover, -.setting-line .settings-toggle input:hover { +.setting-radio input:hover, .setting-check input:hover { border-color: var(--settings-input-color) !important; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 604ab147f6a..b9ad8ef70e9 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1142,7 +1142,11 @@ function loadCss(cssUrl) { (function() { let reset_button_timeout = null; - window.copy_path = but => { + const but = document.getElementById("copy-path"); + if (!but) { + return; + } + but.onclick = () => { const parent = but.parentElement; const path = []; diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 84df1b7d391..1cd552e7f25 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ +/* global getSettingValue, getVirtualKey, updateLocalStorage, updateTheme */ /* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ /* global MAIN_ID, getVar, getSettingsButton */ @@ -19,7 +19,7 @@ case "theme": case "preferred-dark-theme": case "preferred-light-theme": - updateSystemTheme(); + updateTheme(); updateLightAndDark(); break; case "line-numbers": @@ -48,13 +48,13 @@ } function showLightAndDark() { - removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden"); - removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden"); + removeClass(document.getElementById("preferred-light-theme"), "hidden"); + removeClass(document.getElementById("preferred-dark-theme"), "hidden"); } function hideLightAndDark() { - addClass(document.getElementById("preferred-light-theme").parentElement, "hidden"); - addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden"); + addClass(document.getElementById("preferred-light-theme"), "hidden"); + addClass(document.getElementById("preferred-dark-theme"), "hidden"); } function updateLightAndDark() { @@ -80,17 +80,6 @@ toggle.onkeyup = handleKey; toggle.onkeyrelease = handleKey; }); - onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), elem => { - const select = elem.getElementsByTagName("select")[0]; - const settingId = select.id; - const settingValue = getSettingValue(settingId); - if (settingValue !== null) { - select.value = settingValue; - } - select.onchange = function() { - changeSetting(this.id, this.value); - }; - }); onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => { const settingId = elem.name; let settingValue = getSettingValue(settingId); @@ -127,38 +116,40 @@ let output = ""; for (const setting of settings) { - output += "<div class=\"setting-line\">"; const js_data_name = setting["js_name"]; const setting_name = setting["name"]; if (setting["options"] !== undefined) { // This is a select setting. output += `\ -<div class="radio-line" id="${js_data_name}"> - <div class="setting-name">${setting_name}</div> -<div class="choices">`; +<div class="setting-line" id="${js_data_name}"> + <div class="setting-radio-name">${setting_name}</div> + <div class="setting-radio-choices">`; onEach(setting["options"], option => { const checked = option === setting["default"] ? " checked" : ""; const full = `${js_data_name}-${option.replace(/ /g,"-")}`; output += `\ -<label for="${full}" class="choice"> - <input type="radio" name="${js_data_name}" - id="${full}" value="${option}"${checked}> - <span>${option}</span> -</label>`; + <label for="${full}" class="setting-radio"> + <input type="radio" name="${js_data_name}" + id="${full}" value="${option}"${checked}> + <span>${option}</span> + </label>`; }); - output += "</div></div>"; + output += `\ + </div> +</div>`; } else { // This is a checkbox toggle. const checked = setting["default"] === true ? " checked" : ""; output += `\ -<label class="settings-toggle">\ - <input type="checkbox" id="${js_data_name}"${checked}>\ - <span class="label">${setting_name}</span>\ -</label>`; +<div class="setting-line">\ + <label class="setting-check">\ + <input type="checkbox" id="${js_data_name}"${checked}>\ + <span>${setting_name}</span>\ + </label>\ +</div>`; } - output += "</div>"; } return output; } diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index db2db83ca63..8836d1b2e46 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -153,79 +153,74 @@ function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) { } } -// This function is called from "main.js". -// eslint-disable-next-line no-unused-vars -function useSystemTheme(value) { - if (value === undefined) { - value = true; - } - - updateLocalStorage("use-system-theme", value); - - // update the toggle if we're on the settings page - const toggle = document.getElementById("use-system-theme"); - if (toggle && toggle instanceof HTMLInputElement) { - toggle.checked = value; - } -} - -const updateSystemTheme = (function() { - if (!window.matchMedia) { - // fallback to the CSS computed value - return () => { - const cssTheme = getComputedStyle(document.documentElement) - .getPropertyValue("content"); - - switchTheme( - window.currentTheme, - window.mainTheme, - JSON.parse(cssTheme) || "light", - true - ); +const updateTheme = (function() { + /** + * Update the current theme to match whatever the current combination of + * * the preference for using the system theme + * (if this is the case, the value of preferred-light-theme, if the + * system theme is light, otherwise if dark, the value of + * preferred-dark-theme.) + * * the preferred theme + * … dictates that it should be. + */ + function updateTheme() { + const use = (theme, saveTheme) => { + switchTheme(window.currentTheme, window.mainTheme, theme, saveTheme); }; - } - - // only listen to (prefers-color-scheme: dark) because light is the default - const mql = window.matchMedia("(prefers-color-scheme: dark)"); - function handlePreferenceChange(mql) { - const use = theme => { - switchTheme(window.currentTheme, window.mainTheme, theme, true); - }; // maybe the user has disabled the setting in the meantime! if (getSettingValue("use-system-theme") !== "false") { const lightTheme = getSettingValue("preferred-light-theme") || "light"; const darkTheme = getSettingValue("preferred-dark-theme") || "dark"; - if (mql.matches) { - use(darkTheme); + if (isDarkMode()) { + use(darkTheme, true); } else { // prefers a light theme, or has no preference - use(lightTheme); + use(lightTheme, true); } // note: we save the theme so that it doesn't suddenly change when // the user disables "use-system-theme" and reloads the page or // navigates to another page } else { - use(getSettingValue("theme")); + use(getSettingValue("theme"), false); } } - mql.addListener(handlePreferenceChange); + // This is always updated below to a function () => bool. + let isDarkMode; - return () => { - handlePreferenceChange(mql); - }; -})(); + // Determine the function for isDarkMode, and if we have + // `window.matchMedia`, set up an event listener on the preferred color + // scheme. + // + // Otherwise, fall back to the prefers-color-scheme value CSS captured in + // the "content" property. + if (window.matchMedia) { + // only listen to (prefers-color-scheme: dark) because light is the default + const mql = window.matchMedia("(prefers-color-scheme: dark)"); -function switchToSavedTheme() { - switchTheme( - window.currentTheme, - window.mainTheme, - getSettingValue("theme") || "light", - false - ); -} + isDarkMode = () => mql.matches; + + if (mql.addEventListener) { + mql.addEventListener("change", updateTheme); + } else { + // This is deprecated, see: + // https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener + mql.addListener(updateTheme); + } + } else { + // fallback to the CSS computed value + const cssContent = getComputedStyle(document.documentElement) + .getPropertyValue("content"); + // (Note: the double-quotes come from that this is a CSS value, which + // might be a length, string, etc.) + const cssColorScheme = cssContent || "\"light\""; + isDarkMode = () => (cssColorScheme === "\"dark\""); + } + + return updateTheme; +})(); if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { // update the preferred dark theme if the user is already using a dark theme @@ -235,13 +230,10 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { && darkThemes.indexOf(localStoredTheme) >= 0) { updateLocalStorage("preferred-dark-theme", localStoredTheme); } - - // call the function to initialize the theme at least once! - updateSystemTheme(); -} else { - switchToSavedTheme(); } +updateTheme(); + if (getSettingValue("source-sidebar-show") === "true") { // At this point in page load, `document.body` is not available yet. // Set a class on the `<html>` element instead. @@ -259,6 +251,6 @@ if (getSettingValue("source-sidebar-show") === "true") { // specifically when talking to a remote website with no caching. window.addEventListener("pageshow", ev => { if (ev.persisted) { - setTimeout(switchToSavedTheme, 0); + setTimeout(updateTheme, 0); } }); diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index ee2880bf6d1..3a1867b7feb 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -6,7 +6,7 @@ <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr> {%- endfor -%} <a class="{{item_type}}" href="#">{{name}}</a> {#- -#} - <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#} + <button id="copy-path" title="Copy item path to clipboard"> {#- -#} <img src="{{static_root_path|safe}}{{clipboard_svg}}" {# -#} width="19" height="18" {# -#} alt="Copy item path"> {#- -#} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 86454e1f2eb..64108c88285 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -6,7 +6,6 @@ #![feature(array_methods)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(is_terminal)] #![feature(let_chains)] @@ -815,7 +814,7 @@ fn main_args(at_args: &[String]) -> MainResult { sess.fatal("Compilation failed, aborting rustdoc"); } - let global_ctxt = abort_on_err(queries.global_ctxt(), sess); + let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess); global_ctxt.enter(|tcx| { let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 02b22789608..0b22f943dab 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -216,13 +216,7 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> { ); let has_doc_example = tests.found_tests != 0; - // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` - // would presumably panic if a fake `DefIndex` were passed. - let hir_id = self - .ctx - .tcx - .hir() - .local_def_id_to_hir_id(i.item_id.expect_def_id().expect_local()); + let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap(); let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id); // In case we have: diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 6aa2dda980c..f3961d5017e 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -14,8 +14,8 @@ use crate::visit::DocVisitor; use crate::visit_ast::inherits_doc_hidden; use rustc_hir as hir; use rustc_middle::lint::LintLevelSource; +use rustc_middle::ty::DefIdTree; use rustc_session::lint; -use rustc_span::symbol::sym; pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass { name: "check_doc_test_visibility", @@ -79,11 +79,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` // would presumably panic if a fake `DefIndex` were passed. - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.item_id.expect_def_id().expect_local()); + let def_id = item.item_id.expect_def_id().expect_local(); // check if parent is trait impl - if let Some(parent_hir_id) = cx.tcx.hir().opt_parent_id(hir_id) { - if let Some(parent_node) = cx.tcx.hir().find(parent_hir_id) { + if let Some(parent_def_id) = cx.tcx.opt_local_parent(def_id) { + if let Some(parent_node) = cx.tcx.hir().find_by_def_id(parent_def_id) { if matches!( parent_node, hir::Node::Item(hir::Item { @@ -96,13 +96,16 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - } } - if cx.tcx.hir().attrs(hir_id).lists(sym::doc).has_word(sym::hidden) - || inherits_doc_hidden(cx.tcx, hir_id) - || cx.tcx.hir().span(hir_id).in_derive_expansion() + if cx.tcx.is_doc_hidden(def_id.to_def_id()) + || inherits_doc_hidden(cx.tcx, def_id) + || cx.tcx.def_span(def_id.to_def_id()).in_derive_expansion() { return false; } - let (level, source) = cx.tcx.lint_level_at_node(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id); + let (level, source) = cx.tcx.lint_level_at_node( + crate::lint::MISSING_DOC_CODE_EXAMPLES, + cx.tcx.hir().local_def_id_to_hir_id(def_id), + ); level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 075951312a6..8435972bb11 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -542,6 +542,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Dynamic(..) | ty::Param(_) | ty::Bound(..) @@ -1194,14 +1195,9 @@ impl LinkCollector<'_, '_> { } // item can be non-local e.g. when using #[doc(primitive = "pointer")] - if let Some((src_id, dst_id)) = id - .as_local() - // The `expect_def_id()` should be okay because `local_def_id_to_hir_id` - // would presumably panic if a fake `DefIndex` were passed. - .and_then(|dst_id| { - item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) - }) - { + if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| { + item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) + }) { if self.cx.tcx.effective_visibilities(()).is_exported(src_id) && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id) { diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 42677bd8497..f690c49005d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -2,6 +2,7 @@ use crate::clean::Attributes; use crate::core::ResolverCaches; use crate::passes::collect_intra_doc_links::preprocessed_markdown_links; use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink}; +use crate::visit_lib::early_lib_embargo_visit_item; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, ItemKind}; @@ -34,6 +35,8 @@ pub(crate) fn early_resolve_intra_doc_links( traits_in_scope: Default::default(), all_trait_impls: Default::default(), all_macro_rules: Default::default(), + extern_doc_reachable: Default::default(), + local_doc_reachable: Default::default(), document_private_items, }; @@ -61,6 +64,7 @@ pub(crate) fn early_resolve_intra_doc_links( traits_in_scope: link_resolver.traits_in_scope, all_trait_impls: Some(link_resolver.all_trait_impls), all_macro_rules: link_resolver.all_macro_rules, + extern_doc_reachable: link_resolver.extern_doc_reachable, } } @@ -77,6 +81,15 @@ struct EarlyDocLinkResolver<'r, 'ra> { traits_in_scope: DefIdMap<Vec<TraitCandidate>>, all_trait_impls: Vec<DefId>, all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>, + /// This set is used as a seed for `effective_visibilities`, which are then extended by some + /// more items using `lib_embargo_visit_item` during doc inlining. + extern_doc_reachable: DefIdSet, + /// This is an easily identifiable superset of items added to `effective_visibilities` + /// using `lib_embargo_visit_item` during doc inlining. + /// The union of `(extern,local)_doc_reachable` is therefore a superset of + /// `effective_visibilities` and can be used for pruning extern impls here + /// in early doc link resolution. + local_doc_reachable: DefIdSet, document_private_items: bool, } @@ -105,6 +118,10 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { } } + fn is_doc_reachable(&self, def_id: DefId) -> bool { + self.extern_doc_reachable.contains(&def_id) || self.local_doc_reachable.contains(&def_id) + } + /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass. /// That pass filters impls using type-based information, but we don't yet have such /// information here, so we just conservatively calculate traits in scope for *all* modules @@ -114,6 +131,14 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { let mut start_cnum = 0; loop { let crates = Vec::from_iter(self.resolver.cstore().crates_untracked()); + for cnum in &crates[start_cnum..] { + early_lib_embargo_visit_item( + self.resolver, + &mut self.extern_doc_reachable, + cnum.as_def_id(), + true, + ); + } for &cnum in &crates[start_cnum..] { let all_trait_impls = Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum)); @@ -127,28 +152,26 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { // privacy, private traits and impls from other crates are never documented in // the current crate, and links in their doc comments are not resolved. for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls { - if self.resolver.cstore().visibility_untracked(trait_def_id).is_public() - && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| { - self.resolver.cstore().visibility_untracked(ty_def_id).is_public() - }) + if self.is_doc_reachable(trait_def_id) + && simplified_self_ty + .and_then(|ty| ty.def()) + .map_or(true, |ty_def_id| self.is_doc_reachable(ty_def_id)) { if self.visited_mods.insert(trait_def_id) { self.resolve_doc_links_extern_impl(trait_def_id, false); } self.resolve_doc_links_extern_impl(impl_def_id, false); } + self.all_trait_impls.push(impl_def_id); } for (ty_def_id, impl_def_id) in all_inherent_impls { - if self.resolver.cstore().visibility_untracked(ty_def_id).is_public() { + if self.is_doc_reachable(ty_def_id) { self.resolve_doc_links_extern_impl(impl_def_id, true); } } for impl_def_id in all_incoherent_impls { self.resolve_doc_links_extern_impl(impl_def_id, true); } - - self.all_trait_impls - .extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id)); } if crates.len() > start_cnum { @@ -298,6 +321,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { && module_id.is_local() { if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() { + self.local_doc_reachable.insert(def_id); let scope_id = match child.res { Res::Def( DefKind::Variant diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 7158355ffda..03be5e79971 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -19,8 +19,7 @@ use crate::passes::source_span_for_markdown_range; pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) { if let Some(dox) = &item.attrs.collapsed_doc_value() { let sp = item.attr_span(cx.tcx); - let extra = - crate::html::markdown::ExtraInfo::new_did(cx.tcx, item.item_id.expect_def_id(), sp); + let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp); for code_block in markdown::rust_code_blocks(dox, &extra) { check_rust_syntax(cx, item, dox, code_block); } @@ -73,7 +72,6 @@ fn check_rust_syntax( return; }; - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id); let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; @@ -93,6 +91,7 @@ fn check_rust_syntax( // Finally build and emit the completed diagnostic. // All points of divergence have been handled earlier so this can be // done the same way whether the span is precise or not. + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id); cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| { let explanation = if is_ignore { "`ignore` code blocks require valid Rust code for syntax highlighting; \ diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index de3a4b33905..a4bc486900b 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -9,6 +9,7 @@ use crate::fold::DocFolder; use crate::passes::Pass; use rustc_hir::def_id::LocalDefId; +use rustc_middle::ty::DefIdTree; pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass { name: "propagate-doc-cfg", @@ -41,24 +42,22 @@ impl<'a, 'tcx> CfgPropagator<'a, 'tcx> { let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) else { return }; - let hir = self.cx.tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(def_id); - if check_parent { - let expected_parent = hir.get_parent_item(hir_id); + let expected_parent = self.cx.tcx.opt_local_parent(def_id); // If parents are different, it means that `item` is a reexport and we need // to compute the actual `cfg` by iterating through its "real" parents. - if self.parent == Some(expected_parent.def_id) { + if self.parent.is_some() && self.parent == expected_parent { return; } } let mut attrs = Vec::new(); - for (parent_hir_id, _) in hir.parent_iter(hir_id) { - if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) { - attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id())); - } + let mut next_def_id = def_id; + while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) { + attrs.extend_from_slice(load_attrs(self.cx, parent_def_id.to_def_id())); + next_def_id = parent_def_id; } + let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); item.cfg = cfg; } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 00ea6ca4152..a89d6fa8398 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -4,9 +4,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_hir::{HirIdSet, Node, CRATE_HIR_ID}; -use rustc_middle::ty::TyCtxt; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; +use rustc_hir::{Node, CRATE_HIR_ID}; +use rustc_middle::ty::{DefIdTree, TyCtxt}; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -23,19 +23,26 @@ pub(crate) struct Module<'hir> { pub(crate) name: Symbol, pub(crate) where_inner: Span, pub(crate) mods: Vec<Module<'hir>>, - pub(crate) id: hir::HirId, + pub(crate) def_id: LocalDefId, // (item, renamed, import_id) - pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<hir::HirId>)>, + pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>)>, pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>, } impl Module<'_> { - pub(crate) fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Self { - Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() } + pub(crate) fn new(name: Symbol, def_id: LocalDefId, where_inner: Span) -> Self { + Module { + name, + def_id, + where_inner, + mods: Vec::new(), + items: Vec::new(), + foreigns: Vec::new(), + } } pub(crate) fn where_outer(&self, tcx: TyCtxt<'_>) -> Span { - tcx.hir().span(self.id) + tcx.def_span(self.def_id) } } @@ -46,10 +53,10 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> { std::iter::once(crate_name).chain(relative).collect() } -pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool { - while let Some(id) = tcx.hir().get_enclosing_scope(node) { +pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: LocalDefId) -> bool { + while let Some(id) = tcx.opt_local_parent(node) { node = id; - if tcx.hir().attrs(node).lists(sym::doc).has_word(sym::hidden) { + if tcx.is_doc_hidden(node.to_def_id()) { return true; } } @@ -61,7 +68,7 @@ pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool pub(crate) struct RustdocVisitor<'a, 'tcx> { cx: &'a mut core::DocContext<'tcx>, - view_item_stack: HirIdSet, + view_item_stack: LocalDefIdSet, inlining: bool, /// Are the current module and all of its parents public? inside_public_path: bool, @@ -71,8 +78,8 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. - let mut stack = HirIdSet::default(); - stack.insert(hir::CRATE_HIR_ID); + let mut stack = LocalDefIdSet::default(); + stack.insert(CRATE_DEF_ID); RustdocVisitor { cx, view_item_stack: stack, @@ -89,7 +96,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub(crate) fn visit(mut self) -> Module<'tcx> { let mut top_level_module = self.visit_mod_contents( - hir::CRATE_HIR_ID, + CRATE_DEF_ID, self.cx.tcx.hir().root_module(), self.cx.tcx.crate_name(LOCAL_CRATE), None, @@ -152,16 +159,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_mod_contents( &mut self, - id: hir::HirId, + def_id: LocalDefId, m: &'tcx hir::Mod<'tcx>, name: Symbol, - parent_id: Option<hir::HirId>, + parent_id: Option<LocalDefId>, ) -> Module<'tcx> { - let mut om = Module::new(name, id, m.spans.inner_span); - let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); + let mut om = Module::new(name, def_id, m.spans.inner_span); // Keep track of if there were any private modules in the path. let orig_inside_public_path = self.inside_public_path; - self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public(); + self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public(); for &i in m.item_ids { let item = self.cx.tcx.hir().item(i); if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { @@ -193,7 +199,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { /// Returns `true` if the target has been inlined. fn maybe_inline_local( &mut self, - id: hir::HirId, + def_id: LocalDefId, res: Res, renamed: Option<Symbol>, glob: bool, @@ -211,10 +217,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; }; - let use_attrs = tcx.hir().attrs(id); + let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) - || use_attrs.lists(sym::doc).has_word(sym::hidden); + || tcx.is_doc_hidden(def_id.to_def_id()); // For cross-crate impl inlining we need to know whether items are // reachable in documentation -- a previously unreachable item can be @@ -225,37 +231,39 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - let res_hir_id = match res_did.as_local() { - Some(n) => tcx.hir().local_def_id_to_hir_id(n), - None => return false, + let Some(res_did) = res_did.as_local() else { + return false; }; - let is_private = - !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, res_did); - let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id); + let is_private = !self + .cx + .cache + .effective_visibilities + .is_directly_public(self.cx.tcx, res_did.to_def_id()); + let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did); // Only inline if requested or if the item would otherwise be stripped. if (!please_inline && !is_private && !is_hidden) || is_no_inline { return false; } - if !self.view_item_stack.insert(res_hir_id) { + if !self.view_item_stack.insert(res_did) { return false; } - let ret = match tcx.hir().get(res_hir_id) { + let ret = match tcx.hir().get_by_def_id(res_did) { Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { let i = self.cx.tcx.hir().item(i); - self.visit_item(i, None, om, Some(id)); + self.visit_item(i, None, om, Some(def_id)); } self.inlining = prev; true } Node::Item(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_item(it, renamed, om, Some(id)); + self.visit_item(it, renamed, om, Some(def_id)); self.inlining = prev; true } @@ -267,7 +275,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } _ => false, }; - self.view_item_stack.remove(&res_hir_id); + self.view_item_stack.remove(&res_did); ret } @@ -276,7 +284,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { item: &'tcx hir::Item<'_>, renamed: Option<Symbol>, om: &mut Module<'tcx>, - parent_id: Option<hir::HirId>, + parent_id: Option<LocalDefId>, ) { debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); @@ -321,7 +329,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let is_glob = kind == hir::UseKind::Glob; let ident = if is_glob { None } else { Some(name) }; if self.maybe_inline_local( - item.hir_id(), + item.owner_id.def_id, res, ident, is_glob, @@ -356,7 +364,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } hir::ItemKind::Mod(ref m) => { - om.mods.push(self.visit_mod_contents(item.hir_id(), m, name, parent_id)); + om.mods.push(self.visit_mod_contents(item.owner_id.def_id, m, name, parent_id)); } hir::ItemKind::Fn(..) | hir::ItemKind::ExternCrate(..) diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index fd4f9254107..07d8b78d767 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,7 +1,8 @@ use crate::core::DocContext; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; +use rustc_resolve::Resolver; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses @@ -25,6 +26,10 @@ impl RustdocEffectiveVisibilities { define_method!(is_directly_public); define_method!(is_exported); define_method!(is_reachable); + + pub(crate) fn init(&mut self, extern_public: DefIdSet) { + self.extern_public = extern_public; + } } pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { @@ -37,6 +42,17 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { .visit_item(def_id) } +pub(crate) fn early_lib_embargo_visit_item( + resolver: &Resolver<'_>, + extern_public: &mut DefIdSet, + def_id: DefId, + is_mod: bool, +) { + assert!(!def_id.is_local()); + EarlyLibEmbargoVisitor { resolver, extern_public, visited_mods: Default::default() } + .visit_item(def_id, is_mod) +} + /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) struct LibEmbargoVisitor<'a, 'tcx> { @@ -47,6 +63,14 @@ struct LibEmbargoVisitor<'a, 'tcx> { visited_mods: DefIdSet, } +struct EarlyLibEmbargoVisitor<'r, 'ra> { + resolver: &'r Resolver<'ra>, + // Effective visibilities for reachable nodes + extern_public: &'r mut DefIdSet, + // Keeps track of already visited modules, in case a module re-exports its parent + visited_mods: DefIdSet, +} + impl LibEmbargoVisitor<'_, '_> { fn visit_mod(&mut self, def_id: DefId) { if !self.visited_mods.insert(def_id) { @@ -71,3 +95,28 @@ impl LibEmbargoVisitor<'_, '_> { } } } + +impl EarlyLibEmbargoVisitor<'_, '_> { + fn visit_mod(&mut self, def_id: DefId) { + if !self.visited_mods.insert(def_id) { + return; + } + + for item in self.resolver.cstore().module_children_untracked(def_id, self.resolver.sess()) { + if let Some(def_id) = item.res.opt_def_id() { + if item.vis.is_public() { + self.visit_item(def_id, matches!(item.res, Res::Def(DefKind::Mod, _))); + } + } + } + } + + fn visit_item(&mut self, def_id: DefId, is_mod: bool) { + if !self.resolver.cstore().is_doc_hidden_untracked(def_id) { + self.extern_public.insert(def_id); + if is_mod { + self.visit_mod(def_id); + } + } + } +} diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 985d561f0bb9b76ec043a2b12511790ec7a2b95 +Subproject 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6 diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 1bc457a9479..24e677ce8e1 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -157,6 +157,11 @@ jobs: - name: Test metadata collection run: cargo collect-metadata + - name: Test lint_configuration.md is up-to-date + run: | + echo "run \`cargo collect-metadata\` if this fails" + git update-index --refresh + integration_build: needs: changelog runs-on: ubuntu-latest diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 8e31e8f0d98..e2cde09776f 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,204 @@ document. ## Unreleased / Beta / In Rust Nightly -[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master) +[d822110d...master](https://github.com/rust-lang/rust-clippy/compare/d822110d...master) + +## Rust 1.67 + +Current stable, released 2023-01-26 + +[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d) + +### New Lints + +* [`seek_from_current`] + [#9681](https://github.com/rust-lang/rust-clippy/pull/9681) +* [`from_raw_with_void_ptr`] + [#9690](https://github.com/rust-lang/rust-clippy/pull/9690) +* [`misnamed_getters`] + [#9770](https://github.com/rust-lang/rust-clippy/pull/9770) +* [`seek_to_start_instead_of_rewind`] + [#9667](https://github.com/rust-lang/rust-clippy/pull/9667) +* [`suspicious_xor_used_as_pow`] + [#9506](https://github.com/rust-lang/rust-clippy/pull/9506) +* [`unnecessary_safety_doc`] + [#9822](https://github.com/rust-lang/rust-clippy/pull/9822) +* [`unchecked_duration_subtraction`] + [#9570](https://github.com/rust-lang/rust-clippy/pull/9570) +* [`manual_is_ascii_check`] + [#9765](https://github.com/rust-lang/rust-clippy/pull/9765) +* [`unnecessary_safety_comment`] + [#9851](https://github.com/rust-lang/rust-clippy/pull/9851) +* [`let_underscore_future`] + [#9760](https://github.com/rust-lang/rust-clippy/pull/9760) +* [`manual_let_else`] + [#8437](https://github.com/rust-lang/rust-clippy/pull/8437) + +### Moves and Deprecations + +* Moved [`uninlined_format_args`] to `style` (Now warn-by-default) + [#9865](https://github.com/rust-lang/rust-clippy/pull/9865) +* Moved [`needless_collect`] to `nursery` (Now allow-by-default) + [#9705](https://github.com/rust-lang/rust-clippy/pull/9705) +* Moved [`or_fun_call`] to `nursery` (Now allow-by-default) + [#9829](https://github.com/rust-lang/rust-clippy/pull/9829) +* Uplifted [`let_underscore_lock`] into rustc + [#9697](https://github.com/rust-lang/rust-clippy/pull/9697) +* Uplifted [`let_underscore_drop`] into rustc + [#9697](https://github.com/rust-lang/rust-clippy/pull/9697) +* Moved [`bool_to_int_with_if`] to `pedantic` (Now allow-by-default) + [#9830](https://github.com/rust-lang/rust-clippy/pull/9830) +* Move `index_refutable_slice` to `pedantic` (Now warn-by-default) + [#9975](https://github.com/rust-lang/rust-clippy/pull/9975) +* Moved [`manual_clamp`] to `nursery` (Now allow-by-default) + [#10101](https://github.com/rust-lang/rust-clippy/pull/10101) + +### Enhancements + +* The scope of `#![clippy::msrv]` is now tracked correctly + [#9924](https://github.com/rust-lang/rust-clippy/pull/9924) +* `#[clippy::msrv]` can now be used as an outer attribute + [#9860](https://github.com/rust-lang/rust-clippy/pull/9860) +* Clippy will now avoid Cargo's cache, if `Cargo.toml` or `clippy.toml` have changed + [#9707](https://github.com/rust-lang/rust-clippy/pull/9707) +* [`uninlined_format_args`]: Added a new config `allow-mixed-uninlined-format-args` to allow the + lint, if only some arguments can be inlined + [#9865](https://github.com/rust-lang/rust-clippy/pull/9865) +* [`needless_lifetimes`]: Now provides suggests for individual lifetimes + [#9743](https://github.com/rust-lang/rust-clippy/pull/9743) +* [`needless_collect`]: Now detects needless `is_empty` and `contains` calls + [#8744](https://github.com/rust-lang/rust-clippy/pull/8744) +* [`blanket_clippy_restriction_lints`]: Now lints, if `clippy::restriction` is enabled via the + command line arguments + [#9755](https://github.com/rust-lang/rust-clippy/pull/9755) +* [`mutable_key_type`]: Now has the `ignore-interior-mutability` configuration, to add types which + should be ignored by the lint + [#9692](https://github.com/rust-lang/rust-clippy/pull/9692) +* [`uninlined_format_args`]: Now works for multiline `format!` expressions + [#9945](https://github.com/rust-lang/rust-clippy/pull/9945) +* [`cognitive_complexity`]: Now works for async functions + [#9828](https://github.com/rust-lang/rust-clippy/pull/9828) + [#9836](https://github.com/rust-lang/rust-clippy/pull/9836) +* [`vec_box`]: Now avoids an off-by-one error when using the `vec-box-size-threshold` configuration + [#9848](https://github.com/rust-lang/rust-clippy/pull/9848) +* [`never_loop`]: Now correctly handles breaks in nested labeled blocks + [#9858](https://github.com/rust-lang/rust-clippy/pull/9858) + [#9837](https://github.com/rust-lang/rust-clippy/pull/9837) +* [`disallowed_methods`], [`disallowed_types`], [`disallowed_macros`]: Now correctly resolve + paths, if a crate is used multiple times with different versions + [#9800](https://github.com/rust-lang/rust-clippy/pull/9800) +* [`disallowed_methods`]: Can now be used for local methods + [#9800](https://github.com/rust-lang/rust-clippy/pull/9800) +* [`print_stdout`], [`print_stderr`]: Can now be enabled in test with the `allow-print-in-tests` + config value + [#9797](https://github.com/rust-lang/rust-clippy/pull/9797) +* [`from_raw_with_void_ptr`]: Now works for `Rc`, `Arc`, `alloc::rc::Weak` and + `alloc::sync::Weak` types. + [#9700](https://github.com/rust-lang/rust-clippy/pull/9700) +* [`needless_borrowed_reference`]: Now works for struct and tuple patterns with wildcards + [#9855](https://github.com/rust-lang/rust-clippy/pull/9855) +* [`or_fun_call`]: Now supports `map_or` methods + [#9689](https://github.com/rust-lang/rust-clippy/pull/9689) +* [`unwrap_used`], [`expect_used`]: No longer lints in test code + [#9686](https://github.com/rust-lang/rust-clippy/pull/9686) +* [`fn_params_excessive_bools`]: Is now emitted with the lint level at the linted function + [#9698](https://github.com/rust-lang/rust-clippy/pull/9698) + +### False Positive Fixes + +* [`new_ret_no_self`]: No longer lints when `impl Trait<Self>` is returned + [#9733](https://github.com/rust-lang/rust-clippy/pull/9733) +* [`unnecessary_lazy_evaluations`]: No longer lints, if the type has a significant drop + [#9750](https://github.com/rust-lang/rust-clippy/pull/9750) +* [`option_if_let_else`]: No longer lints, if any arm has guard + [#9747](https://github.com/rust-lang/rust-clippy/pull/9747) +* [`explicit_auto_deref`]: No longer lints, if the target type is a projection with generic + arguments + [#9813](https://github.com/rust-lang/rust-clippy/pull/9813) +* [`unnecessary_to_owned`]: No longer lints, if the suggestion effects types + [#9796](https://github.com/rust-lang/rust-clippy/pull/9796) +* [`needless_borrow`]: No longer lints, if the suggestion is affected by `Deref` + [#9674](https://github.com/rust-lang/rust-clippy/pull/9674) +* [`unused_unit`]: No longer lints, if lifetimes are bound to the return type + [#9849](https://github.com/rust-lang/rust-clippy/pull/9849) +* [`mut_mut`]: No longer lints cases with unsized mutable references + [#9835](https://github.com/rust-lang/rust-clippy/pull/9835) +* [`bool_to_int_with_if`]: No longer lints in const context + [#9738](https://github.com/rust-lang/rust-clippy/pull/9738) +* [`use_self`]: No longer lints in macros + [#9704](https://github.com/rust-lang/rust-clippy/pull/9704) +* [`unnecessary_operation`]: No longer lints, if multiple macros are involved + [#9981](https://github.com/rust-lang/rust-clippy/pull/9981) +* [`allow_attributes_without_reason`]: No longer lints inside external macros + [#9630](https://github.com/rust-lang/rust-clippy/pull/9630) +* [`question_mark`]: No longer lints for `if let Err()` with an `else` branch + [#9722](https://github.com/rust-lang/rust-clippy/pull/9722) +* [`unnecessary_cast`]: No longer lints if the identifier and cast originate from different macros + [#9980](https://github.com/rust-lang/rust-clippy/pull/9980) +* [`arithmetic_side_effects`]: Now detects operations with associated constants + [#9592](https://github.com/rust-lang/rust-clippy/pull/9592) +* [`explicit_auto_deref`]: No longer lints, if the initial value is not a reference or reference + receiver + [#9997](https://github.com/rust-lang/rust-clippy/pull/9997) +* [`module_name_repetitions`], [`single_component_path_imports`]: Now handle `#[allow]` + attributes correctly + [#9879](https://github.com/rust-lang/rust-clippy/pull/9879) +* [`bool_to_int_with_if`]: No longer lints `if let` statements + [#9714](https://github.com/rust-lang/rust-clippy/pull/9714) +* [`needless_borrow`]: No longer lints, `if`-`else`-statements that require the borrow + [#9791](https://github.com/rust-lang/rust-clippy/pull/9791) +* [`needless_borrow`]: No longer lints borrows, if moves were illegal + [#9711](https://github.com/rust-lang/rust-clippy/pull/9711) +* [`manual_swap`]: No longer lints in const context + [#9871](https://github.com/rust-lang/rust-clippy/pull/9871) + +### Suggestion Fixes/Improvements + +* [`missing_safety_doc`], [`missing_errors_doc`], [`missing_panics_doc`]: No longer show the + entire item in the lint emission. + [#9772](https://github.com/rust-lang/rust-clippy/pull/9772) +* [`needless_lifetimes`]: Only suggests `'_` when it's applicable + [#9743](https://github.com/rust-lang/rust-clippy/pull/9743) +* [`use_self`]: Now suggests full paths correctly + [#9726](https://github.com/rust-lang/rust-clippy/pull/9726) +* [`redundant_closure_call`]: Now correctly deals with macros during suggestion creation + [#9987](https://github.com/rust-lang/rust-clippy/pull/9987) +* [`unnecessary_cast`]: Suggestions now correctly deal with references + [#9996](https://github.com/rust-lang/rust-clippy/pull/9996) +* [`unnecessary_join`]: Suggestions now correctly use [turbofish] operators + [#9779](https://github.com/rust-lang/rust-clippy/pull/9779) +* [`equatable_if_let`]: Can now suggest `matches!` replacements + [#9368](https://github.com/rust-lang/rust-clippy/pull/9368) +* [`string_extend_chars`]: Suggestions now correctly work for `str` slices + [#9741](https://github.com/rust-lang/rust-clippy/pull/9741) +* [`redundant_closure_for_method_calls`]: Suggestions now include angle brackets and generic + arguments if needed + [#9745](https://github.com/rust-lang/rust-clippy/pull/9745) +* [`manual_let_else`]: Suggestions no longer expand macro calls + [#9943](https://github.com/rust-lang/rust-clippy/pull/9943) +* [`infallible_destructuring_match`]: Suggestions now preserve references + [#9850](https://github.com/rust-lang/rust-clippy/pull/9850) +* [`result_large_err`]: The error now shows the largest enum variant + [#9662](https://github.com/rust-lang/rust-clippy/pull/9662) +* [`needless_return`]: Suggestions are now formatted better + [#9967](https://github.com/rust-lang/rust-clippy/pull/9967) +* [`unused_rounding`]: The suggestion now preserves the original float literal notation + [#9870](https://github.com/rust-lang/rust-clippy/pull/9870) + +[turbofish]: https://turbo.fish/::%3CClippy%3E + +### ICE Fixes + +* [`result_large_err`]: Fixed ICE for empty enums + [#10007](https://github.com/rust-lang/rust-clippy/pull/10007) +* [`redundant_allocation`]: Fixed ICE for types with bounded variables + [#9773](https://github.com/rust-lang/rust-clippy/pull/9773) +* [`unused_rounding`]: Fixed ICE, if `_` was used as a separator + [#10001](https://github.com/rust-lang/rust-clippy/pull/10001) ## Rust 1.66 -Current stable, released 2022-12-15 +Released 2022-12-15 [b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1) @@ -166,6 +359,7 @@ Current stable, released 2022-12-15 * [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing [#9505](https://github.com/rust-lang/rust-clippy/pull/9505) + [#10027](https://github.com/rust-lang/rust-clippy/pull/10027) * [`manual_range_contains`]: No longer ICEs on values behind references [#9627](https://github.com/rust-lang/rust-clippy/pull/9627) * [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments @@ -4383,6 +4577,7 @@ Released 2018-09-13 [`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl +[`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block [`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate [`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit [`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index f8cb4b7219c..2cfb47dd758 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.68" +version = "0.1.69" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 81254ba8b8b..ab44db69483 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -194,11 +194,21 @@ value` mapping e.g. ```toml avoid-breaking-exported-api = false disallowed-names = ["toto", "tata", "titi"] -cognitive-complexity-threshold = 30 ``` -See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration), -the lint descriptions contain the names and meanings of these configuration variables. +The [table of configurations](https://doc.rust-lang.org/nightly/clippy/lint_configuration.html) +contains all config values, their default, and a list of lints they affect. +Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration) +, also contains information about these values. + +For configurations that are a list type with default values such as +[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names), +you can use the unique value `".."` to extend the default values instead of replacing them. + +```toml +# default of disallowed-names is ["foo", "baz", "quux"] +disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"] +``` > **Note** > diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md index 1f0b8db28a1..0649f7a631d 100644 --- a/src/tools/clippy/book/src/SUMMARY.md +++ b/src/tools/clippy/book/src/SUMMARY.md @@ -5,6 +5,7 @@ - [Installation](installation.md) - [Usage](usage.md) - [Configuration](configuration.md) + - [Lint Configuration](lint_configuration.md) - [Clippy's Lints](lints.md) - [Continuous Integration](continuous_integration/README.md) - [GitHub Actions](continuous_integration/github_actions.md) diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md index 430ff8b739a..87f4a697af9 100644 --- a/src/tools/clippy/book/src/configuration.md +++ b/src/tools/clippy/book/src/configuration.md @@ -8,11 +8,21 @@ basic `variable = value` mapping eg. ```toml avoid-breaking-exported-api = false disallowed-names = ["toto", "tata", "titi"] -cognitive-complexity-threshold = 30 ``` -See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration), -the lint descriptions contain the names and meanings of these configuration variables. +The [table of configurations](./lint_configuration.md) +contains all config values, their default, and a list of lints they affect. +Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration) +, also contains information about these values. + +For configurations that are a list type with default values such as +[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names), +you can use the unique value `".."` to extend the default values instead of replacing them. + +```toml +# default of disallowed-names is ["foo", "baz", "quux"] +disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"] +``` To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index 8b4eee8c9d9..f57dc627dce 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -146,7 +146,8 @@ For cargo lints, the process of testing differs in that we are interested in the manifest. If our new lint is named e.g. `foo_categories`, after running `cargo dev -new_lint` we will find by default two new crates, each with its manifest file: +new_lint --name=foo_categories --type=cargo --category=cargo` we will find by +default two new crates, each with its manifest file: * `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error. @@ -699,6 +700,10 @@ for some users. Adding a configuration is done in the following steps: `clippy.toml` file with the configuration value and a rust file that should be linted by Clippy. The test can otherwise be written as usual. +5. Update [Lint Configuration](../lint_configuration.md) + + Run `cargo collect-metadata` to generate documentation changes for the book. + [`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs [`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs [`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui diff --git a/src/tools/clippy/book/src/development/infrastructure/book.md b/src/tools/clippy/book/src/development/infrastructure/book.md index a4874219185..dbd624ecd73 100644 --- a/src/tools/clippy/book/src/development/infrastructure/book.md +++ b/src/tools/clippy/book/src/development/infrastructure/book.md @@ -3,15 +3,15 @@ This document explains how to make additions and changes to the Clippy book, the guide to Clippy that you're reading right now. The Clippy book is formatted with [Markdown](https://www.markdownguide.org) and generated by -[mdbook](https://github.com/rust-lang/mdBook). +[mdBook](https://github.com/rust-lang/mdBook). -- [Get mdbook](#get-mdbook) +- [Get mdBook](#get-mdbook) - [Make changes](#make-changes) -## Get mdbook +## Get mdBook While not strictly necessary since the book source is simply Markdown text -files, having mdbook locally will allow you to build, test and serve the book +files, having mdBook locally will allow you to build, test and serve the book locally to view changes before you commit them to the repository. You likely already have `cargo` installed, so the easiest option is to simply: @@ -19,7 +19,7 @@ already have `cargo` installed, so the easiest option is to simply: cargo install mdbook ``` -See the mdbook [installation](https://github.com/rust-lang/mdBook#installation) +See the mdBook [installation](https://github.com/rust-lang/mdBook#installation) instructions for other options. ## Make changes @@ -27,7 +27,7 @@ instructions for other options. The book's [src](https://github.com/rust-lang/rust-clippy/tree/master/book/src) directory contains all of the markdown files used to generate the book. If you -want to see your changes in real time, you can use the mdbook `serve` command to +want to see your changes in real time, you can use the mdBook `serve` command to run a web server locally that will automatically update changes as they are made. From the top level of your `rust-clippy` directory: @@ -38,5 +38,5 @@ mdbook serve book --open Then navigate to `http://localhost:3000` to see the generated book. While the server is running, changes you make will automatically be updated. -For more information, see the mdbook +For more information, see the mdBook [guide](https://rust-lang.github.io/mdBook/). diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md index 80a47affe30..d1ac7237b5e 100644 --- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md +++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md @@ -95,11 +95,23 @@ As section headers, we use: Please also be sure to update the Beta/Unreleased sections at the top with the relevant commit ranges. -If you have the time, it would be appreciated if you double-check, that the -`#[clippy::version]` attributes for the added lints contains the correct version. +#### 3.1 Include `beta-accepted` PRs + +Look for the [`beta-accepted`] label and make sure to also include the PRs with +that label in the changelog. If you can, remove the `beta-accepted` labels +**after** the changelog PR was merged. + +> _Note:_ Some of those PRs might even got backported to the previous `beta`. +> Those have to be included in the changelog of the _previous_ release. + +### 4. Update `clippy::version` attributes + +Next, make sure to check that the `#[clippy::version]` attributes for the added +lints contain the correct version. [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy [rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy [rust_stable_tools]: https://github.com/rust-lang/rust/releases +[`beta-accepted`]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-accepted+ diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md new file mode 100644 index 00000000000..f79dbb50ff4 --- /dev/null +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -0,0 +1,523 @@ +<!-- +This file is generated by `cargo collect-metadata`. +Please use that command to update the file and do not edit it by hand. +--> + +## Lint Configuration Options +| <div style="width:290px">Option</div> | Default Value | +|--|--| +| [arithmetic-side-effects-allowed](#arithmetic-side-effects-allowed) | `{}` | +| [arithmetic-side-effects-allowed-binary](#arithmetic-side-effects-allowed-binary) | `[]` | +| [arithmetic-side-effects-allowed-unary](#arithmetic-side-effects-allowed-unary) | `{}` | +| [avoid-breaking-exported-api](#avoid-breaking-exported-api) | `true` | +| [msrv](#msrv) | `None` | +| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` | +| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` | +| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` | +| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` | +| [type-complexity-threshold](#type-complexity-threshold) | `250` | +| [single-char-binding-names-threshold](#single-char-binding-names-threshold) | `4` | +| [too-large-for-stack](#too-large-for-stack) | `200` | +| [enum-variant-name-threshold](#enum-variant-name-threshold) | `3` | +| [enum-variant-size-threshold](#enum-variant-size-threshold) | `200` | +| [verbose-bit-mask-threshold](#verbose-bit-mask-threshold) | `1` | +| [literal-representation-threshold](#literal-representation-threshold) | `16384` | +| [trivial-copy-size-limit](#trivial-copy-size-limit) | `None` | +| [pass-by-value-size-limit](#pass-by-value-size-limit) | `256` | +| [too-many-lines-threshold](#too-many-lines-threshold) | `100` | +| [array-size-threshold](#array-size-threshold) | `512000` | +| [vec-box-size-threshold](#vec-box-size-threshold) | `4096` | +| [max-trait-bounds](#max-trait-bounds) | `3` | +| [max-struct-bools](#max-struct-bools) | `3` | +| [max-fn-params-bools](#max-fn-params-bools) | `3` | +| [warn-on-all-wildcard-imports](#warn-on-all-wildcard-imports) | `false` | +| [disallowed-macros](#disallowed-macros) | `[]` | +| [disallowed-methods](#disallowed-methods) | `[]` | +| [disallowed-types](#disallowed-types) | `[]` | +| [unreadable-literal-lint-fractions](#unreadable-literal-lint-fractions) | `true` | +| [upper-case-acronyms-aggressive](#upper-case-acronyms-aggressive) | `false` | +| [matches-for-let-else](#matches-for-let-else) | `WellKnownTypes` | +| [cargo-ignore-publish](#cargo-ignore-publish) | `false` | +| [standard-macro-braces](#standard-macro-braces) | `[]` | +| [enforced-import-renames](#enforced-import-renames) | `[]` | +| [allowed-scripts](#allowed-scripts) | `["Latin"]` | +| [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` | +| [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` | +| [max-include-file-size](#max-include-file-size) | `1000000` | +| [allow-expect-in-tests](#allow-expect-in-tests) | `false` | +| [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` | +| [allow-dbg-in-tests](#allow-dbg-in-tests) | `false` | +| [allow-print-in-tests](#allow-print-in-tests) | `false` | +| [large-error-threshold](#large-error-threshold) | `128` | +| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` | +| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` | +| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | + +### arithmetic-side-effects-allowed +Suppress checking of the passed type names in all types of operations. + +If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. + +#### Example + +```toml +arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] +``` + +#### Noteworthy + +A type, say `SomeType`, listed in this configuration has the same behavior of +`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. + +**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`) + +* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) + + +### arithmetic-side-effects-allowed-binary +Suppress checking of the passed type pair names in binary operations like addition or +multiplication. + +Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless +of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`. + +Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as +`["AnotherType", "SomeType"]`. + +#### Example + +```toml +arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] +``` + +**Default Value:** `[]` (`Vec<[String; 2]>`) + +* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) + + +### arithmetic-side-effects-allowed-unary +Suppress checking of the passed type names in unary operations like "negation" (`-`). + +#### Example + +```toml +arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] +``` + +**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`) + +* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) + + +### avoid-breaking-exported-api +Suppress lints whenever the suggested change would cause breakage for other crates. + +**Default Value:** `true` (`bool`) + +* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) +* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) +* [unnecessary_wraps](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps) +* [unused_self](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self) +* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) +* [wrong_self_convention](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) +* [box_collection](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) +* [redundant_allocation](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) +* [rc_buffer](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) +* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) +* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) +* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) + + +### msrv +The minimum rust version that the project supports + +**Default Value:** `None` (`Option<String>`) + +* [manual_split_once](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) +* [manual_str_repeat](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) +* [cloned_instead_of_copied](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) +* [redundant_field_names](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) +* [redundant_static_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) +* [filter_map_next](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) +* [checked_conversions](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) +* [manual_range_contains](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) +* [use_self](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) +* [mem_replace_with_default](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) +* [manual_non_exhaustive](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [option_as_ref_deref](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) +* [map_unwrap_or](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) +* [match_like_matches_macro](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) +* [manual_strip](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) +* [missing_const_for_fn](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) +* [unnested_or_patterns](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) +* [ptr_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) +* [if_then_some_else_none](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) +* [approx_constant](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) +* [deprecated_cfg_attr](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) +* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +* [map_clone](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) +* [borrow_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) +* [manual_bits](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) +* [err_expect](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) +* [cast_abs_to_unsigned](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) +* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) +* [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) +* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) +* [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) + + +### cognitive-complexity-threshold +The maximum cognitive complexity a function can have + +**Default Value:** `25` (`u64`) + +* [cognitive_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) + + +### disallowed-names +The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value +`".."` can be used as part of the list to indicate, that the configured values should be appended to the +default configuration of Clippy. By default any configuration will replace the default value. + +**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`) + +* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) + + +### doc-valid-idents +The list of words this lint should not consider as identifiers needing ticks. The value +`".."` can be used as part of the list to indicate, that the configured values should be appended to the +default configuration of Clippy. By default any configuraction will replace the default value. For example: +* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. +* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. + +Default list: + +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`) + +* [doc_markdown](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) + + +### too-many-arguments-threshold +The maximum number of argument a function or method can have + +**Default Value:** `7` (`u64`) + +* [too_many_arguments](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) + + +### type-complexity-threshold +The maximum complexity a type can have + +**Default Value:** `250` (`u64`) + +* [type_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) + + +### single-char-binding-names-threshold +The maximum number of single char bindings a scope may have + +**Default Value:** `4` (`u64`) + +* [many_single_char_names](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) + + +### too-large-for-stack +The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap + +**Default Value:** `200` (`u64`) + +* [boxed_local](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) +* [useless_vec](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) + + +### enum-variant-name-threshold +The minimum number of enum variants for the lints about variant names to trigger + +**Default Value:** `3` (`u64`) + +* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) + + +### enum-variant-size-threshold +The maximum size of an enum's variant to avoid box suggestion + +**Default Value:** `200` (`u64`) + +* [large_enum_variant](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) + + +### verbose-bit-mask-threshold +The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' + +**Default Value:** `1` (`u64`) + +* [verbose_bit_mask](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) + + +### literal-representation-threshold +The lower bound for linting decimal literals + +**Default Value:** `16384` (`u64`) + +* [decimal_literal_representation](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) + + +### trivial-copy-size-limit +The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. + +**Default Value:** `None` (`Option<u64>`) + +* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) + + +### pass-by-value-size-limit +The minimum size (in bytes) to consider a type for passing by reference instead of by value. + +**Default Value:** `256` (`u64`) + +* [large_type_pass_by_move](https://rust-lang.github.io/rust-clippy/master/index.html#large_type_pass_by_move) + + +### too-many-lines-threshold +The maximum number of lines a function or method can have + +**Default Value:** `100` (`u64`) + +* [too_many_lines](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) + + +### array-size-threshold +The maximum allowed size for arrays on the stack + +**Default Value:** `512000` (`u128`) + +* [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) +* [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) + + +### vec-box-size-threshold +The size of the boxed type in bytes, where boxing in a `Vec` is allowed + +**Default Value:** `4096` (`u64`) + +* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) + + +### max-trait-bounds +The maximum number of bounds a trait can have to be linted + +**Default Value:** `3` (`u64`) + +* [type_repetition_in_bounds](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) + + +### max-struct-bools +The maximum number of bool fields a struct can have + +**Default Value:** `3` (`u64`) + +* [struct_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) + + +### max-fn-params-bools +The maximum number of bool parameters a function can have + +**Default Value:** `3` (`u64`) + +* [fn_params_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) + + +### warn-on-all-wildcard-imports +Whether to allow certain wildcard imports (prelude, super in tests). + +**Default Value:** `false` (`bool`) + +* [wildcard_imports](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) + + +### disallowed-macros +The list of disallowed macros, written as fully qualified paths. + +**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) + +* [disallowed_macros](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros) + + +### disallowed-methods +The list of disallowed methods, written as fully qualified paths. + +**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) + +* [disallowed_methods](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) + + +### disallowed-types +The list of disallowed types, written as fully qualified paths. + +**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`) + +* [disallowed_types](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) + + +### unreadable-literal-lint-fractions +Should the fraction of a decimal be linted to include separators. + +**Default Value:** `true` (`bool`) + +* [unreadable_literal](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) + + +### upper-case-acronyms-aggressive +Enables verbose mode. Triggers if there is more than one uppercase char next to each other + +**Default Value:** `false` (`bool`) + +* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) + + +### matches-for-let-else +Whether the matches should be considered by the lint, and whether there should +be filtering for common types. + +**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`) + +* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) + + +### cargo-ignore-publish +For internal testing only, ignores the current `publish` settings in the Cargo manifest. + +**Default Value:** `false` (`bool`) + +* [_cargo_common_metadata](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata) + + +### standard-macro-braces +Enforce the named macros always use the braces specified. + +A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro +is could be used with a full path two `MacroMatcher`s have to be added one with the full path +`crate_name::macro_name` and one with just the macro name. + +**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`) + +* [nonstandard_macro_braces](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) + + +### enforced-import-renames +The list of imports to always rename, a fully qualified path followed by the rename. + +**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`) + +* [missing_enforced_import_renames](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) + + +### allowed-scripts +The list of unicode scripts allowed to be used in the scope. + +**Default Value:** `["Latin"]` (`Vec<String>`) + +* [disallowed_script_idents](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) + + +### enable-raw-pointer-heuristic-for-send +Whether to apply the raw pointer heuristic to determine if a type is `Send`. + +**Default Value:** `true` (`bool`) + +* [non_send_fields_in_send_ty](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty) + + +### max-suggested-slice-pattern-length +When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in +the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed. +For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. + +**Default Value:** `3` (`u64`) + +* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) + + +### max-include-file-size +The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes + +**Default Value:** `1000000` (`u64`) + +* [large_include_file](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) + + +### allow-expect-in-tests +Whether `expect` should be allowed within `#[cfg(test)]` + +**Default Value:** `false` (`bool`) + +* [expect_used](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) + + +### allow-unwrap-in-tests +Whether `unwrap` should be allowed in test cfg + +**Default Value:** `false` (`bool`) + +* [unwrap_used](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) + + +### allow-dbg-in-tests +Whether `dbg!` should be allowed in test functions + +**Default Value:** `false` (`bool`) + +* [dbg_macro](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) + + +### allow-print-in-tests +Whether print macros (ex. `println!`) should be allowed in test functions + +**Default Value:** `false` (`bool`) + +* [print_stdout](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) +* [print_stderr](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) + + +### large-error-threshold +The maximum size of the `Err`-variant in a `Result` returned from a function + +**Default Value:** `128` (`u64`) + +* [result_large_err](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) + + +### ignore-interior-mutability +A list of paths to types that should be treated like `Arc`, i.e. ignored but +for the generic parameters for determining interior mutability + +**Default Value:** `["bytes::Bytes"]` (`Vec<String>`) + +* [mutable_key](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key) + + +### allow-mixed-uninlined-format-args +Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` + +**Default Value:** `true` (`bool`) + +* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) + + +### suppress-restriction-lint-in-const +In same +cases the restructured operation might not be unavoidable, as the +suggested counterparts are unavailable in constant code. This +configuration will cause restriction lints to trigger even +if no suggestion can be made. + +**Default Value:** `false` (`bool`) + +* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) + + + diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index a9f69b1ba63..4c40483e3ec 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.68" +version = "0.1.69" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 82d368bb8bc..556fa579000 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -1,10 +1,11 @@ +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; -use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait}; +use clippy_utils::ty::{implements_trait, is_copy}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; @@ -43,9 +44,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool { ) && !e.span.from_expansion() } -fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(e); - +fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { cx.tcx .lang_items() .not_trait() @@ -77,31 +76,57 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { return; } let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return }; - if !(is_bool_lit(a) ^ is_bool_lit(b)) { + + let a_span = a.span.source_callsite(); + let b_span = b.span.source_callsite(); + + let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) { + // assert_eq!(true, b) + // ^^^^^^ + (true, false) => (a_span.until(b_span), b), + // assert_eq!(a, true) + // ^^^^^^ + (false, true) => (b_span.with_lo(a_span.hi()), a), // If there are two boolean arguments, we definitely don't understand // what's going on, so better leave things as is... // // Or there is simply no boolean and then we can leave things as is! - return; - } + _ => return, + }; - if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) { + let non_lit_ty = cx.typeck_results().expr_ty(non_lit_expr); + + if !is_impl_not_trait_with_bool_out(cx, non_lit_ty) { // At this point the expression which is not a boolean // literal does not implement Not trait with a bool output, // so we cannot suggest to rewrite our code return; } + if !is_copy(cx, non_lit_ty) { + // Only lint with types that are `Copy` because `assert!(x)` takes + // ownership of `x` whereas `assert_eq(x, true)` does not + return; + } + let macro_name = macro_name.as_str(); let non_eq_mac = ¯o_name[..macro_name.len() - 3]; - span_lint_and_sugg( + span_lint_and_then( cx, BOOL_ASSERT_COMPARISON, macro_call.span, &format!("used `{macro_name}!` with a literal bool"), - "replace it with", - format!("{non_eq_mac}!(..)"), - Applicability::MaybeIncorrect, + |diag| { + // assert_eq!(...) + // ^^^^^^^^^ + let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); + + diag.multipart_suggestion( + format!("replace it with `{non_eq_mac}!(..)`"), + vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())], + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 939bdbcdc7c..e8106beec37 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -6,9 +6,10 @@ use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp}; +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::sym; @@ -82,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, _: Span, - _: HirId, + _: LocalDefId, ) { NonminimalBoolVisitor { cx }.visit_body(body); } diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs index 9409f4844f5..1633ffd589c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind && method_name.ident.name == rustc_span::sym::as_ptr && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id) - && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did) + && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).subst_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() && let Some(recv) = snippet_opt(cx, receiver.span) diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index a6376484914..f3f8b8d8798 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,11 +1,14 @@ use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::expr_or_init; +use clippy_utils::source::snippet; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; +use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; +use rustc_span::Span; use rustc_target::abi::IntegerType; use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; @@ -74,7 +77,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_expr: &Expr<'_>, + cast_from: Ty<'_>, + cast_to: Ty<'_>, + cast_to_span: Span, +) { let msg = match (cast_from.kind(), cast_to.is_integral()) { (ty::Int(_) | ty::Uint(_), true) => { let from_nbits = apply_reductions( @@ -139,7 +149,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, ); return; } - format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) + format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}") }, (ty::Float(_), true) => { @@ -153,5 +163,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, _ => return, }; - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg); + let name_of_cast_from = snippet(cx, cast_expr.span, ".."); + let cast_to_snip = snippet(cx, cast_to_span, ".."); + let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})"); + + span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { + diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ..."); + diag.span_suggestion_with_style( + expr.span, + "... or use `try_from` and handle the error accordingly", + suggestion, + Applicability::Unspecified, + // always show the suggestion in a separate line + SuggestionStyle::ShowAlways, + ); + }); } diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 161e3a698e9..362f70d12d1 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -80,7 +80,8 @@ declare_clippy_lint! { /// ### What it does /// Checks for casts between numerical types that may /// truncate large values. This is expected behavior, so the cast is `Allow` by - /// default. + /// default. It suggests user either explicitly ignore the lint, + /// or use `try_from()` and handle the truncation, default, or panic explicitly. /// /// ### Why is this bad? /// In some problem domains, it is good practice to avoid @@ -93,6 +94,21 @@ declare_clippy_lint! { /// x as u8 /// } /// ``` + /// Use instead: + /// ``` + /// fn as_u8(x: u64) -> u8 { + /// if let Ok(x) = u8::try_from(x) { + /// x + /// } else { + /// todo!(); + /// } + /// } + /// // Or + /// #[allow(clippy::cast_possible_truncation)] + /// fn as_u16(x: u64) -> u16 { + /// x as u16 + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub CAST_POSSIBLE_TRUNCATION, pedantic, @@ -712,7 +728,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { - cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); + cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 1c3a89a9782..e8531157e0f 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -8,9 +8,10 @@ use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::{sym, BytePos}; @@ -140,9 +141,8 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { - let def_id = cx.tcx.hir().local_def_id(hir_id); if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) { let expr = if is_async_fn(kind) { match get_async_fn_body(cx.tcx, body) { diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 91ca73633f0..36a366fc974 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -422,6 +422,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::module_style::MOD_MODULE_FILES_INFO, crate::module_style::SELF_NAMED_MODULE_FILES_INFO, crate::multi_assignments::MULTI_ASSIGNMENTS_INFO, + crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO, crate::mut_key::MUTABLE_KEY_TYPE_INFO, crate::mut_mut::MUT_MUT_INFO, crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 03460689e19..f806ba238c7 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { ExprKind::MethodCall(_, receiver, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { - let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); + let fn_sig = self.cx.tcx.fn_sig(def_id).subst_identity().skip_binder(); for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { self.ty_bounds.push((*bound).into()); self.visit_expr(expr); @@ -215,7 +215,7 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<' let node_ty = cx.typeck_results().node_type_opt(hir_id)?; // We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs. match node_ty.kind() { - ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)), + ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).subst_identity()), ty::FnPtr(fn_sig) => Some(*fn_sig), _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 05f2b92c037..6c333afacc6 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -759,7 +759,7 @@ fn walk_parents<'tcx>( }) if span.ctxt() == ctxt => { let output = cx .tcx - .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output()); + .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output()); Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) }, @@ -778,20 +778,20 @@ fn walk_parents<'tcx>( Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { ExprKind::Ret(_) => { - let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); + let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()); Some( if let Node::Expr( closure_expr @ Expr { kind: ExprKind::Closure(closure), .. }, - ) = cx.tcx.hir().get(owner_id) + ) = cx.tcx.hir().get_by_def_id(owner_id) { closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence) } else { let output = cx .tcx - .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output()); + .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output()); ty_auto_deref_stability(cx, output, precedence).position_for_result(cx) }, ) @@ -858,7 +858,7 @@ fn walk_parents<'tcx>( && let subs = cx .typeck_results() .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default() - && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { + && let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() { // Trait methods taking `&self` sub_ty } else { @@ -879,7 +879,7 @@ fn walk_parents<'tcx>( return Some(Position::MethodReceiver); } args.iter().position(|arg| arg.hir_id == child_id).map(|i| { - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1]; + let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1]; // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739 // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782 if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() { @@ -896,7 +896,7 @@ fn walk_parents<'tcx>( } else { ty_auto_deref_stability( cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)), + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)), precedence, ) .position_for_arg() @@ -1093,7 +1093,7 @@ fn needless_borrow_impl_arg_position<'tcx>( let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) }; - let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder(); let substs_with_expr_ty = cx .typeck_results() .node_substs(if let ExprKind::Call(callee, _) = parent.kind { @@ -1221,7 +1221,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { .in_definition_order() .any(|assoc_item| { if assoc_item.fn_has_self_parameter { - let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0]; + let self_ty = cx.tcx.fn_sig(assoc_item.def_id).subst_identity().skip_binder().inputs()[0]; matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut)) } else { false @@ -1419,6 +1419,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc | ty::FnDef(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Closure(..) | ty::Never | ty::Tuple(_) diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 248d7388410..f8fc726d603 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::{ - self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource, + self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, Unsafety, }; use rustc_lint::{LateContext, LateLintPass}; @@ -18,6 +18,7 @@ use rustc_middle::ty::{ TraitPredicate, Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::sym; @@ -425,7 +426,7 @@ struct UnsafeVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) { + fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) { if self.has_unsafe { return; } diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index cdc23a4d227..127201b72e2 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -23,7 +23,6 @@ use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span}; use rustc_span::{sym, FileName, Pos}; @@ -251,7 +250,7 @@ declare_clippy_lint! { /// unimplemented!(); /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub UNNECESSARY_SAFETY_DOC, restriction, "`pub fn` or `pub trait` with `# Safety` docs" @@ -302,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { panic_span: None, }; fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span); + lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); } }, hir::ItemKind::Impl(impl_) => { @@ -338,7 +337,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return }; if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { if !in_external_macro(cx.tcx.sess, item.span) { - lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None); + lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None); } } } @@ -357,20 +356,20 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { panic_span: None, }; fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span); + lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); } } } fn lint_for_missing_headers( cx: &LateContext<'_>, - def_id: LocalDefId, + owner_id: hir::OwnerId, sig: &hir::FnSig<'_>, headers: DocHeaders, body_id: Option<hir::BodyId>, panic_span: Option<Span>, ) { - if !cx.effective_visibilities.is_exported(def_id) { + if !cx.effective_visibilities.is_exported(owner_id.def_id) { return; // Private functions do not require doc comments } @@ -378,13 +377,13 @@ fn lint_for_missing_headers( if cx .tcx .hir() - .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id)) + .parent_iter(owner_id.into()) .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) { return; } - let span = cx.tcx.def_span(def_id); + let span = cx.tcx.def_span(owner_id); match (headers.safety, sig.header.unsafety) { (false, hir::Unsafety::Unsafe) => span_lint( cx, @@ -411,8 +410,7 @@ fn lint_for_missing_headers( ); } if !headers.errors { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) { + if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { span_lint( cx, MISSING_ERRORS_DOC, diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index b77b5621b4c..4c69dacf381 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -277,7 +277,7 @@ impl LateLintPass<'_> for EnumVariantNames { Some(c) if is_word_beginning(c) => span_lint( cx, MODULE_NAME_REPETITIONS, - item.span, + item.ident.span, "item name starts with its containing module's name", ), _ => (), @@ -287,7 +287,7 @@ impl LateLintPass<'_> for EnumVariantNames { span_lint( cx, MODULE_NAME_REPETITIONS, - item.span, + item.ident.span, "item name ends with its containing module's name", ); } diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index dfb43893326..d6ab4c25e83 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -8,6 +8,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::symbol::kw; use rustc_target::spec::abi::Abi; @@ -63,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { _: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, _: Span, - hir_id: HirId, + fn_def_id: LocalDefId, ) { if let Some(header) = fn_kind.header() { if header.abi != Abi::Rust { @@ -71,7 +72,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { } } - let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id; + let parent_id = cx + .tcx + .hir() + .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id)) + .def_id; let parent_node = cx.tcx.hir().find_by_def_id(parent_id); let mut trait_self_ty = None; @@ -84,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { // find `self` ty for this trait if relevant if let ItemKind::Trait(_, _, _, _, items) = item.kind { for trait_item in items { - if trait_item.id.hir_id() == hir_id { + if trait_item.id.owner_id.def_id == fn_def_id { // be sure we have `self` parameter in this function if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { trait_self_ty = Some( @@ -105,7 +110,6 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { too_large_for_stack: self.too_large_for_stack, }; - let fn_def_id = cx.tcx.hir().local_def_id(hir_id); let infcx = cx.tcx.infer_ctxt().build(); ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index fc2912f696e..9d089fcad70 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool}; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, FnDecl, HirId, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; +use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -168,8 +169,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { fn_decl: &'tcx FnDecl<'tcx>, _: &'tcx Body<'tcx>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust && get_parent_as_impl(cx.tcx, hir_id) diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 1fece5d1c48..9fd13084dc9 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -79,8 +79,7 @@ impl LateLintPass<'_> for ExhaustiveItems { then { let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind { if v.fields().iter().any(|f| { - let def_id = cx.tcx.hir().local_def_id(f.hir_id); - !cx.tcx.visibility(def_id).is_public() + !cx.tcx.visibility(f.def_id).is_public() }) { // skip structs with private fields return; diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 043112bbc95..d376ad3bfe3 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -7,14 +7,14 @@ use clippy_utils::macros::{ }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; use itertools::Itertools; use rustc_errors::{ Applicability, SuggestionStyle::{CompletelyHidden, ShowCode}, }; -use rustc_hir::{Expr, ExprKind, HirId, QPath}; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; @@ -237,7 +237,7 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { ); } - if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() { + if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() { span_lint_and_then( cx, UNUSED_FORMAT_SPECS, @@ -311,6 +311,10 @@ fn check_uninlined_args( // in those cases, make the code suggestion hidden let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span)); + // Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`. + fixes.sort_unstable_by_key(|(span, _)| *span); + fixes.dedup_by_key(|(span, _)| *span); + span_lint_and_then( cx, UNINLINED_FORMAT_ARGS, diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index 00f5ba56496..096508dc4f1 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// let _ = unsafe { Box::from_raw(ptr as *mut usize) }; /// ``` /// - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub FROM_RAW_WITH_VOID_PTR, suspicious, "creating a `Box` from a void raw pointer" diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs index 27acad45ccf..d6b50537c2e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs +++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_errors::Applicability; -use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, HirId, ImplicitSelfKind, Unsafety}; +use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; @@ -16,7 +16,6 @@ pub fn check_fn( decl: &FnDecl<'_>, body: &Body<'_>, span: Span, - _hir_id: HirId, ) { let FnKind::Method(ref ident, sig) = kind else { return; diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 9dbce3f889b..4399c68e130 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -9,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; declare_clippy_lint! { @@ -363,12 +364,13 @@ impl<'tcx> LateLintPass<'tcx> for Functions { decl: &'tcx hir::FnDecl<'_>, body: &'tcx hir::Body<'_>, span: Span, - hir_id: hir::HirId, + def_id: LocalDefId, ) { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold); too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); - not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id); - misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id); + not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); + misnamed_getters::check_fn(cx, kind, decl, body, span); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index d22bede36b4..29bdc46b647 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -1,6 +1,6 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; -use rustc_hir::def_id::{DefIdSet, LocalDefId}; +use rustc_hir::def_id::DefIdSet; use rustc_hir::{self as hir, def::Res, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::{ @@ -27,14 +27,14 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, sig.decl, cx.tcx.hir().body(*body_id), item.span, - item.owner_id.def_id, + item.owner_id, item.span.with_hi(sig.decl.output.span().hi()), "this function could have a `#[must_use]` attribute", ); @@ -49,7 +49,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() @@ -59,7 +59,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp sig.decl, cx.tcx.hir().body(*body_id), item.span, - item.owner_id.def_id, + item.owner_id, item.span.with_hi(sig.decl.output.span().hi()), "this method could have a `#[must_use]` attribute", ); @@ -75,7 +75,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { @@ -84,7 +84,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr sig.decl, body, item.span, - item.owner_id.def_id, + item.owner_id, item.span.with_hi(sig.decl.output.span().hi()), "this method could have a `#[must_use]` attribute", ); @@ -96,7 +96,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr fn check_needless_must_use( cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, - item_id: hir::HirId, + item_id: hir::OwnerId, item_span: Span, fn_header_span: Span, attr: &Attribute, @@ -131,7 +131,7 @@ fn check_must_use_candidate<'tcx>( decl: &'tcx hir::FnDecl<'_>, body: &'tcx hir::Body<'_>, item_span: Span, - item_id: LocalDefId, + item_id: hir::OwnerId, fn_span: Span, msg: &str, ) { @@ -139,8 +139,8 @@ fn check_must_use_candidate<'tcx>( || mutates_static(cx, body) || in_external_macro(cx.sess(), item_span) || returns_unit(decl) - || !cx.effective_visibilities.is_exported(item_id) - || is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id))) + || !cx.effective_visibilities.is_exported(item_id.def_id) + || is_must_use_ty(cx, return_ty(cx, item_id)) { return; } diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 2c0bf551fd7..a13909a2cdb 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -17,7 +17,7 @@ pub(super) fn check_fn<'tcx>( kind: intravisit::FnKind<'tcx>, decl: &'tcx hir::FnDecl<'tcx>, body: &'tcx hir::Body<'tcx>, - hir_id: hir::HirId, + def_id: LocalDefId, ) { let unsafety = match kind { intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety, @@ -25,7 +25,7 @@ pub(super) fn check_fn<'tcx>( intravisit::FnKind::Closure => return, }; - check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id)); + check_raw_ptr(cx, unsafety, decl, body, def_id) } pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { @@ -58,7 +58,7 @@ fn check_raw_ptr<'tcx>( }, hir::ExprKind::MethodCall(_, recv, args, _) => { let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap(); - if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe { + if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().unsafety == hir::Unsafety::Unsafe { check_arg(cx, &raw_ptrs, recv); for arg in args { check_arg(cx, &raw_ptrs, arg); diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 23da145d038..fa2a9b30c05 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -21,7 +21,7 @@ fn result_err_ty<'tcx>( ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !in_external_macro(cx.sess(), item_span) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output()) + && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().output()) && is_type_diagnostic_item(cx, ty, sym::Result) && let ty::Adt(_, substs) = ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 989f83cf80d..9fb73a371b8 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::return_ty; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, FnDecl, HirId}; +use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::{self, FulfillmentError}; @@ -56,12 +57,12 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { decl: &'tcx FnDecl<'tcx>, _: &'tcx Body<'tcx>, _: Span, - hir_id: HirId, + fn_def_id: LocalDefId, ) { if let FnKind::Closure = kind { return; } - let ret_ty = return_ty(cx, hir_id); + let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner()); if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; @@ -78,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); - let cause = traits::ObligationCause::misc(span, hir_id); + let cause = traits::ObligationCause::misc(span, fn_def_id); let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait); if !send_errors.is_empty() { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index 946d04eff6f..372b6ead3fe 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -11,6 +11,7 @@ use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { @@ -223,7 +224,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - _: HirId, + _: LocalDefId, ) { if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_))) || span.ctxt() != body.value.span.ctxt() diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index aaecc4fa8f2..d43e5cc9b2c 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })); // Check if return type is String - if is_type_lang_item(cx, return_ty(cx, impl_item.hir_id()), LangItem::String); + if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String); // Filters instances of to_string which are required by a trait if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none(); @@ -124,7 +124,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { .expect("Failed to get trait ID of `Display`!"); // Get the real type of 'self' - let self_type = cx.tcx.fn_sig(item.owner_id).input(0); + let self_type = cx.tcx.fn_sig(item.owner_id).skip_binder().input(0); let self_type = self_type.skip_binder().peel_refs(); // Emit either a warning or an error diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 9f6e8940571..668110c7cc0 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { /// /// [`Duration`]: std::time::Duration /// [`Instant::now()`]: std::time::Instant::now; - #[clippy::version = "1.65.0"] + #[clippy::version = "1.67.0"] pub UNCHECKED_DURATION_SUBTRACTION, pedantic, "finds unchecked subtraction of a 'Duration' from an 'Instant'" diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index e76de77f195..7557a9ce13f 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) { if sig.decl.implicit_self.has_implicit_self() { - let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).output()); + let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output()); let ret_ty = cx .tcx .try_normalize_erasing_regions(cx.param_env, ret_ty) diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 3c70c9cf19a..80ed2862a41 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let Some(local_id) = ty_id.as_local(); let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id); if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id); - if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder()); + if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder()); then { let (name, kind) = match cx.tcx.hir().find(ty_hir_id) { Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"), @@ -196,7 +196,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool { item.ident.name == name && if let AssocItemKind::Fn { has_self } = item.kind { - has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 } + has_self && { cx.tcx.fn_sig(item.id.owner_id).skip_binder().inputs().skip_binder().len() == 1 } } else { false } @@ -224,7 +224,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items .any(|i| { i.kind == ty::AssocKind::Fn && i.fn_has_self_parameter - && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1 + && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 }); if !is_empty_method_found { @@ -342,7 +342,7 @@ fn check_for_is_empty<'tcx>( ), Some(is_empty) if !(is_empty.fn_has_self_parameter - && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) => + && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(), self_kind, output)) => { ( format!( @@ -473,7 +473,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { if item.kind == ty::AssocKind::Fn { - let sig = cx.tcx.fn_sig(item.def_id); + let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let ty = sig.skip_binder(); ty.inputs().len() == 1 } else { diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 61f87b91400..f8e35950980 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -84,7 +84,7 @@ declare_clippy_lint! { /// let _ = foo().await; /// # } /// ``` - #[clippy::version = "1.66"] + #[clippy::version = "1.67.0"] pub LET_UNDERSCORE_FUTURE, suspicious, "non-binding `let` on a future" diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index d8e2ae02c5a..d0683039776 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,7 +1,6 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(iter_intersperse)] #![feature(let_chains)] @@ -198,6 +197,7 @@ mod missing_trait_methods; mod mixed_read_write_in_expression; mod module_style; mod multi_assignments; +mod multiple_unsafe_ops_per_block; mod mut_key; mod mut_mut; mod mut_reference; @@ -908,6 +908,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); + store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 7cf1a6b8084..747a94ba5a6 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -15,7 +15,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter as middle_nested_filter; -use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -154,7 +153,7 @@ fn check_fn_inner<'tcx>( .filter(|param| matches!(param.kind, GenericParamKind::Type { .. })); for typ in types { - for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) { + for pred in generics.bounds_for_param(typ.def_id) { if pred.origin == PredicateOrigin::WhereClause { // has_where_lifetimes checked that this predicate contains no lifetime. continue; @@ -251,7 +250,7 @@ fn could_use_elision<'tcx>( // level of the current item. // check named LTs - let allowed_lts = allowed_lts_from(cx.tcx, named_generics); + let allowed_lts = allowed_lts_from(named_generics); // these will collect all the lifetimes for references in arg/return types let mut input_visitor = RefVisitor::new(cx); @@ -360,11 +359,11 @@ fn could_use_elision<'tcx>( } } -fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> { +fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> { let mut allowed_lts = FxHashSet::default(); for par in named_generics.iter() { if let GenericParamKind::Lifetime { .. } = par.kind { - allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id))); + allowed_lts.insert(RefLt::Named(par.def_id)); } } allowed_lts.insert(RefLt::Unnamed); @@ -516,7 +515,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ return true; } // if the bounds define new lifetimes, they are fine to occur - let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params); + let allowed_lts = allowed_lts_from(pred.bound_generic_params); // now walk the bounds for bound in pred.bounds.iter() { walk_param_bound(&mut visitor, bound); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 3bca93d80aa..e6ed4ea7a5d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { ExprKind::MethodCall(_, receiver, args, _) => { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); for (ty, expr) in iter::zip( - self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), + self.cx.tcx.fn_sig(def_id).subst_identity().inputs().skip_binder(), std::iter::once(receiver).chain(args.iter()), ) { self.prefer_mutable = false; diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 63212beaa63..3778eb4c732 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -6,10 +6,11 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, - HirId, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, + ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - _: HirId, + _: LocalDefId, ) { if_chain! { if let Some(header) = kind.header(); diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index d9ef7dffa02..2fd32c009ea 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// 'A'.is_ascii_uppercase(); /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub MANUAL_IS_ASCII_CHECK, style, "use dedicated method to check ascii range" diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index bca193be9e7..9a84068d448 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -157,11 +157,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { && def.variants.len() > 1 { let mut iter = def.variants.iter().filter_map(|v| { - let id = cx.tcx.hir().local_def_id(v.hir_id); - (matches!(v.data, hir::VariantData::Unit(..)) + (matches!(v.data, hir::VariantData::Unit(_, _)) && v.ident.as_str().starts_with('_') && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) - .then_some((id, v.span)) + .then_some((v.def_id, v.span)) }); if let Some((id, span)) = iter.next() && iter.next().is_none() diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 59195d1ae4e..edcab6968cb 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -104,7 +104,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); if let ty::FnDef(id, _) = *ty.kind() { - if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() { + if let Some(fn_type) = cx.tcx.fn_sig(id).subst_identity().no_bound_vars() { return is_unit_type(fn_type.output()); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs index ac61b437788..5e01ed90ff0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs @@ -54,7 +54,7 @@ fn collect_replace_calls<'tcx>( from_args.push_front(from); ControlFlow::Continue(()) } else { - ControlFlow::BREAK + ControlFlow::Break(()) } } else { ControlFlow::Continue(()) diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index a9189b31c57..aed0ad5d9b5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -70,7 +70,7 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Path(ref p) = fun.kind { match cx.qpath_res(p, fun.hir_id) { hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( - cx.tcx.fn_sig(def_id).output().skip_binder().kind(), + cx.tcx.fn_sig(def_id).subst_identity().output().skip_binder().kind(), ty::Ref(re, ..) if re.is_static(), ), _ => false, @@ -84,7 +84,7 @@ pub(super) fn check<'tcx>( .type_dependent_def_id(arg.hir_id) .map_or(false, |method_id| { matches!( - cx.tcx.fn_sig(method_id).output().skip_binder().kind(), + cx.tcx.fn_sig(method_id).subst_identity().output().skip_binder().kind(), ty::Ref(re, ..) if re.is_static() ) }) diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 77be61b4793..fb94dfa5980 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -3102,7 +3102,7 @@ declare_clippy_lint! { /// Ok(()) /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub SEEK_FROM_CURRENT, complexity, "use dedicated method for seek from current position" @@ -3133,7 +3133,7 @@ declare_clippy_lint! { /// t.rewind(); /// } /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub SEEK_TO_START_INSTEAD_OF_REWIND, complexity, "jumping to the start of stream using `seek` method" @@ -3352,7 +3352,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind { - let method_sig = cx.tcx.fn_sig(impl_item.owner_id); + let method_sig = cx.tcx.fn_sig(impl_item.owner_id).subst_identity(); let method_sig = cx.tcx.erase_late_bound_regions(method_sig); let first_arg_ty_opt = method_sig.inputs().iter().next().copied(); // if this impl block implements a trait, lint in trait definition instead @@ -3412,7 +3412,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } if let hir::ImplItemKind::Fn(_, _) = impl_item.kind { - let ret_ty = return_ty(cx, impl_item.hir_id()); + let ret_ty = return_ty(cx, impl_item.owner_id); if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) { return; @@ -3460,7 +3460,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if_chain! { if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; - let ret_ty = return_ty(cx, item.hir_id()); + let ret_ty = return_ty(cx, item.owner_id); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) .self_ty() .skip_binder(); diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index f4d3ef3b742..82d3b830d4f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -137,7 +137,7 @@ pub(super) fn check<'tcx>( /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { - let sig = cx.tcx.fn_sig(id).skip_binder(); + let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder(); sig.inputs().len() == 1 && sig.output().is_bool() }) } @@ -165,7 +165,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool { let typeck = cx.typeck_results(); if let Some(id) = typeck.type_dependent_def_id(call_id) - && let sig = cx.tcx.fn_sig(id) + && let sig = cx.tcx.fn_sig(id).subst_identity() && sig.skip_binder().output().is_bool() && let [_, search_ty] = *sig.skip_binder().inputs() && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind() diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs index 2ac0786b37b..0dc7fe2a2c5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs @@ -11,10 +11,8 @@ use super::SUSPICIOUS_MAP; pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, count_recv, sym::Iterator); - let closure = expr_or_init(cx, map_arg); - if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id); - if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id); - let closure_body = cx.tcx.hir().body(body_id); + if let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind; + let closure_body = cx.tcx.hir().body(closure.body); if !cx.typeck_results().expr_ty(closure_body.value).is_unit(); then { if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 9263f051972..4e5af1c7c71 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -246,7 +246,7 @@ fn check_other_call_arg<'tcx>( if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call); - let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder(); if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id); if let Some(input) = fn_sig.inputs().get(i); let (input, n_refs) = peel_mid_ty_refs(*input); @@ -368,10 +368,9 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Block(..) => continue, Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind - && let output_ty = return_ty(cx, item.hir_id()) - && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id()) - && Inherited::build(cx.tcx, local_def_id).enter(|inherited| { - let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id()); + && let output_ty = return_ty(cx, item.owner_id) + && Inherited::build(cx.tcx, item.owner_id.def_id).enter(|inherited| { + let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.owner_id.def_id); fn_ctxt.can_coerce(ty, output_ty) }) { if has_lifetime(output_ty) && has_lifetime(ty) { @@ -386,7 +385,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Expr(parent_expr) => { if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr) { - let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) && let Some(param_ty) = fn_sig.inputs().get(arg_index) && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 9f4beb92b9d..0705029a613 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -4,12 +4,13 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, - Stmt, StmtKind, TyKind, + self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, Stmt, + StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; @@ -151,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - _: HirId, + _: LocalDefId, ) { if let FnKind::Closure = k { // Does not apply to closures diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 5bc04bc17fb..87bd007a26a 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -6,11 +6,12 @@ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_ma use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; +use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; declare_clippy_lint! { @@ -91,14 +92,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { _: &FnDecl<'_>, body: &Body<'tcx>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { if !self.msrv.meets(msrvs::CONST_IF_MATCH) { return; } - let def_id = cx.tcx.hir().local_def_id(hir_id); - if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) { return; } @@ -132,6 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Closure => return, } + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + // Const fns are not allowed as methods in a trait. { let parent = cx.tcx.hir().get_parent_item(hir_id).def_id; diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 3371b4cce32..e99081ad062 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { "implement the method", ); } - }) + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs new file mode 100644 index 00000000000..2814c92e67a --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -0,0 +1,185 @@ +use clippy_utils::{ + diagnostics::span_lint_and_then, + visitors::{for_each_expr_with_closures, Descend, Visitable}, +}; +use core::ops::ControlFlow::Continue; +use hir::{ + def::{DefKind, Res}, + BlockCheckMode, ExprKind, QPath, UnOp, Unsafety, +}; +use rustc_ast::Mutability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `unsafe` blocks that contain more than one unsafe operation. + /// + /// ### Why is this bad? + /// Combined with `undocumented_unsafe_blocks`, + /// this lint ensures that each unsafe operation must be independently justified. + /// Combined with `unused_unsafe`, this lint also ensures + /// elimination of unnecessary unsafe blocks through refactoring. + /// + /// ### Example + /// ```rust + /// /// Reads a `char` from the given pointer. + /// /// + /// /// # Safety + /// /// + /// /// `ptr` must point to four consecutive, initialized bytes which + /// /// form a valid `char` when interpreted in the native byte order. + /// fn read_char(ptr: *const u8) -> char { + /// // SAFETY: The caller has guaranteed that the value pointed + /// // to by `bytes` is a valid `char`. + /// unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } + /// } + /// ``` + /// Use instead: + /// ```rust + /// /// Reads a `char` from the given pointer. + /// /// + /// /// # Safety + /// /// + /// /// - `ptr` must be 4-byte aligned, point to four consecutive + /// /// initialized bytes, and be valid for reads of 4 bytes. + /// /// - The bytes pointed to by `ptr` must represent a valid + /// /// `char` when interpreted in the native byte order. + /// fn read_char(ptr: *const u8) -> char { + /// // SAFETY: `ptr` is 4-byte aligned, points to four consecutive + /// // initialized bytes, and is valid for reads of 4 bytes. + /// let int_value = unsafe { *ptr.cast::<u32>() }; + /// + /// // SAFETY: The caller has guaranteed that the four bytes + /// // pointed to by `bytes` represent a valid `char`. + /// unsafe { char::from_u32_unchecked(int_value) } + /// } + /// ``` + #[clippy::version = "1.68.0"] + pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, + restriction, + "more than one unsafe operation per `unsafe` block" +} +declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]); + +impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { + if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) { + return; + } + let mut unsafe_ops = vec![]; + collect_unsafe_exprs(cx, block, &mut unsafe_ops); + if unsafe_ops.len() > 1 { + span_lint_and_then( + cx, + MULTIPLE_UNSAFE_OPS_PER_BLOCK, + block.span, + &format!( + "this `unsafe` block contains {} unsafe operations, expected only one", + unsafe_ops.len() + ), + |diag| { + for (msg, span) in unsafe_ops { + diag.span_note(span, msg); + } + }, + ); + } + } +} + +fn collect_unsafe_exprs<'tcx>( + cx: &LateContext<'tcx>, + node: impl Visitable<'tcx>, + unsafe_ops: &mut Vec<(&'static str, Span)>, +) { + for_each_expr_with_closures(cx, node, |expr| { + match expr.kind { + ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), + + ExprKind::Field(e, _) => { + if cx.typeck_results().expr_ty(e).is_union() { + unsafe_ops.push(("union field access occurs here", expr.span)); + } + }, + + ExprKind::Path(QPath::Resolved( + _, + hir::Path { + res: Res::Def(DefKind::Static(Mutability::Mut), _), + .. + }, + )) => { + unsafe_ops.push(("access of a mutable static occurs here", expr.span)); + }, + + ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_unsafe_ptr() => { + unsafe_ops.push(("raw pointer dereference occurs here", expr.span)); + }, + + ExprKind::Call(path_expr, _) => match path_expr.kind { + ExprKind::Path(QPath::Resolved( + _, + hir::Path { + res: Res::Def(kind, def_id), + .. + }, + )) if kind.is_fn_like() => { + let sig = cx.tcx.fn_sig(*def_id); + if sig.0.unsafety() == Unsafety::Unsafe { + unsafe_ops.push(("unsafe function call occurs here", expr.span)); + } + }, + + ExprKind::Path(QPath::TypeRelative(..)) => { + if let Some(sig) = cx + .typeck_results() + .type_dependent_def_id(path_expr.hir_id) + .map(|def_id| cx.tcx.fn_sig(def_id)) + { + if sig.0.unsafety() == Unsafety::Unsafe { + unsafe_ops.push(("unsafe function call occurs here", expr.span)); + } + } + }, + + _ => {}, + }, + + ExprKind::MethodCall(..) => { + if let Some(sig) = cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .map(|def_id| cx.tcx.fn_sig(def_id)) + { + if sig.0.unsafety() == Unsafety::Unsafe { + unsafe_ops.push(("unsafe method call occurs here", expr.span)); + } + } + }, + + ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => { + if matches!( + lhs.kind, + ExprKind::Path(QPath::Resolved( + _, + hir::Path { + res: Res::Def(DefKind::Static(Mutability::Mut), _), + .. + } + )) + ) { + unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); + collect_unsafe_exprs(cx, rhs, unsafe_ops); + return Continue(Descend::No); + } + }, + + _ => {}, + }; + + Continue::<(), _>(Descend::Yes) + }); +} diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index a651020ca65..5f7aac21e6e 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::symbol::sym; use std::iter; @@ -102,21 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { if let hir::ItemKind::Fn(ref sig, ..) = item.kind { - self.check_sig(cx, item.hir_id(), sig.decl); + self.check_sig(cx, item.owner_id.def_id, sig.decl); } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) { if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind { if trait_ref_of_method(cx, item.owner_id.def_id).is_none() { - self.check_sig(cx, item.hir_id(), sig.decl); + self.check_sig(cx, item.owner_id.def_id, sig.decl); } } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) { if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { - self.check_sig(cx, item.hir_id(), sig.decl); + self.check_sig(cx, item.owner_id.def_id, sig.decl); } } @@ -136,9 +137,8 @@ impl MutableKeyType { } } - fn check_sig(&self, cx: &LateContext<'_>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) { - let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id); - let fn_sig = cx.tcx.fn_sig(fn_def_id); + fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity(); for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { self.check_ty_(cx, hir_ty.span, *ty); } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 8c9d4c5cfe6..996ea6ed723 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -20,6 +20,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; @@ -82,12 +83,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - hir_id: HirId, + fn_def_id: LocalDefId, ) { if span.from_expansion() { return; } + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id); + match kind { FnKind::ItemFn(.., header) => { let attrs = cx.tcx.hir().attrs(hir_id); @@ -119,8 +122,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let sized_trait = need!(cx.tcx.lang_items().sized_trait()); - let fn_def_id = cx.tcx.hir().local_def_id(hir_id); - let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) .filter_map(|obligation| { @@ -147,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ctx }; - let fn_sig = cx.tcx.fn_sig(fn_def_id); + let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity(); let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig); for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() { diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 54a3c82b713..faf9ec61ec5 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { } if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind { let name = impl_item.ident.name; - let id = impl_item.hir_id(); + let id = impl_item.owner_id; if sig.header.constness == hir::Constness::Const { // can't be implemented by default return; @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { if sig.decl.inputs.is_empty(); if name == sym::new; if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id); - let self_def_id = cx.tcx.hir().get_parent_item(id); + let self_def_id = cx.tcx.hir().get_parent_item(id.into()); let self_ty = cx.tcx.type_of(self_def_id); if self_ty == return_ty(cx, id); if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { span_lint_hir_and_then( cx, NEW_WITHOUT_DEFAULT, - id, + id.into(), impl_item.span, &format!( "you should consider adding a `Default` implementation for `{self_type_snip}`" diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 7b1d974f2f8..8b77a5c99f7 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdMap; use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{kw, Ident}; @@ -244,7 +244,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { })) => { #[allow(trivial_casts)] if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into()) - && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(|t| t.subst_identity()) + && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity) && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id { ( diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index cff82b875f1..d592f6e814c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -209,7 +209,8 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { let body_owner = cx.tcx.hir().body_owner(body.id()); - let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner); + let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id()); + let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind { let body_span = cx.tcx.hir().span_with_body(body_owner); diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 0830a106f55..777395f452c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -96,7 +96,7 @@ impl Context { pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { let body_owner = cx.tcx.hir().body_owner(body.id()); - let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner); + let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id()); match cx.tcx.hir().body_owner_kind(body_owner_def_id) { hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => { diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index efec12489a9..849cd03dd7b 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -8,6 +8,7 @@ use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -49,9 +50,13 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { _: &'tcx hir::FnDecl<'tcx>, body: &'tcx hir::Body<'tcx>, span: Span, - hir_id: hir::HirId, + def_id: LocalDefId, ) { - if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) { + if matches!(fn_kind, FnKind::Closure) { + return; + } + let owner = cx.tcx.hir().local_def_id_to_hir_id(def_id).expect_owner(); + if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) { lint_impl_body(cx, span, body); } } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 2d21aaa4f7f..0d78c3048ba 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; -use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; +use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCast}; use rustc_middle::ty::layout::LayoutOf; @@ -143,7 +143,7 @@ impl<'tcx> PassByRefOrValue { return; } - let fn_sig = cx.tcx.fn_sig(def_id); + let fn_sig = cx.tcx.fn_sig(def_id).subst_identity(); let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id)); // Gather all the lifetimes found in the output type which may affect whether @@ -272,12 +272,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { decl: &'tcx FnDecl<'_>, _body: &'tcx Body<'_>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { if span.from_expansion() { return; } + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); match kind { FnKind::ItemFn(.., header) => { if header.abi != Abi::Rust { @@ -308,6 +309,6 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } } - self.check_poly_fn(cx, cx.tcx.hir().local_def_id(hir_id), decl, Some(span)); + self.check_poly_fn(cx, def_id, decl, Some(span)); } } diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 97b5a4ce364..9f98195d311 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{ - intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, -}; +use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; declare_clippy_lint! { @@ -116,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { _: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, _: Span, - _: HirId, + _: LocalDefId, ) { for param in body.params { apply_lint(cx, param.pat, DerefPossible::Impossible); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 26295304258..8afe286fbd5 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { check_mut_from_ref(cx, sig, None); for arg in check_fn_args( cx, - cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(), + cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(), sig.decl.inputs, &[], ) @@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { check_mut_from_ref(cx, sig, Some(body)); let decl = sig.decl; - let sig = cx.tcx.fn_sig(item_id).skip_binder(); + let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder(); let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params) .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not) .collect(); @@ -624,7 +624,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: return; }; - match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() { + match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i].peel_refs().kind() { ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => { set_skip_flag(); }, diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index c1677fb3da1..944a33cc3e5 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -6,11 +6,12 @@ use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem}; +use rustc_hir::{def_id, Body, FnDecl, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::{BytePos, Span}; use rustc_span::sym; @@ -69,12 +70,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { cx: &LateContext<'tcx>, _: FnKind<'tcx>, _: &'tcx FnDecl<'_>, - body: &'tcx Body<'_>, + _: &'tcx Body<'_>, _: Span, - _: HirId, + def_id: LocalDefId, ) { - let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - // Building MIR for `fn`s with unsatisfiable preds results in ICE. if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) { return; diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index b77faf7322b..8c39b4fc569 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_must_use_ty; use clippy_utils::{nth_arg, return_ty}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind}; +use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -68,7 +68,7 @@ declare_clippy_lint! { declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]); -fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) { +fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) { if_chain! { // If it comes from an external macro, better ignore it. if !in_external_macro(cx.sess(), span); @@ -76,10 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa // We only show this warning for public exported methods. if cx.effective_visibilities.is_exported(fn_def); // We don't want to emit this lint if the `#[must_use]` attribute is already there. - if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use)); + if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)); if cx.tcx.visibility(fn_def.to_def_id()).is_public(); - let ret_ty = return_ty(cx, hir_id); - let self_arg = nth_arg(cx, hir_id, 0); + let ret_ty = return_ty(cx, owner_id.into()); + let self_arg = nth_arg(cx, owner_id.into(), 0); // If `Self` has the same type as the returned type, then we want to warn. // // For this check, we don't want to remove the reference on the returned type because if @@ -109,26 +109,26 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse { decl: &'tcx FnDecl<'tcx>, _: &'tcx Body<'tcx>, span: Span, - hir_id: HirId, + fn_def: LocalDefId, ) { if_chain! { // We are only interested in methods, not in functions or associated functions. if matches!(kind, FnKind::Method(_, _)); - if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id); if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id()); // We don't want this method to be te implementation of a trait because the // `#[must_use]` should be put on the trait definition directly. if cx.tcx.trait_id_of_impl(impl_def).is_none(); then { - check_method(cx, decl, fn_def, span, hir_id); + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def); + check_method(cx, decl, fn_def, span, hir_id.expect_owner()); } } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) { if let TraitItemKind::Fn(ref sig, _) = item.kind { - check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id()); + check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.owner_id); } } } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index bbbd9e4989e..84a0c6b9558 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,16 +1,17 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::visitors::{for_each_expr, Descend}; -use clippy_utils::{fn_def_id, path_to_local_id}; +use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi}; use core::ops::ControlFlow; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::{BytePos, Pos}; @@ -151,8 +152,8 @@ impl<'tcx> LateLintPass<'tcx> for Return { kind: FnKind<'tcx>, _: &'tcx FnDecl<'tcx>, body: &'tcx Body<'tcx>, - _: Span, - _: HirId, + sp: Span, + _: LocalDefId, ) { match kind { FnKind::Closure => { @@ -166,14 +167,14 @@ impl<'tcx> LateLintPass<'tcx> for Return { check_final_expr(cx, body.value, vec![], replacement); }, FnKind::ItemFn(..) | FnKind::Method(..) => { - check_block_return(cx, &body.value.kind, vec![]); + check_block_return(cx, &body.value.kind, sp, vec![]); }, } } } // if `expr` is a block, check if there are needless returns in it -fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec<Span>) { +fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) { if let ExprKind::Block(block, _) = expr_kind { if let Some(block_expr) = block.expr { check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty); @@ -183,12 +184,14 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, check_final_expr(cx, expr, semi_spans, RetReplacement::Empty); }, StmtKind::Semi(semi_expr) => { - let mut semi_spans_and_this_one = semi_spans; - // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382` - if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) { - semi_spans_and_this_one.push(semicolon_span); - check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty); + // Remove ending semicolons and any whitespace ' ' in between. + // Without `return`, the suggestion might not compile if the semicolon is retained + if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) { + let semi_span_to_remove = + span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi())); + semi_spans.push(semi_span_to_remove); } + check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty); }, _ => (), } @@ -231,9 +234,9 @@ fn check_final_expr<'tcx>( emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement); }, ExprKind::If(_, then, else_clause_opt) => { - check_block_return(cx, &then.kind, semi_spans.clone()); + check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone()); if let Some(else_clause) = else_clause_opt { - check_block_return(cx, &else_clause.kind, semi_spans); + check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans); } }, // a match expr, check all arms @@ -246,7 +249,7 @@ fn check_final_expr<'tcx>( } }, // if it's a whole block, check it - other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans), + other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans), } } @@ -288,6 +291,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) && cx .tcx .fn_sig(def_id) + .subst_identity() .skip_binder() .output() .walk() diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs index 71b387c66a3..3ce030cd721 100644 --- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs +++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id); - let ret_ty = return_ty(cx, impl_item.hir_id()); + let ret_ty = return_ty(cx, impl_item.owner_id); // Do not check trait impls if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) { diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs index 301aa5798bf..9c0dc8096d0 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// ### What it does /// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal. /// ### Why is this bad? - /// It's most probably a typo and may lead to unexpected behaviours. + /// It's most probably a typo and may lead to unexpected behaviours. /// ### Example /// ```rust /// let x = 3_i32 ^ 4_i32; @@ -18,7 +18,7 @@ declare_clippy_lint! { /// ```rust /// let x = 3_i32.pow(4); /// ``` - #[clippy::version = "1.66.0"] + #[clippy::version = "1.67.0"] pub SUSPICIOUS_XOR_USED_AS_POW, restriction, "XOR (`^`) operator possibly used as exponentiation operator" diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 63b326048a4..de0c5d56e41 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -61,8 +61,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_ if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind; // Then check if that that array zero-sized - let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); - let length = Const::from_anon_const(cx.tcx, length_ldid); + let length = Const::from_anon_const(cx.tcx, length.def_id); let length = length.try_eval_usize(cx.tcx, cx.param_env); if let Some(length) = length; then { diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 691d759d773..c0d290b5adc 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -479,7 +479,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { // - char conversions (https://github.com/rust-lang/rust/issues/89259) let const_context = in_constant(cx, e.hir_id); - let from_ty = cx.typeck_results().expr_ty_adjusted(arg); + let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) { + [] => (cx.typeck_results().expr_ty(arg), false), + [.., a] => (a.target, true), + }; // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them. let to_ty = cx.typeck_results().expr_ty(e); @@ -506,7 +509,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { ); if !linted { - transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg); + transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg); } } } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index b79d4e915a2..8530b43243f 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,11 +1,11 @@ -use super::utils::can_be_expressed_as_pointer_cast; +use super::utils::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{cast::CastKind, Ty}; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. @@ -13,24 +13,40 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, + from_ty_adjusted: bool, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, ) -> bool { - if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) { - span_lint_and_then( - cx, - TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, - e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), - |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg = arg.as_ty(to_ty.to_string()).to_string(); - diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); - } - }, - ); - true - } else { - false - } + use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; + let mut app = Applicability::MachineApplicable; + let sugg = match check_cast(cx, e, from_ty, to_ty) { + Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { + Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) + .as_ty(to_ty.to_string()) + .to_string() + }, + Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) + .as_ty(to_ty.to_string()) + .to_string(), + + // The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't + // be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to + // a usize. + Some(PtrAddrCast) => format!( + "{} as {to_ty}", + Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty) + ), + _ => return false, + }; + + span_lint_and_sugg( + cx, + TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, + e.span, + &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), + "try", + sugg, + app, + ); + true } diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 49d863ec03f..cddaf9450ea 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -20,33 +20,21 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx } } -/// Check if the type conversion can be expressed as a pointer cast, instead of -/// a transmute. In certain cases, including some invalid casts from array -/// references to pointers, this may cause additional errors to be emitted and/or -/// ICE error messages. This function will panic if that occurs. -pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, -) -> bool { - use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; - matches!( - check_cast(cx, e, from_ty, to_ty), - Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) - ) -} - /// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> { +pub(super) fn check_cast<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option<CastKind> { let hir_id = e.hir_id; let local_def_id = hir_id.owner.def_id; Inherited::build(cx.tcx, local_def_id).enter(|inherited| { - let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id); + let fn_ctxt = FnCtxt::new(inherited, cx.param_env, local_def_id); // If we already have errors, we can't be sure we can pointer cast. assert!( diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 229478b7ce3..585e2075fa9 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -12,11 +12,12 @@ mod vec_box; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, + Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; declare_clippy_lint! { @@ -311,15 +312,27 @@ pub struct Types { impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]); impl<'tcx> LateLintPass<'tcx> for Types { - fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) { - let is_in_trait_impl = - if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) { - matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) - } else { - false - }; + fn check_fn( + &mut self, + cx: &LateContext<'_>, + _: FnKind<'_>, + decl: &FnDecl<'_>, + _: &Body<'_>, + _: Span, + def_id: LocalDefId, + ) { + let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id( + cx.tcx + .hir() + .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(def_id)) + .def_id, + ) { + matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) + } else { + false + }; - let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id)); + let is_exported = cx.effective_visibilities.is_exported(def_id); self.check_fn_decl( cx, @@ -381,7 +394,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { let is_exported = cx .effective_visibilities - .is_exported(cx.tcx.hir().local_def_id(field.hir_id)); + .is_exported(field.def_id); self.check_ty( cx, diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 2e1b6d8d4ea..2920684ade3 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -263,6 +263,18 @@ fn expr_has_unnecessary_safety_comment<'tcx>( expr: &'tcx hir::Expr<'tcx>, comment_pos: BytePos, ) -> Option<Span> { + if cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, ref node)| { + matches!( + node, + Node::Block(&Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }), + ) + }) { + return None; + } + // this should roughly be the reverse of `block_parents_have_safety_comment` if for_each_expr_with_closures(cx, expr, |expr| match expr.kind { hir::ExprKind::Block( diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index a138a4baa9b..289ca4e9bed 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -76,7 +76,7 @@ fn get_projection_pred<'tcx>( fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> { let mut args_to_check = Vec::new(); if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - let fn_sig = cx.tcx.fn_sig(def_id); + let fn_sig = cx.tcx.fn_sig(def_id).subst_identity(); let generics = cx.tcx.predicates_of(def_id); let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait()); let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord)); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index ce9ebad8c89..d6167a62169 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -156,7 +156,7 @@ fn needs_inferred_result_ty( }, _ => return false, }; - let sig = cx.tcx.fn_sig(id).skip_binder(); + let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder(); if let ty::Param(output_ty) = *sig.output().kind() { let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver { std::iter::once(receiver).chain(args.iter()).collect() diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 84ec0d0fb1c..8b0e0ce5a30 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -5,10 +5,11 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::{OptionSome, ResultOk}; -use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node}; +use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; @@ -77,12 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { fn_decl: &FnDecl<'tcx>, body: &Body<'tcx>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { // Abort if public function/method or closure. match fn_kind { FnKind::ItemFn(..) | FnKind::Method(..) => { - let def_id = cx.tcx.hir().local_def_id(hir_id); if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; } @@ -91,6 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } // Abort if the method is implementing a trait or of it a trait method. + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if matches!( item.kind, @@ -101,17 +102,18 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } // Get the wrapper and inner types, if can't, abort. - let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() { - if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) { - ("Option", OptionSome, subst.type_at(0)) - } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) { - ("Result", ResultOk, subst.type_at(0)) + let (return_type_label, lang_item, inner_type) = + if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id.expect_owner()).kind() { + if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) { + ("Option", OptionSome, subst.type_at(0)) + } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) { + ("Result", ResultOk, subst.type_at(0)) + } else { + return; + } } else { return; - } - } else { - return; - }; + }; // Check if all return expression respect the following condition and collect them. let mut suggs = Vec::new(); diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 3538bef6e06..55651a28be9 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, YieldSource}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; declare_clippy_lint! { @@ -66,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { fn_decl: &'tcx FnDecl<'tcx>, body: &Body<'tcx>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { if !span.from_expansion() && fn_kind.asyncness().is_async() { let mut visitor = AsyncFnVisitor { cx, found_await: false }; - walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id); + walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id); if !visitor.found_await { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index ea878043c04..377d3fb6f4e 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -11,6 +11,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; use rustc_span::sym; @@ -312,7 +313,7 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - fn_id: HirId, + fn_id: LocalDefId, ) { if span.from_expansion() { return; diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index f3611d17434..3a1845425a2 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -64,8 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { // first check if it's a method or function if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Result) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Option); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option); then { lint_impl_body(cx, impl_item.span, impl_item); } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 6ae9d9d6353..3cd35838961 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { .associated_item(impl_item.owner_id) .trait_item_def_id .expect("impl method matches a trait method"); - let trait_method_sig = cx.tcx.fn_sig(trait_method); + let trait_method_sig = cx.tcx.fn_sig(trait_method).subst_identity(); let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig); // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index c1589c771c4..f48be27592b 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -219,7 +219,8 @@ define_Conf! { /// /// #### Noteworthy /// - /// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. + /// A type, say `SomeType`, listed in this configuration has the same behavior of + /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c4d8c28f060..b1b5164ffb3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -14,6 +14,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths}; use if_chain::if_chain; +use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ @@ -34,8 +35,10 @@ use std::path::Path; use std::path::PathBuf; use std::process::Command; -/// This is the output file of the lint collector. -const OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; +/// This is the json output file of the lint collector. +const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; +/// This is the markdown output file of the lint collector. +const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md"; /// These lints are excluded from the export. const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"]; /// These groups will be ignored by the lint group matcher. This is useful for collections like @@ -176,6 +179,23 @@ This lint has the following configuration variables: ) }) } + + fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String { + self.config + .iter() + .filter(|config| config.deprecation_reason.is_none()) + .filter(|config| !config.lints.is_empty()) + .map(map_fn) + .join("\n") + } + + fn get_markdown_docs(&self) -> String { + format!( + "## Lint Configuration Options\n| <div style=\"width:290px\">Option</div> | Default Value |\n|--|--|\n{}\n\n{}\n", + self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry), + self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph), + ) + } } impl Drop for MetadataCollector { @@ -199,12 +219,37 @@ impl Drop for MetadataCollector { collect_renames(&mut lints); - // Outputting - if Path::new(OUTPUT_FILE).exists() { - fs::remove_file(OUTPUT_FILE).unwrap(); + // Outputting json + if Path::new(JSON_OUTPUT_FILE).exists() { + fs::remove_file(JSON_OUTPUT_FILE).unwrap(); } - let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap(); + let mut file = OpenOptions::new() + .write(true) + .create(true) + .open(JSON_OUTPUT_FILE) + .unwrap(); writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap(); + + // Outputting markdown + if Path::new(MARKDOWN_OUTPUT_FILE).exists() { + fs::remove_file(MARKDOWN_OUTPUT_FILE).unwrap(); + } + let mut file = OpenOptions::new() + .write(true) + .create(true) + .open(MARKDOWN_OUTPUT_FILE) + .unwrap(); + writeln!( + file, + "<!-- +This file is generated by `cargo collect-metadata`. +Please use that command to update the file and do not edit it by hand. +--> + +{}", + self.get_markdown_docs(), + ) + .unwrap(); } } @@ -505,6 +550,28 @@ impl ClippyConfiguration { deprecation_reason, } } + + fn to_markdown_paragraph(&self) -> String { + format!( + "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n", + self.name, + self.doc + .lines() + .map(|line| line.strip_prefix(" ").unwrap_or(line)) + .join("\n"), + self.default, + self.config_type, + self.lints + .iter() + .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) + .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) + .join("\n"), + ) + } + + fn to_markdown_table_entry(&self) -> String { + format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) + } } fn collect_configs() -> Vec<ClippyConfiguration> { diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index ac6a566b9cd..173469f6cdc 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.68" +version = "0.1.69" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 96711936968..5c89dd3e49f 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -79,7 +79,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) { // Limit the function to either `(self) -> bool` or `(&self) -> bool` - match &**cx.tcx.fn_sig(fn_id).skip_binder().inputs_and_output { + match &**cx.tcx.fn_sig(fn_id).subst_identity().skip_binder().inputs_and_output { [arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange, _ => Lazy, } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7a4a9036dd3..26f279f5585 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_chunks)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] @@ -1119,9 +1118,8 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap); } }, - ExprKind::Closure { .. } => { - let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id); - for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) { + ExprKind::Closure(closure) => { + for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) { let local_id = match capture.place.base { PlaceBase::Local(id) => id, PlaceBase::Upvar(var) => var.var_path.hir_id, @@ -1379,7 +1377,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>( .chain(args.iter()) .position(|arg| arg.hir_id == id)?; let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?; - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; + let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i]; ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(()) }, _ => None, @@ -1578,16 +1576,14 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { } /// Convenience function to get the return type of a function. -pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> { - let fn_def_id = cx.tcx.hir().local_def_id(fn_item); - let ret_ty = cx.tcx.fn_sig(fn_def_id).output(); +pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> { + let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output(); cx.tcx.erase_late_bound_regions(ret_ty) } /// Convenience function to get the nth argument type of a function. -pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> { - let fn_def_id = cx.tcx.hir().local_def_id(fn_item); - let arg = cx.tcx.fn_sig(fn_def_id).input(nth); +pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> { + let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth); cx.tcx.erase_late_bound_regions(arg) } @@ -2491,6 +2487,10 @@ pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { comments_buf.join("\n") } +pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { + sm.span_take_while(span, |&ch| ch == ' ' || ch == ';') +} + macro_rules! op_utils { ($($name:ident $assign:ident)*) => { /// Binary operation traits like `LangItem::Add` diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 77c5f115542..d7f466c1976 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -1,6 +1,5 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::is_path_diagnostic_item; use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; @@ -8,7 +7,7 @@ use arrayvec::ArrayVec; use itertools::{izip, Either, Itertools}; use rustc_ast::ast::LitKind; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath}; +use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind}; use rustc_lexer::unescape::unescape_literal; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lint::LateContext; @@ -328,7 +327,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> } else { match cx.tcx.item_name(macro_call.def_id) { // `cfg!(debug_assertions)` in `debug_assert!` - sym::cfg => ControlFlow::CONTINUE, + sym::cfg => ControlFlow::Continue(()), // assert!(other_macro!(..)) _ => ControlFlow::Break(true), } @@ -439,8 +438,7 @@ impl<'tcx> FormatArgsValues<'tcx> { // ArgumentV1::from_usize(<val>) if let ExprKind::Call(callee, [val]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind - && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind - && path.segments.last().unwrap().ident.name == sym::ArgumentV1 + && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind { let val_idx = if val.span.ctxt() == expr.span.ctxt() && let ExprKind::Field(_, field) = val.kind @@ -486,20 +484,6 @@ struct ParamPosition { impl<'tcx> Visitor<'tcx> for ParamPosition { fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { - fn parse_count(expr: &Expr<'_>) -> Option<usize> { - // ::core::fmt::rt::v1::Count::Param(1usize), - if let ExprKind::Call(ctor, [val]) = expr.kind - && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind - && path.segments.last()?.ident.name == sym::Param - && let ExprKind::Lit(lit) = &val.kind - && let LitKind::Int(pos, _) = lit.node - { - Some(pos as usize) - } else { - None - } - } - match field.ident.name { sym::position => { if let ExprKind::Lit(lit) = &field.expr.kind @@ -519,15 +503,41 @@ impl<'tcx> Visitor<'tcx> for ParamPosition { } } +fn parse_count(expr: &Expr<'_>) -> Option<usize> { + // <::core::fmt::rt::v1::Count>::Param(1usize), + if let ExprKind::Call(ctor, [val]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind + && path.ident.name == sym::Param + && let ExprKind::Lit(lit) = &val.kind + && let LitKind::Int(pos, _) = lit.node + { + Some(pos as usize) + } else { + None + } +} + /// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> { if let ExprKind::AddrOf(.., array) = fmt_arg.kind && let ExprKind::Array(specs) = array.kind { Some(specs.iter().map(|spec| { - let mut position = ParamPosition::default(); - position.visit_expr(spec); - position + if let ExprKind::Call(f, args) = spec.kind + && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind + && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind + && f.ident.name == sym::new + && let [position, _fill, _align, _flags, precision, width] = args + && let ExprKind::Lit(position) = &position.kind + && let LitKind::Int(position, _) = position.node { + ParamPosition { + value: position as usize, + width: parse_count(width), + precision: parse_count(precision), + } + } else { + ParamPosition::default() + } })) } else { None @@ -701,8 +711,8 @@ pub struct FormatSpec<'tcx> { pub fill: Option<char>, /// Optionally specified alignment. pub align: Alignment, - /// Packed version of various flags provided, see [`rustc_parse_format::Flag`]. - pub flags: u32, + /// Whether all flag options are set to default (no flags specified). + pub no_flags: bool, /// Represents either the maximum width or the integer precision. pub precision: Count<'tcx>, /// The minimum width, will be padded according to `width`/`align` @@ -718,7 +728,7 @@ impl<'tcx> FormatSpec<'tcx> { Some(Self { fill: spec.fill, align: spec.align, - flags: spec.flags, + no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(), precision: Count::new( FormatParamUsage::Precision, spec.precision, @@ -763,7 +773,7 @@ impl<'tcx> FormatSpec<'tcx> { self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown - && self.flags == 0 + && self.no_flags } } @@ -890,7 +900,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind - && is_path_diagnostic_item(cx, ty, sym::Arguments) + && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted") { let format_string = FormatString::new(cx, pieces)?; diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index 9adae773389..5836eb73bd9 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -140,7 +140,7 @@ impl TypeVisitor<'_> for ContainsRegion { type BreakTy = (); fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> { - ControlFlow::BREAK + ControlFlow::Break(()) } } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index e5d7da68281..72705878075 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -55,7 +55,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) // impl trait is gone in MIR, so check the return type manually check_ty( tcx, - tcx.fn_sig(def_id).output().skip_binder(), + tcx.fn_sig(def_id).subst_identity().output().skip_binder(), body.local_decls.iter().next().unwrap().source_info.span, )?; @@ -240,6 +240,7 @@ fn check_statement<'tcx>( | StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => Ok(()), } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index e7879bb196e..b8c87aa5e1e 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -219,6 +219,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Yeet(..) + | ast::ExprKind::FormatArgs(..) | ast::ExprKind::Struct(..) | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..) @@ -808,7 +809,7 @@ pub struct DerefClosure { /// /// note: this only works on single line immutable closures with exactly one input parameter. pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option<DerefClosure> { - if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind { + if let hir::ExprKind::Closure(&Closure { fn_decl, def_id, body, .. }) = closure.kind { let closure_body = cx.tcx.hir().body(body); // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`) // a type annotation is present if param `kind` is different from `TyKind::Infer` @@ -828,10 +829,8 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti applicability: Applicability::MachineApplicable, }; - let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id); let infcx = cx.tcx.infer_ctxt().build(); - ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) - .consume_body(closure_body); + ExprUseVisitor::new(&mut visitor, &infcx, def_id, cx.param_env, cx.typeck_results()).consume_body(closure_body); if !visitor.suggestion_start.is_empty() { return Some(DerefClosure { @@ -884,7 +883,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { .cx .typeck_results() .type_dependent_def_id(parent_expr.hir_id) - .map(|did| self.cx.tcx.fn_sig(did).skip_binder()) + .map(|did| self.cx.tcx.fn_sig(did).subst_identity().skip_binder()) { std::iter::once(receiver) .chain(call_args.iter()) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 99fba4fe741..c48d27b05f0 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -628,7 +628,7 @@ impl<'tcx> ExprFnSig<'tcx> { /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> { if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { - Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id))) + Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst_identity(), Some(id))) } else { ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) } @@ -646,10 +646,13 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) }, - ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), cx.tcx.opt_parent(def_id)) - }, + ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))), + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds( + cx, + ty, + cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), + cx.tcx.opt_parent(def_id), + ), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _, _) => { let lang_items = cx.tcx.lang_items(); diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 14c01a60b4c..d18b62d1bf1 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -392,12 +392,12 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe) => + .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe) => { self.is_unsafe = true; }, ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() { - ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe => self.is_unsafe = true, + ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => self.is_unsafe = true, ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true, _ => walk_expr(self, e), }, diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index c01e1062cb5..80eee368178 100644 --- a/src/tools/clippy/declare_clippy_lint/Cargo.toml +++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.68" +version = "0.1.69" edition = "2021" publish = false diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 40a6f47095e..4e7fc565a32 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-01-12" +channel = "nightly-2023-01-27" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs index 7a78b32620d..82147eba33f 100644 --- a/src/tools/clippy/src/main.rs +++ b/src/tools/clippy/src/main.rs @@ -28,7 +28,7 @@ with: -D --deny OPT Set lint denied -F --forbid OPT Set lint forbidden -You can use tool lints to allow or deny lints from your code, eg.: +You can use tool lints to allow or deny lints from your code, e.g.: #[allow(clippy::needless_lifetimes)] "#; diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index 3ca45404e44..2a240cc249b 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -7,14 +7,6 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; = help: convert all references to use `sym::Deref` = note: `-D clippy::unnecessary-def-path` implied by `-D warnings` -error: hardcoded path to a language item - --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40 - | -LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: convert all references to use `LangItem::DerefMut` - error: hardcoded path to a diagnostic item --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 | @@ -23,5 +15,13 @@ LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", | = help: convert all references to use `sym::deref_method` +error: hardcoded path to a language item + --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40 + | +LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: convert all references to use `LangItem::DerefMut` + error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed new file mode 100644 index 00000000000..95f35a61bb2 --- /dev/null +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed @@ -0,0 +1,161 @@ +// run-rustfix + +#![allow(unused, clippy::assertions_on_constants)] +#![warn(clippy::bool_assert_comparison)] + +use std::ops::Not; + +macro_rules! a { + () => { + true + }; +} +macro_rules! b { + () => { + true + }; +} + +// Implements the Not trait but with an output type +// that's not bool. Should not suggest a rewrite +#[derive(Debug, Clone, Copy)] +enum ImplNotTraitWithoutBool { + VariantX(bool), + VariantY(u32), +} + +impl PartialEq<bool> for ImplNotTraitWithoutBool { + fn eq(&self, other: &bool) -> bool { + match *self { + ImplNotTraitWithoutBool::VariantX(b) => b == *other, + _ => false, + } + } +} + +impl Not for ImplNotTraitWithoutBool { + type Output = Self; + + fn not(self) -> Self::Output { + match self { + ImplNotTraitWithoutBool::VariantX(b) => ImplNotTraitWithoutBool::VariantX(!b), + ImplNotTraitWithoutBool::VariantY(0) => ImplNotTraitWithoutBool::VariantY(1), + ImplNotTraitWithoutBool::VariantY(_) => ImplNotTraitWithoutBool::VariantY(0), + } + } +} + +// This type implements the Not trait with an Output of +// type bool. Using assert!(..) must be suggested +#[derive(Debug, Clone, Copy)] +struct ImplNotTraitWithBool; + +impl PartialEq<bool> for ImplNotTraitWithBool { + fn eq(&self, other: &bool) -> bool { + false + } +} + +impl Not for ImplNotTraitWithBool { + type Output = bool; + + fn not(self) -> Self::Output { + true + } +} + +#[derive(Debug)] +struct NonCopy; + +impl PartialEq<bool> for NonCopy { + fn eq(&self, other: &bool) -> bool { + false + } +} + +impl Not for NonCopy { + type Output = bool; + + fn not(self) -> Self::Output { + true + } +} + +fn main() { + let a = ImplNotTraitWithoutBool::VariantX(true); + let b = ImplNotTraitWithBool; + + assert_eq!("a".len(), 1); + assert!("a".is_empty()); + assert!("".is_empty()); + assert!("".is_empty()); + assert_eq!(a!(), b!()); + assert_eq!(a!(), "".is_empty()); + assert_eq!("".is_empty(), b!()); + assert_eq!(a, true); + assert!(b); + + assert_ne!("a".len(), 1); + assert!("a".is_empty()); + assert!("".is_empty()); + assert!("".is_empty()); + assert_ne!(a!(), b!()); + assert_ne!(a!(), "".is_empty()); + assert_ne!("".is_empty(), b!()); + assert_ne!(a, true); + assert!(b); + + debug_assert_eq!("a".len(), 1); + debug_assert!("a".is_empty()); + debug_assert!("".is_empty()); + debug_assert!("".is_empty()); + debug_assert_eq!(a!(), b!()); + debug_assert_eq!(a!(), "".is_empty()); + debug_assert_eq!("".is_empty(), b!()); + debug_assert_eq!(a, true); + debug_assert!(b); + + debug_assert_ne!("a".len(), 1); + debug_assert!("a".is_empty()); + debug_assert!("".is_empty()); + debug_assert!("".is_empty()); + debug_assert_ne!(a!(), b!()); + debug_assert_ne!(a!(), "".is_empty()); + debug_assert_ne!("".is_empty(), b!()); + debug_assert_ne!(a, true); + debug_assert!(b); + + // assert with error messages + assert_eq!("a".len(), 1, "tadam {}", 1); + assert_eq!("a".len(), 1, "tadam {}", true); + assert!("a".is_empty(), "tadam {}", 1); + assert!("a".is_empty(), "tadam {}", true); + assert!("a".is_empty(), "tadam {}", true); + assert_eq!(a, true, "tadam {}", false); + + debug_assert_eq!("a".len(), 1, "tadam {}", 1); + debug_assert_eq!("a".len(), 1, "tadam {}", true); + debug_assert!("a".is_empty(), "tadam {}", 1); + debug_assert!("a".is_empty(), "tadam {}", true); + debug_assert!("a".is_empty(), "tadam {}", true); + debug_assert_eq!(a, true, "tadam {}", false); + + assert!(a!()); + assert!(b!()); + + use debug_assert_eq as renamed; + renamed!(a, true); + debug_assert!(b); + + let non_copy = NonCopy; + assert_eq!(non_copy, true); + // changing the above to `assert!(non_copy)` would cause a `borrow of moved value` + println!("{non_copy:?}"); + + macro_rules! in_macro { + ($v:expr) => {{ + assert_eq!($v, true); + }}; + } + in_macro!(a); +} diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs index ec4d6f3ff84..88e7560b4f9 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs @@ -1,3 +1,6 @@ +// run-rustfix + +#![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] use std::ops::Not; @@ -15,7 +18,7 @@ macro_rules! b { // Implements the Not trait but with an output type // that's not bool. Should not suggest a rewrite -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] enum ImplNotTraitWithoutBool { VariantX(bool), VariantY(u32), @@ -44,7 +47,7 @@ impl Not for ImplNotTraitWithoutBool { // This type implements the Not trait with an Output of // type bool. Using assert!(..) must be suggested -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] struct ImplNotTraitWithBool; impl PartialEq<bool> for ImplNotTraitWithBool { @@ -61,6 +64,23 @@ impl Not for ImplNotTraitWithBool { } } +#[derive(Debug)] +struct NonCopy; + +impl PartialEq<bool> for NonCopy { + fn eq(&self, other: &bool) -> bool { + false + } +} + +impl Not for NonCopy { + type Output = bool; + + fn not(self) -> Self::Output { + true + } +} + fn main() { let a = ImplNotTraitWithoutBool::VariantX(true); let b = ImplNotTraitWithBool; @@ -119,4 +139,23 @@ fn main() { debug_assert_eq!("a".is_empty(), false, "tadam {}", true); debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); debug_assert_eq!(a, true, "tadam {}", false); + + assert_eq!(a!(), true); + assert_eq!(true, b!()); + + use debug_assert_eq as renamed; + renamed!(a, true); + renamed!(b, true); + + let non_copy = NonCopy; + assert_eq!(non_copy, true); + // changing the above to `assert!(non_copy)` would cause a `borrow of moved value` + println!("{non_copy:?}"); + + macro_rules! in_macro { + ($v:expr) => {{ + assert_eq!($v, true); + }}; + } + in_macro!(a); } diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr index 377d51be4cd..3d9f8573e61 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr @@ -1,136 +1,303 @@ error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:69:5 + --> $DIR/bool_assert_comparison.rs:89:5 | LL | assert_eq!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::bool-assert-comparison` implied by `-D warnings` +help: replace it with `assert!(..)` + | +LL - assert_eq!("a".is_empty(), false); +LL + assert!("a".is_empty()); + | error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:70:5 + --> $DIR/bool_assert_comparison.rs:90:5 | LL | assert_eq!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!("".is_empty(), true); +LL + assert!("".is_empty()); + | error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:71:5 + --> $DIR/bool_assert_comparison.rs:91:5 | LL | assert_eq!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(true, "".is_empty()); +LL + assert!("".is_empty()); + | error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:76:5 + --> $DIR/bool_assert_comparison.rs:96:5 | LL | assert_eq!(b, true); - | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(b, true); +LL + assert!(b); + | error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:79:5 + --> $DIR/bool_assert_comparison.rs:99:5 | LL | assert_ne!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_ne!("a".is_empty(), false); +LL + assert!("a".is_empty()); + | error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:80:5 + --> $DIR/bool_assert_comparison.rs:100:5 | LL | assert_ne!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_ne!("".is_empty(), true); +LL + assert!("".is_empty()); + | error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:81:5 + --> $DIR/bool_assert_comparison.rs:101:5 | LL | assert_ne!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_ne!(true, "".is_empty()); +LL + assert!("".is_empty()); + | error: used `assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:86:5 + --> $DIR/bool_assert_comparison.rs:106:5 | LL | assert_ne!(b, true); - | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_ne!(b, true); +LL + assert!(b); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:89:5 + --> $DIR/bool_assert_comparison.rs:109:5 | LL | debug_assert_eq!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!("a".is_empty(), false); +LL + debug_assert!("a".is_empty()); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:90:5 + --> $DIR/bool_assert_comparison.rs:110:5 | LL | debug_assert_eq!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!("".is_empty(), true); +LL + debug_assert!("".is_empty()); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:91:5 + --> $DIR/bool_assert_comparison.rs:111:5 | LL | debug_assert_eq!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!(true, "".is_empty()); +LL + debug_assert!("".is_empty()); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:96:5 + --> $DIR/bool_assert_comparison.rs:116:5 | LL | debug_assert_eq!(b, true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!(b, true); +LL + debug_assert!(b); + | error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:99:5 + --> $DIR/bool_assert_comparison.rs:119:5 | LL | debug_assert_ne!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_ne!("a".is_empty(), false); +LL + debug_assert!("a".is_empty()); + | error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:100:5 + --> $DIR/bool_assert_comparison.rs:120:5 | LL | debug_assert_ne!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_ne!("".is_empty(), true); +LL + debug_assert!("".is_empty()); + | error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:101:5 + --> $DIR/bool_assert_comparison.rs:121:5 | LL | debug_assert_ne!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_ne!(true, "".is_empty()); +LL + debug_assert!("".is_empty()); + | error: used `debug_assert_ne!` with a literal bool - --> $DIR/bool_assert_comparison.rs:106:5 + --> $DIR/bool_assert_comparison.rs:126:5 | LL | debug_assert_ne!(b, true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_ne!(b, true); +LL + debug_assert!(b); + | error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:111:5 + --> $DIR/bool_assert_comparison.rs:131:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!("a".is_empty(), false, "tadam {}", 1); +LL + assert!("a".is_empty(), "tadam {}", 1); + | error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:112:5 + --> $DIR/bool_assert_comparison.rs:132:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!("a".is_empty(), false, "tadam {}", true); +LL + assert!("a".is_empty(), "tadam {}", true); + | error: used `assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:113:5 + --> $DIR/bool_assert_comparison.rs:133:5 | LL | assert_eq!(false, "a".is_empty(), "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(false, "a".is_empty(), "tadam {}", true); +LL + assert!("a".is_empty(), "tadam {}", true); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:118:5 + --> $DIR/bool_assert_comparison.rs:138:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); +LL + debug_assert!("a".is_empty(), "tadam {}", 1); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:119:5 + --> $DIR/bool_assert_comparison.rs:139:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", true); +LL + debug_assert!("a".is_empty(), "tadam {}", true); + | error: used `debug_assert_eq!` with a literal bool - --> $DIR/bool_assert_comparison.rs:120:5 + --> $DIR/bool_assert_comparison.rs:140:5 | LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); +LL + debug_assert!("a".is_empty(), "tadam {}", true); + | + +error: used `assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:143:5 + | +LL | assert_eq!(a!(), true); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(a!(), true); +LL + assert!(a!()); + | + +error: used `assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:144:5 + | +LL | assert_eq!(true, b!()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(true, b!()); +LL + assert!(b!()); + | + +error: used `debug_assert_eq!` with a literal bool + --> $DIR/bool_assert_comparison.rs:148:5 + | +LL | renamed!(b, true); + | ^^^^^^^^^^^^^^^^^ + | +help: replace it with `debug_assert!(..)` + | +LL - renamed!(b, true); +LL + debug_assert!(b); + | -error: aborting due to 22 previous errors +error: aborting due to 25 previous errors diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index e6031e9adae..8b2673c2a7f 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -28,6 +28,7 @@ fn main() { 1i32 as u8; 1f64 as isize; 1f64 as usize; + 1f32 as u32 as u16; // Test clippy::cast_possible_wrap 1u8 as i8; 1u16 as i16; diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 0c63b4af308..4af1de9aa38 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -42,13 +42,24 @@ error: casting `f32` to `i32` may truncate the value LL | 1f32 as i32; | ^^^^^^^^^^^ | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1f32); + | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value --> $DIR/cast.rs:25:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1f32); + | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:25:5 @@ -63,30 +74,60 @@ error: casting `f64` to `f32` may truncate the value | LL | 1f64 as f32; | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | f32::try_from(1f64); + | ~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `i8` may truncate the value --> $DIR/cast.rs:27:5 | LL | 1i32 as i8; | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from(1i32); + | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value --> $DIR/cast.rs:28:5 | LL | 1i32 as u8; | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u8::try_from(1i32); + | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value --> $DIR/cast.rs:29:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1f64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may truncate the value --> $DIR/cast.rs:30:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1f64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may lose the sign of the value --> $DIR/cast.rs:30:5 @@ -94,8 +135,38 @@ error: casting `f64` to `usize` may lose the sign of the value LL | 1f64 as usize; | ^^^^^^^^^^^^^ +error: casting `u32` to `u16` may truncate the value + --> $DIR/cast.rs:31:5 + | +LL | 1f32 as u32 as u16; + | ^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u16::try_from(1f32 as u32); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: casting `f32` to `u32` may truncate the value + --> $DIR/cast.rs:31:5 + | +LL | 1f32 as u32 as u16; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1f32) as u16; + | ~~~~~~~~~~~~~~~~~~~ + +error: casting `f32` to `u32` may lose the sign of the value + --> $DIR/cast.rs:31:5 + | +LL | 1f32 as u32 as u16; + | ^^^^^^^^^^^ + error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:32:5 + --> $DIR/cast.rs:33:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -103,61 +174,79 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:34:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:34:5 + --> $DIR/cast.rs:35:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:36:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:37:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:39:5 + --> $DIR/cast.rs:40:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:41:5 + --> $DIR/cast.rs:42:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:108:5 + --> $DIR/cast.rs:109:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:120:5 + --> $DIR/cast.rs:121:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> $DIR/cast.rs:141:21 + --> $DIR/cast.rs:142:21 | LL | let _ = self as u8; | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = u8::try_from(self); + | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> $DIR/cast.rs:142:21 + --> $DIR/cast.rs:143:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -165,46 +254,82 @@ LL | let _ = Self::B as u8; = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` error: casting `main::E5` to `i8` may truncate the value - --> $DIR/cast.rs:178:21 + --> $DIR/cast.rs:179:21 | LL | let _ = self as i8; | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = i8::try_from(self); + | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> $DIR/cast.rs:179:21 + --> $DIR/cast.rs:180:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> $DIR/cast.rs:193:21 + --> $DIR/cast.rs:194:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = i16::try_from(self); + | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:208:21 + --> $DIR/cast.rs:209:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = usize::try_from(self); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> $DIR/cast.rs:249:21 + --> $DIR/cast.rs:250:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _ = u16::try_from(self); + | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:257:13 + --> $DIR/cast.rs:258:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let c = u8::try_from((q >> 16)); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:260:13 + --> $DIR/cast.rs:261:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let c = u8::try_from((q / 1000)); + | ~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 33 previous errors +error: aborting due to 36 previous errors diff --git a/src/tools/clippy/tests/ui/cast_size.stderr b/src/tools/clippy/tests/ui/cast_size.stderr index 95552f2e285..8acf26049f4 100644 --- a/src/tools/clippy/tests/ui/cast_size.stderr +++ b/src/tools/clippy/tests/ui/cast_size.stderr @@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value LL | 1isize as i8; | ^^^^^^^^^^^^ | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> $DIR/cast_size.rs:15:5 @@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi | LL | 1isize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size.rs:20:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size.rs:21:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size.rs:22:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size.rs:22:5 @@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi | LL | 1i64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size.rs:25:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size.rs:26:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers --> $DIR/cast_size.rs:26:5 @@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi | LL | 1u64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size.rs:28:5 diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.stderr b/src/tools/clippy/tests/ui/module_name_repetitions.stderr index 3f343a3e430..277801194a1 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.stderr +++ b/src/tools/clippy/tests/ui/module_name_repetitions.stderr @@ -1,34 +1,34 @@ error: item name starts with its containing module's name - --> $DIR/module_name_repetitions.rs:8:5 + --> $DIR/module_name_repetitions.rs:8:12 | LL | pub fn foo_bar() {} - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::module-name-repetitions` implied by `-D warnings` error: item name ends with its containing module's name - --> $DIR/module_name_repetitions.rs:9:5 + --> $DIR/module_name_repetitions.rs:9:12 | LL | pub fn bar_foo() {} - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: item name starts with its containing module's name - --> $DIR/module_name_repetitions.rs:10:5 + --> $DIR/module_name_repetitions.rs:10:16 | LL | pub struct FooCake; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: item name ends with its containing module's name - --> $DIR/module_name_repetitions.rs:11:5 + --> $DIR/module_name_repetitions.rs:11:14 | LL | pub enum CakeFoo {} - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: item name starts with its containing module's name - --> $DIR/module_name_repetitions.rs:12:5 + --> $DIR/module_name_repetitions.rs:12:16 | LL | pub struct Foo7Bar; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs new file mode 100644 index 00000000000..41263535df6 --- /dev/null +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs @@ -0,0 +1,110 @@ +#![allow(unused)] +#![allow(deref_nullptr)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::drop_copy)] +#![warn(clippy::multiple_unsafe_ops_per_block)] + +use core::arch::asm; + +fn raw_ptr() -> *const () { + core::ptr::null() +} + +unsafe fn not_very_safe() {} + +struct Sample; + +impl Sample { + unsafe fn not_very_safe(&self) {} +} + +#[allow(non_upper_case_globals)] +const sample: Sample = Sample; + +union U { + i: i32, + u: u32, +} + +static mut STATIC: i32 = 0; + +fn test1() { + unsafe { + STATIC += 1; + not_very_safe(); + } +} + +fn test2() { + let u = U { i: 0 }; + + unsafe { + drop(u.u); + *raw_ptr(); + } +} + +fn test3() { + unsafe { + asm!("nop"); + sample.not_very_safe(); + STATIC = 0; + } +} + +fn test_all() { + let u = U { i: 0 }; + unsafe { + drop(u.u); + drop(STATIC); + sample.not_very_safe(); + not_very_safe(); + *raw_ptr(); + asm!("nop"); + } +} + +// no lint +fn correct1() { + unsafe { + STATIC += 1; + } +} + +// no lint +fn correct2() { + unsafe { + STATIC += 1; + } + + unsafe { + *raw_ptr(); + } +} + +// no lint +fn correct3() { + let u = U { u: 0 }; + + unsafe { + not_very_safe(); + } + + unsafe { + drop(u.i); + } +} + +// tests from the issue (https://github.com/rust-lang/rust-clippy/issues/10064) + +unsafe fn read_char_bad(ptr: *const u8) -> char { + unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } +} + +// no lint +unsafe fn read_char_good(ptr: *const u8) -> char { + let int_value = unsafe { *ptr.cast::<u32>() }; + unsafe { core::char::from_u32_unchecked(int_value) } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr new file mode 100644 index 00000000000..f6b8341795d --- /dev/null +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -0,0 +1,129 @@ +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> $DIR/multiple_unsafe_ops_per_block.rs:32:5 + | +LL | / unsafe { +LL | | STATIC += 1; +LL | | not_very_safe(); +LL | | } + | |_____^ + | +note: modification of a mutable static occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:33:9 + | +LL | STATIC += 1; + | ^^^^^^^^^^^ +note: unsafe function call occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:34:9 + | +LL | not_very_safe(); + | ^^^^^^^^^^^^^^^ + = note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings` + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> $DIR/multiple_unsafe_ops_per_block.rs:41:5 + | +LL | / unsafe { +LL | | drop(u.u); +LL | | *raw_ptr(); +LL | | } + | |_____^ + | +note: union field access occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:42:14 + | +LL | drop(u.u); + | ^^^ +note: raw pointer dereference occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:43:9 + | +LL | *raw_ptr(); + | ^^^^^^^^^^ + +error: this `unsafe` block contains 3 unsafe operations, expected only one + --> $DIR/multiple_unsafe_ops_per_block.rs:48:5 + | +LL | / unsafe { +LL | | asm!("nop"); +LL | | sample.not_very_safe(); +LL | | STATIC = 0; +LL | | } + | |_____^ + | +note: inline assembly used here + --> $DIR/multiple_unsafe_ops_per_block.rs:49:9 + | +LL | asm!("nop"); + | ^^^^^^^^^^^ +note: unsafe method call occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:50:9 + | +LL | sample.not_very_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: modification of a mutable static occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:51:9 + | +LL | STATIC = 0; + | ^^^^^^^^^^ + +error: this `unsafe` block contains 6 unsafe operations, expected only one + --> $DIR/multiple_unsafe_ops_per_block.rs:57:5 + | +LL | / unsafe { +LL | | drop(u.u); +LL | | drop(STATIC); +LL | | sample.not_very_safe(); +... | +LL | | asm!("nop"); +LL | | } + | |_____^ + | +note: union field access occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:58:14 + | +LL | drop(u.u); + | ^^^ +note: access of a mutable static occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:59:14 + | +LL | drop(STATIC); + | ^^^^^^ +note: unsafe method call occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:60:9 + | +LL | sample.not_very_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:61:9 + | +LL | not_very_safe(); + | ^^^^^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:62:9 + | +LL | *raw_ptr(); + | ^^^^^^^^^^ +note: inline assembly used here + --> $DIR/multiple_unsafe_ops_per_block.rs:63:9 + | +LL | asm!("nop"); + | ^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> $DIR/multiple_unsafe_ops_per_block.rs:101:5 + | +LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: unsafe function call occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:101:14 + | +LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> $DIR/multiple_unsafe_ops_per_block.rs:101:39 + | +LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) } + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index ab1c0e590bb..079e3531def 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool { true } +#[rustfmt::skip] +fn test_multiple_semicolon() -> bool { + true +} + +#[rustfmt::skip] +fn test_multiple_semicolon_with_spaces() -> bool { + true +} + fn test_if_block() -> bool { if true { true diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index abed338bb9b..c1c48284f08 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool { return true; } +#[rustfmt::skip] +fn test_multiple_semicolon() -> bool { + return true;;; +} + +#[rustfmt::skip] +fn test_multiple_semicolon_with_spaces() -> bool { + return true;; ; ; +} + fn test_if_block() -> bool { if true { return true; diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 52eabf6e137..08b04bfe9d8 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -16,7 +16,23 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:36:9 + --> $DIR/needless_return.rs:36:5 + | +LL | return true;;; + | ^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:41:5 + | +LL | return true;; ; ; + | ^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:46:9 | LL | return true; | ^^^^^^^^^^^ @@ -24,7 +40,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:38:9 + --> $DIR/needless_return.rs:48:9 | LL | return false; | ^^^^^^^^^^^^ @@ -32,7 +48,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:44:17 + --> $DIR/needless_return.rs:54:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -40,7 +56,7 @@ LL | true => return false, = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:46:13 + --> $DIR/needless_return.rs:56:13 | LL | return true; | ^^^^^^^^^^^ @@ -48,7 +64,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:53:9 + --> $DIR/needless_return.rs:63:9 | LL | return true; | ^^^^^^^^^^^ @@ -56,7 +72,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:55:16 + --> $DIR/needless_return.rs:65:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -64,7 +80,7 @@ LL | let _ = || return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:59:5 + --> $DIR/needless_return.rs:69:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +88,7 @@ LL | return the_answer!(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:62:21 + --> $DIR/needless_return.rs:72:21 | LL | fn test_void_fun() { | _____________________^ @@ -82,7 +98,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:67:11 + --> $DIR/needless_return.rs:77:11 | LL | if b { | ___________^ @@ -92,7 +108,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:69:13 + --> $DIR/needless_return.rs:79:13 | LL | } else { | _____________^ @@ -102,7 +118,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:77:14 + --> $DIR/needless_return.rs:87:14 | LL | _ => return, | ^^^^^^ @@ -110,7 +126,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:85:24 + --> $DIR/needless_return.rs:95:24 | LL | let _ = 42; | ________________________^ @@ -120,7 +136,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:88:14 + --> $DIR/needless_return.rs:98:14 | LL | _ => return, | ^^^^^^ @@ -128,7 +144,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:101:9 + --> $DIR/needless_return.rs:111:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +152,7 @@ LL | return String::from("test"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:103:9 + --> $DIR/needless_return.rs:113:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +160,7 @@ LL | return String::new(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:125:32 + --> $DIR/needless_return.rs:135:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -152,7 +168,7 @@ LL | bar.unwrap_or_else(|_| return) = help: replace `return` with an empty block error: unneeded `return` statement - --> $DIR/needless_return.rs:129:21 + --> $DIR/needless_return.rs:139:21 | LL | let _ = || { | _____________________^ @@ -162,7 +178,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:132:20 + --> $DIR/needless_return.rs:142:20 | LL | let _ = || return; | ^^^^^^ @@ -170,7 +186,7 @@ LL | let _ = || return; = help: replace `return` with an empty block error: unneeded `return` statement - --> $DIR/needless_return.rs:138:32 + --> $DIR/needless_return.rs:148:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -178,7 +194,7 @@ LL | res.unwrap_or_else(|_| return Foo) = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:147:5 + --> $DIR/needless_return.rs:157:5 | LL | return true; | ^^^^^^^^^^^ @@ -186,7 +202,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:151:5 + --> $DIR/needless_return.rs:161:5 | LL | return true; | ^^^^^^^^^^^ @@ -194,7 +210,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:156:9 + --> $DIR/needless_return.rs:166:9 | LL | return true; | ^^^^^^^^^^^ @@ -202,7 +218,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:158:9 + --> $DIR/needless_return.rs:168:9 | LL | return false; | ^^^^^^^^^^^^ @@ -210,7 +226,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:164:17 + --> $DIR/needless_return.rs:174:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -218,7 +234,7 @@ LL | true => return false, = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:166:13 + --> $DIR/needless_return.rs:176:13 | LL | return true; | ^^^^^^^^^^^ @@ -226,7 +242,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:173:9 + --> $DIR/needless_return.rs:183:9 | LL | return true; | ^^^^^^^^^^^ @@ -234,7 +250,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:175:16 + --> $DIR/needless_return.rs:185:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -242,7 +258,7 @@ LL | let _ = || return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:179:5 + --> $DIR/needless_return.rs:189:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -250,7 +266,7 @@ LL | return the_answer!(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:182:33 + --> $DIR/needless_return.rs:192:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -260,7 +276,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:187:11 + --> $DIR/needless_return.rs:197:11 | LL | if b { | ___________^ @@ -270,7 +286,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:189:13 + --> $DIR/needless_return.rs:199:13 | LL | } else { | _____________^ @@ -280,7 +296,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:197:14 + --> $DIR/needless_return.rs:207:14 | LL | _ => return, | ^^^^^^ @@ -288,7 +304,7 @@ LL | _ => return, = help: replace `return` with a unit value error: unneeded `return` statement - --> $DIR/needless_return.rs:210:9 + --> $DIR/needless_return.rs:220:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +312,7 @@ LL | return String::from("test"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:212:9 + --> $DIR/needless_return.rs:222:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +320,7 @@ LL | return String::new(); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:228:5 + --> $DIR/needless_return.rs:238:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +328,7 @@ LL | return format!("Hello {}", "world!"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:239:9 + --> $DIR/needless_return.rs:249:9 | LL | return true; | ^^^^^^^^^^^ @@ -320,7 +336,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:241:9 + --> $DIR/needless_return.rs:251:9 | LL | return false; | ^^^^^^^^^^^^ @@ -328,7 +344,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:248:13 + --> $DIR/needless_return.rs:258:13 | LL | return 10; | ^^^^^^^^^ @@ -336,7 +352,7 @@ LL | return 10; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:251:13 + --> $DIR/needless_return.rs:261:13 | LL | return 100; | ^^^^^^^^^^ @@ -344,7 +360,7 @@ LL | return 100; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:259:9 + --> $DIR/needless_return.rs:269:9 | LL | return 0; | ^^^^^^^^ @@ -352,7 +368,7 @@ LL | return 0; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:266:13 + --> $DIR/needless_return.rs:276:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -360,7 +376,7 @@ LL | return *(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:268:13 + --> $DIR/needless_return.rs:278:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -368,7 +384,7 @@ LL | return !*(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:275:20 + --> $DIR/needless_return.rs:285:20 | LL | let _ = 42; | ____________________^ @@ -379,7 +395,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:282:20 + --> $DIR/needless_return.rs:292:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -387,7 +403,7 @@ LL | let _ = 42; return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:294:9 + --> $DIR/needless_return.rs:304:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,12 +411,12 @@ LL | return Ok(format!("ok!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:296:9 + --> $DIR/needless_return.rs:306:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: remove `return` -error: aborting due to 48 previous errors +error: aborting due to 50 previous errors diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 7263abac15d..55307506eb3 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -51,6 +51,8 @@ fn main() { // e is a function pointer type and U is an integer; fptr-addr-cast let _usize_from_fn_ptr_transmute = unsafe { foo as usize }; let _usize_from_fn_ptr = foo as *const usize; + + let _usize_from_ref = unsafe { &1u32 as *const u32 as usize }; } // If a ref-to-ptr cast of this form where the pointer type points to a type other diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index d8e4421d4c1..e7360f3f9dc 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -51,6 +51,8 @@ fn main() { // e is a function pointer type and U is an integer; fptr-addr-cast let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) }; let _usize_from_fn_ptr = foo as *const usize; + + let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; } // If a ref-to-ptr cast of this form where the pointer type points to a type other diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index de9418c8d1a..e862fcb67a4 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -46,11 +46,17 @@ error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` +error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead + --> $DIR/transmutes_expressible_as_ptr_casts.rs:55:36 + | +LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` + error: transmute from a reference to a pointer - --> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14 + --> $DIR/transmutes_expressible_as_ptr_casts.rs:66:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs index 7fefea7051d..89fedb145f8 100644 --- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs +++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs @@ -48,4 +48,21 @@ fn unnecessary_on_stmt_and_expr() -> u32 { 24 } +mod issue_10084 { + unsafe fn bar() -> i32 { + 42 + } + + macro_rules! foo { + () => { + // SAFETY: This is necessary + unsafe { bar() } + }; + } + + fn main() { + foo!(); + } +} + fn main() {} diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index e01bfbc74d9..db9f180a5e5 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -43,7 +43,8 @@ function run_tests { # optimizations up all the way, too). # Optimizations change diagnostics (mostly backtraces), so we don't check # them. Also error locations change so we don't run the failing tests. - MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} + #FIXME: temporarily disabled due to <https://github.com/rust-lang/rust/issues/107511>. + #MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} # Also run some many-seeds tests. 64 seeds means this takes around a minute per test. for FILE in tests/many-seeds/*.rs; do diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0f7f4851c7a..f1f26e4e310 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -ad48c109815a2e9441a7ad7796e55b8771fe01a5 +a322848c6b0e037c1f0209387558ecb6ab763714 diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 6c87dad1f1f..96ab8b0d98e 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -357,7 +357,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( match entry_type { EntryFnType::Main { .. } => { let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(entry_id).output(); + let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::resolve( tcx, diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 9c16ef2cbec..395bcc745f8 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -68,52 +68,6 @@ def load_json_from_response(resp): print("Refusing to decode " + str(type(content)) + " to str") return json.loads(content_str) -def validate_maintainers(repo, github_token): - # type: (str, str) -> None - '''Ensure all maintainers are assignable on a GitHub repo''' - next_link_re = re.compile(r'<([^>]+)>; rel="next"') - - # Load the list of assignable people in the GitHub repo - assignable = [] # type: typing.List[str] - url = 'https://api.github.com/repos/' \ - + '%s/collaborators?per_page=100' % repo # type: typing.Optional[str] - while url is not None: - response = urllib2.urlopen(urllib2.Request(url, headers={ - 'Authorization': 'token ' + github_token, - # Properly load nested teams. - 'Accept': 'application/vnd.github.hellcat-preview+json', - })) - assignable.extend(user['login'] for user in load_json_from_response(response)) - # Load the next page if available - url = None - link_header = response.headers.get('Link') - if link_header: - matches = next_link_re.match(link_header) - if matches is not None: - url = matches.group(1) - - errors = False - for tool, maintainers in MAINTAINERS.items(): - for maintainer in maintainers: - if maintainer not in assignable: - errors = True - print( - "error: %s maintainer @%s is not assignable in the %s repo" - % (tool, maintainer, repo), - ) - - if errors: - print() - print(" To be assignable, a person needs to be explicitly listed as a") - print(" collaborator in the repository settings. The simple way to") - print(" fix this is to ask someone with 'admin' privileges on the repo") - print(" to add the person or whole team as a collaborator with 'read'") - print(" privileges. Those privileges don't grant any extra permissions") - print(" so it's safe to apply them.") - print() - print("The build will fail due to this.") - exit(1) - def read_current_status(current_commit, path): # type: (str, str) -> typing.Mapping[str, typing.Any] @@ -280,21 +234,6 @@ def update_latest( try: if __name__ != '__main__': exit(0) - repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO') - if repo: - github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN') - if github_token: - # FIXME: This is currently broken. Starting on 2021-09-15, GitHub - # seems to have changed it so that to list the collaborators - # requires admin permissions. I think this will probably just need - # to be removed since we are probably not going to use an admin - # token, and I don't see another way to do this. - print('maintainer validation disabled') - # validate_maintainers(repo, github_token) - else: - print('skipping toolstate maintainers validation since no GitHub token is present') - # When validating maintainers don't run the full script. - exit(0) cur_commit = sys.argv[1] cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') diff --git a/src/tools/rustfmt/.github/workflows/check_diff.yml b/src/tools/rustfmt/.github/workflows/check_diff.yml new file mode 100644 index 00000000000..8bfb5834519 --- /dev/null +++ b/src/tools/rustfmt/.github/workflows/check_diff.yml @@ -0,0 +1,33 @@ +name: Diff Check +on: + workflow_dispatch: + inputs: + clone_url: + description: 'Git url of a rustfmt fork to compare against the latest master rustfmt' + required: true + branch_name: + description: 'Name of the feature branch on the forked repo' + required: true + commit_hash: + description: 'Optional commit hash from the feature branch' + required: false + rustfmt_configs: + description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch' + required: false + +jobs: + diff_check: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install rustup + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh + sh rustup-init.sh -y --default-toolchain none + rustup target add x86_64-unknown-linux-gnu + + - name: check diff + run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }} diff --git a/src/tools/rustfmt/.github/workflows/integration.yml b/src/tools/rustfmt/.github/workflows/integration.yml index 4d8899b434b..314ce0e84c6 100644 --- a/src/tools/rustfmt/.github/workflows/integration.yml +++ b/src/tools/rustfmt/.github/workflows/integration.yml @@ -27,7 +27,6 @@ jobs: tempdir, futures-rs, rust-clippy, - failure, ] include: # Allowed Failures @@ -63,9 +62,6 @@ jobs: # Original comment was: temporal build failure due to breaking changes in the nightly compiler - integration: rust-semverver allow-failure: true - # Can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged - - integration: failure - allow-failure: true steps: - name: checkout diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md index 0c1893bf8c3..60f961fa12a 100644 --- a/src/tools/rustfmt/CHANGELOG.md +++ b/src/tools/rustfmt/CHANGELOG.md @@ -2,6 +2,32 @@ ## [Unreleased] +## [1.5.2] 2023-01-24 + +### Fixed + +- Resolve issue when comments are found within const generic defaults in unit structs [#5668](https://github.com/rust-lang/rustfmt/issues/5668) +- Resolve issue when block comments are found within trait generics [#5358](https://github.com/rust-lang/rustfmt/issues/5358) +- Correctly handle alignment of comments containing unicode characters [#5504](https://github.com/rust-lang/rustfmt/issues/5504) +- Properly indent a single generic bound that requires being written across multiple lines [#4689](https://github.com/rust-lang/rustfmt/issues/4689) (n.b. this change is version gated and will only appear when the `version` configuration option is set to `Two`) + +### Changed + +- Renamed `fn_args_layout` configuration option to `fn_params_layout` [#4149](https://github.com/rust-lang/rustfmt/issues/4149). Note that `fn_args_layout` has only been soft deprecated: `fn_args_layout` will continue to work without issue, but rustfmt will display a warning to encourage users to switch to the new name + +### Added + +- New configuration option (`skip_macro_invocations`)[https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations] [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) + +### Misc + +- rustfmt now internally supports the ability to have both stable and unstable variants of a configuration option [#5378](https://github.com/rust-lang/rustfmt/issues/5378). This ability will allow the rustfmt team to make certain configuration options available on stable toolchains more quickly because we no longer have to wait for _every_ variant to be stable-ready before stabilizing _any_ variant. + +### Install/Download Options +- **rustup (nightly)** - nightly-2023-01-24 +- **GitHub Release Binaries** - [Release v1.5.2](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.2) +- **Build from source** - [Tag v1.5.2](https://github.com/rust-lang/rustfmt/tree/v1.5.2), see instructions for how to [install rustfmt from source][install-from-source] + ## [1.5.1] 2022-06-24 **N.B** A bug was introduced in v1.5.0/nightly-2022-06-15 which modified formatting. If you happened to run rustfmt over your code with one of those ~10 nightlies it's possible you may have seen formatting changes, and you may see additional changes after this fix since that bug has now been reverted. @@ -840,7 +866,7 @@ from formatting an attribute #3665 - Fix formatting of raw string literals #2983 - Handle chain with try operators with spaces #2986 - Use correct shape in Visual tuple rewriting #2987 -- Impove formatting of arguments with `visual_style = "Visual"` option #2988 +- Improve formatting of arguments with `visual_style = "Visual"` option #2988 - Change `print_diff` to output the correct line number 992b179 - Propagate errors about failing to rewrite a macro 6f318e3 - Handle formatting of long function signature #3010 diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index 311df226da1..24166d51c51 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -476,7 +476,7 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" dependencies = [ "proc-macro2", "quote", @@ -485,7 +485,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.1" +version = "1.5.2" dependencies = [ "annotate-snippets", "anyhow", diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 7a4e02d69ed..87ce59d0217 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.5.1" +version = "1.5.2" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -57,7 +57,7 @@ unicode-segmentation = "1.9" unicode-width = "0.1" unicode_categories = "0.1" -rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" } +rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md index 8b96b9d3689..49e7e4e6489 100644 --- a/src/tools/rustfmt/Configurations.md +++ b/src/tools/rustfmt/Configurations.md @@ -1,6 +1,6 @@ # Configuring Rustfmt -Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/1.0.4/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. +Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this: @@ -425,7 +425,7 @@ fn example() { ## `comment_width` -Maximum length of comments. No effect unless`wrap_comments = true`. +Maximum length of comments. No effect unless `wrap_comments = true`. - **Default value**: `80` - **Possible values**: any positive integer @@ -589,7 +589,7 @@ doesn't get ignored when aligning. #### `0` (default): ```rust -enum Bar { +enum Foo { A = 0, Bb = 1, RandomLongVariantGoesHere = 10, @@ -645,7 +645,8 @@ trailing whitespaces. ## `fn_args_layout` -Control the layout of arguments in a function +This option is deprecated and has been renamed to `fn_params_layout` to better communicate that +it affects the layout of parameters in function signatures. - **Default value**: `"Tall"` - **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` @@ -753,6 +754,8 @@ trait Lorem { } ``` +See also [`fn_params_layout`](#fn_params_layout) + ## `fn_call_width` Maximum width of the args of a function call before falling back to vertical formatting. @@ -765,6 +768,117 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) +## `fn_params_layout` + +Control the layout of parameters in function signatures. + +- **Default value**: `"Tall"` +- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` +- **Stable**: Yes + +#### `"Tall"` (default): + +```rust +trait Lorem { + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet); + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) { + // body + } + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ) { + // body + } +} +``` + +#### `"Compressed"`: + +```rust +trait Lorem { + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet); + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) { + // body + } + + fn lorem( + ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur, + adipiscing: Adipiscing, elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur, + adipiscing: Adipiscing, elit: Elit, + ) { + // body + } +} +``` + +#### `"Vertical"`: + +```rust +trait Lorem { + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + ) { + // body + } + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: Consectetur, + adipiscing: Adipiscing, + elit: Elit, + ) { + // body + } +} +``` + + ## `fn_single_line` Put single-expression functions on a single line @@ -1014,6 +1128,62 @@ macro_rules! foo { See also [`format_macro_matchers`](#format_macro_matchers). +## `skip_macro_invocations` + +Skip formatting the bodies of macro invocations with the following names. + +rustfmt will not format any macro invocation for macros with names set in this list. +Including the special value "*" will prevent any macro invocations from being formatted. + +Note: This option does not have any impact on how rustfmt formats macro definitions. + +- **Default value**: `[]` +- **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]` +- **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346)) + +#### `[]` (default): + +rustfmt will follow its standard approach to formatting macro invocations. + +No macro invocations will be skipped based on their name. More information about rustfmt's standard macro invocation formatting behavior can be found in [#5437](https://github.com/rust-lang/rustfmt/discussions/5437). + +```rust +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; +); +``` + +#### `["lorem"]`: + +The named macro invocations will be skipped. + +```rust +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; +); +``` + +#### `["*"]`: + +The special selector `*` will skip all macro invocations. + +```rust +lorem!( + const _: u8 = 0; +); + +ipsum!( + const _: u8 = 0; +); +``` ## `format_strings` @@ -1687,13 +1857,16 @@ pub enum Foo {} ## `imports_granularity` -How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity. +Controls how imports are structured in `use` statements. Imports will be merged or split to the configured level of granularity. + +Similar to other `import` related configuration options, this option operates within the bounds of user-defined groups of imports. See [`group_imports`](#group_imports) for more information on import groups. + +Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments. - **Default value**: `Preserve` - **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One` - **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991)) -Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments. #### `Preserve` (default): diff --git a/src/tools/rustfmt/Processes.md b/src/tools/rustfmt/Processes.md index f763b5714ce..61abc87eec9 100644 --- a/src/tools/rustfmt/Processes.md +++ b/src/tools/rustfmt/Processes.md @@ -2,7 +2,7 @@ This document outlines processes regarding management of rustfmt. # Stabilising an Option -In this Section, we describe how to stabilise an option of the rustfmt's configration. +In this Section, we describe how to stabilise an option of the rustfmt's configuration. ## Conditions diff --git a/src/tools/rustfmt/ci/build_and_test.bat b/src/tools/rustfmt/ci/build_and_test.bat index ef41017783f..69dae1fff7b 100755 --- a/src/tools/rustfmt/ci/build_and_test.bat +++ b/src/tools/rustfmt/ci/build_and_test.bat @@ -1,4 +1,5 @@ set "RUSTFLAGS=-D warnings" +set "RUSTFMT_CI=1" :: Print version information rustc -Vv || exit /b 1 diff --git a/src/tools/rustfmt/ci/build_and_test.sh b/src/tools/rustfmt/ci/build_and_test.sh index 8fa0f67b0d0..94991853263 100755 --- a/src/tools/rustfmt/ci/build_and_test.sh +++ b/src/tools/rustfmt/ci/build_and_test.sh @@ -3,6 +3,7 @@ set -euo pipefail export RUSTFLAGS="-D warnings" +export RUSTFMT_CI=1 # Print version information rustc -Vv diff --git a/src/tools/rustfmt/ci/check_diff.sh b/src/tools/rustfmt/ci/check_diff.sh new file mode 100755 index 00000000000..062c2dd8673 --- /dev/null +++ b/src/tools/rustfmt/ci/check_diff.sh @@ -0,0 +1,199 @@ +#!/bin/bash + +function print_usage() { + echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]" +} + +if [ $# -le 1 ]; then + print_usage + exit 1 +fi + +REMOTE_REPO=$1 +FEATURE_BRANCH=$2 +OPTIONAL_COMMIT_HASH=$3 +OPTIONAL_RUSTFMT_CONFIGS=$4 + +# OUTPUT array used to collect all the status of running diffs on various repos +STATUSES=() + +# Clone a git repository and cd into it. +# +# Parameters: +# $1: git clone url +# $2: directory where the repo should be cloned +function clone_repo() { + GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2 +} + +# Initialize Git submoduels for the repo. +# +# Parameters +# $1: list of directories to initialize +function init_submodules() { + git submodule update --init $1 +} + +# Run rusfmt with the --check flag to see if a diff is produced. +# +# Parameters: +# $1: Path to a rustfmt binary +# $2: Output file path for the diff +# $3: Any additional configuration options to pass to rustfmt +# +# Globlas: +# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 +function create_diff() { + local config; + if [ -z "$3" ]; then + config="--config=error_on_line_overflow=false,error_on_unformatted=false" + else + config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS" + fi + + for i in `find . | grep "\.rs$"` + do + $1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null + done +} + +# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs +# +# Parameters +# $1: Name of the repository (used for logging) +# +# Globlas: +# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt` +# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt` +# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 +function check_diff() { + echo "running rustfmt (master) on $1" + create_diff $RUSFMT_BIN rustfmt_diff.txt + + echo "running rustfmt (feature) on $1" + create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS + + echo "checking diff" + local diff; + # we don't add color to the diff since we added color when running rustfmt --check. + # tail -n + 6 removes the git diff header info + # cut -c 2- removes the leading diff characters("+","-"," ") from running git diff. + # Again, the diff output we care about was already added when we ran rustfmt --check + diff=$( + git --no-pager diff --color=never \ + --unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2- + ) + + if [ -z "$diff" ]; then + echo "no diff detected between rustfmt and the feture branch" + return 0 + else + echo "$diff" + return 1 + fi +} + +# Compiles and produces two rustfmt binaries. +# One for the current master, and another for the feature branch +# +# Parameters: +# $1: Directory where rustfmt will be cloned +# +# Globlas: +# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test +# $FEATURE_BRANCH: Name of the feature branch +# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided +function compile_rustfmt() { + RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git" + clone_repo $RUSTFMT_REPO $1 + git remote add feature $REMOTE_REPO + git fetch feature $FEATURE_BRANCH + + cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + if [ -z "$OPTIONAL_COMMIT_HASH" ]; then + git switch $FEATURE_BRANCH + else + git switch $OPTIONAL_COMMIT_HASH --detach + fi + cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + RUSFMT_BIN=$1/rustfmt + FEATURE_BIN=$1/feature_rustfmt +} + +# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo. +# +# Parameters +# $1: Clone URL for the repo +# $2: Name of the repo (mostly used for logging) +# $3: Path to any submodules that should be initialized +function check_repo() { + WORKDIR=$(pwd) + REPO_URL=$1 + REPO_NAME=$2 + SUBMODULES=$3 + + local tmp_dir; + tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX) + clone_repo $REPO_URL $tmp_dir + + if [ ! -z "$SUBMODULES" ]; then + init_submodules $SUBMODULES + fi + + check_diff $REPO_NAME + # append the status of running `check_diff` to the STATUSES array + STATUSES+=($?) + + echo "removing tmp_dir $tmp_dir" + rm -rf $tmp_dir + cd $WORKDIR +} + +function main() { + tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX) + echo Created tmp_dir $tmp_dir + + compile_rustfmt $tmp_dir + + # run checks + check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust + check_repo "https://github.com/rust-lang/cargo.git" cargo + check_repo "https://github.com/rust-lang/miri.git" miri + check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer + check_repo "https://github.com/bitflags/bitflags.git" bitflags + check_repo "https://github.com/rust-lang/log.git" log + check_repo "https://github.com/rust-lang/mdBook.git" mdBook + check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd + check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo + check_repo "https://github.com/Stebalien/tempfile.git" tempfile + check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs + check_repo "https://github.com/dtolnay/anyhow.git" anyhow + check_repo "https://github.com/dtolnay/thiserror.git" thiserror + check_repo "https://github.com/dtolnay/syn.git" syn + check_repo "https://github.com/serde-rs/serde.git" serde + check_repo "https://github.com/rust-lang/rustlings.git" rustlings + check_repo "https://github.com/rust-lang/rustup.git" rustup + check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket + check_repo "https://github.com/rustls/rustls.git" rustls + check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen + check_repo "https://github.com/hyperium/hyper.git" hyper + check_repo "https://github.com/actix/actix.git" actix + check_repo "https://github.com/denoland/deno.git" denoland_deno + + # cleanup temp dir + echo removing tmp_dir $tmp_dir + rm -rf $tmp_dir + + # figure out the exit code + for status in ${STATUSES[@]} + do + if [ $status -eq 1 ]; then + echo "formatting diff found 💔" + return 1 + fi + done + + echo "no diff found 😊" +} + +main diff --git a/src/tools/rustfmt/ci/integration.sh b/src/tools/rustfmt/ci/integration.sh index 562d5d70c70..19d502bc5c7 100755 --- a/src/tools/rustfmt/ci/integration.sh +++ b/src/tools/rustfmt/ci/integration.sh @@ -91,14 +91,28 @@ case ${INTEGRATION} in cd - ;; crater) - git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git + git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git cd ${INTEGRATION} show_head check_fmt_with_lib_tests cd - ;; + bitflags) + git clone --depth=1 https://github.com/bitflags/${INTEGRATION}.git + cd ${INTEGRATION} + show_head + check_fmt_with_all_tests + cd - + ;; + error-chain | tempdir) + git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git + cd ${INTEGRATION} + show_head + check_fmt_with_all_tests + cd - + ;; *) - git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git + git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git cd ${INTEGRATION} show_head check_fmt_with_all_tests diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.lock b/src/tools/rustfmt/config_proc_macro/Cargo.lock index ecf561f28fb..49f2f72a8d2 100644 --- a/src/tools/rustfmt/config_proc_macro/Cargo.lock +++ b/src/tools/rustfmt/config_proc_macro/Cargo.lock @@ -22,7 +22,7 @@ dependencies = [ [[package]] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.toml b/src/tools/rustfmt/config_proc_macro/Cargo.toml index a41b3a5e6bf..d10d0469cc4 100644 --- a/src/tools/rustfmt/config_proc_macro/Cargo.toml +++ b/src/tools/rustfmt/config_proc_macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustfmt-config_proc_macro" -version = "0.2.0" +version = "0.3.0" edition = "2018" description = "A collection of procedural macros for rustfmt" license = "Apache-2.0/MIT" diff --git a/src/tools/rustfmt/config_proc_macro/src/attrs.rs b/src/tools/rustfmt/config_proc_macro/src/attrs.rs index 0baba046f9e..dd18ff572cb 100644 --- a/src/tools/rustfmt/config_proc_macro/src/attrs.rs +++ b/src/tools/rustfmt/config_proc_macro/src/attrs.rs @@ -1,8 +1,10 @@ //! This module provides utilities for handling attributes on variants -//! of `config_type` enum. Currently there are two types of attributes -//! that could appear on the variants of `config_type` enum: `doc_hint` -//! and `value`. Both comes in the form of name-value pair whose value -//! is string literal. +//! of `config_type` enum. Currently there are the following attributes +//! that could appear on the variants of `config_type` enum: +//! +//! - `doc_hint`: name-value pair whose value is string literal +//! - `value`: name-value pair whose value is string literal +//! - `unstable_variant`: name only /// Returns the value of the first `doc_hint` attribute in the given slice or /// `None` if `doc_hint` attribute is not available. @@ -27,6 +29,11 @@ pub fn find_config_value(attrs: &[syn::Attribute]) -> Option<String> { attrs.iter().filter_map(config_value).next() } +/// Returns `true` if the there is at least one `unstable` attribute in the given slice. +pub fn any_unstable_variant(attrs: &[syn::Attribute]) -> bool { + attrs.iter().any(is_unstable_variant) +} + /// Returns a string literal value if the given attribute is `value` /// attribute or `None` otherwise. pub fn config_value(attr: &syn::Attribute) -> Option<String> { @@ -38,6 +45,11 @@ pub fn is_config_value(attr: &syn::Attribute) -> bool { is_attr_name_value(attr, "value") } +/// Returns `true` if the given attribute is an `unstable` attribute. +pub fn is_unstable_variant(attr: &syn::Attribute) -> bool { + is_attr_path(attr, "unstable_variant") +} + fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { attr.parse_meta().ok().map_or(false, |meta| match meta { syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true, @@ -45,6 +57,13 @@ fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { }) } +fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool { + attr.parse_meta().ok().map_or(false, |meta| match meta { + syn::Meta::Path(path) if path.is_ident(name) => true, + _ => false, + }) +} + fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> { attr.parse_meta().ok().and_then(|meta| match meta { syn::Meta::NameValue(syn::MetaNameValue { diff --git a/src/tools/rustfmt/config_proc_macro/src/item_enum.rs b/src/tools/rustfmt/config_proc_macro/src/item_enum.rs index dcee77a8549..731a7ea0607 100644 --- a/src/tools/rustfmt/config_proc_macro/src/item_enum.rs +++ b/src/tools/rustfmt/config_proc_macro/src/item_enum.rs @@ -1,5 +1,6 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; use crate::attrs::*; use crate::utils::*; @@ -47,12 +48,23 @@ fn process_variant(variant: &syn::Variant) -> TokenStream { let metas = variant .attrs .iter() - .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr)); + .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr) && !is_unstable_variant(attr)); let attrs = fold_quote(metas, |meta| quote!(#meta)); let syn::Variant { ident, fields, .. } = variant; quote!(#attrs #ident #fields) } +/// Return the correct syntax to pattern match on the enum variant, discarding all +/// internal field data. +fn fields_in_variant(variant: &syn::Variant) -> TokenStream { + // With thanks to https://stackoverflow.com/a/65182902 + match &variant.fields { + syn::Fields::Unnamed(_) => quote_spanned! { variant.span() => (..) }, + syn::Fields::Unit => quote_spanned! { variant.span() => }, + syn::Fields::Named(_) => quote_spanned! { variant.span() => {..} }, + } +} + fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream { let doc_hint = variants .iter() @@ -60,12 +72,26 @@ fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream { .collect::<Vec<_>>() .join("|"); let doc_hint = format!("[{}]", doc_hint); + + let variant_stables = variants + .iter() + .map(|v| (&v.ident, fields_in_variant(&v), !unstable_of_variant(v))); + let match_patterns = fold_quote(variant_stables, |(v, fields, stable)| { + quote! { + #ident::#v #fields => #stable, + } + }); quote! { use crate::config::ConfigType; impl ConfigType for #ident { fn doc_hint() -> String { #doc_hint.to_owned() } + fn stable_variant(&self) -> bool { + match self { + #match_patterns + } + } } } } @@ -123,13 +149,21 @@ fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream { } fn doc_hint_of_variant(variant: &syn::Variant) -> String { - find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string()) + let mut text = find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string()); + if unstable_of_variant(&variant) { + text.push_str(" (unstable)") + }; + text } fn config_value_of_variant(variant: &syn::Variant) -> String { find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string()) } +fn unstable_of_variant(variant: &syn::Variant) -> bool { + any_unstable_variant(&variant.attrs) +} + fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream { let arms = fold_quote(variants.iter(), |v| { let v_ident = &v.ident; diff --git a/src/tools/rustfmt/config_proc_macro/src/lib.rs b/src/tools/rustfmt/config_proc_macro/src/lib.rs index e772c53f423..0c54c132c97 100644 --- a/src/tools/rustfmt/config_proc_macro/src/lib.rs +++ b/src/tools/rustfmt/config_proc_macro/src/lib.rs @@ -69,3 +69,16 @@ pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream { TokenStream::from_str("").unwrap() } } + +/// Used to conditionally output the TokenStream for tests that should be run as part of rustfmts +/// test suite, but should be ignored when running in the rust-lang/rust test suite. +#[proc_macro_attribute] +pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStream { + if option_env!("RUSTFMT_CI").is_some() { + input + } else { + let mut token_stream = TokenStream::from_str("#[ignore]").unwrap(); + token_stream.extend(input); + token_stream + } +} diff --git a/src/tools/rustfmt/config_proc_macro/tests/smoke.rs b/src/tools/rustfmt/config_proc_macro/tests/smoke.rs index 940a8a0c251..c8a83e39c9e 100644 --- a/src/tools/rustfmt/config_proc_macro/tests/smoke.rs +++ b/src/tools/rustfmt/config_proc_macro/tests/smoke.rs @@ -1,6 +1,7 @@ pub mod config { pub trait ConfigType: Sized { fn doc_hint() -> String; + fn stable_variant(&self) -> bool; } } diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain index 2640a9e0ecc..22283b3d620 100644 --- a/src/tools/rustfmt/rust-toolchain +++ b/src/tools/rustfmt/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-06-21" -components = ["rustc-dev"] +channel = "nightly-2023-01-24" +components = ["llvm-tools", "rustc-dev"] diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index c503eeeb9b3..5648e1254ed 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -336,7 +336,7 @@ impl Rewrite for ast::Attribute { } else { let should_skip = self .ident() - .map(|s| context.skip_context.skip_attribute(s.name.as_str())) + .map(|s| context.skip_context.attributes.skip(s.name.as_str())) .unwrap_or(false); let prefix = attr_prefix(self); @@ -390,7 +390,7 @@ impl Rewrite for [ast::Attribute] { // Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]` // or `#![rustfmt::skip::attributes(derive)]` - let skip_derives = context.skip_context.skip_attribute("derive"); + let skip_derives = context.skip_context.attributes.skip("derive"); // This is not just a simple map because we need to handle doc comments // (where we take as many doc comment attributes as possible) and possibly diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 8e871e61f26..be64559e877 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -136,7 +136,7 @@ fn make_opts() -> Options { "l", "files-with-diff", "Prints the names of mismatched files that were formatted. Prints the names of \ - files that would be formated when used with `--check` mode. ", + files that would be formatted when used with `--check` mode. ", ); opts.optmulti( "", diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs index 9031d29b45f..2b714b68df0 100644 --- a/src/tools/rustfmt/src/cargo-fmt/main.rs +++ b/src/tools/rustfmt/src/cargo-fmt/main.rs @@ -198,12 +198,10 @@ fn convert_message_format_to_rustfmt_args( Ok(()) } "human" => Ok(()), - _ => { - return Err(format!( - "invalid --message-format value: {}. Allowed values are: short|json|human", - message_format - )); - } + _ => Err(format!( + "invalid --message-format value: {}. Allowed values are: short|json|human", + message_format + )), } } @@ -215,7 +213,7 @@ fn print_usage_to_stderr(reason: &str) { .expect("failed to write to stderr"); } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Verbosity { Verbose, Normal, diff --git a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs index 56e52fbabb6..696326e4f94 100644 --- a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs +++ b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs @@ -70,9 +70,9 @@ fn mandatory_separator() { .is_err() ); assert!( - !Opts::command() + Opts::command() .try_get_matches_from(&["test", "--", "--emit"]) - .is_err() + .is_ok() ); } diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs index a1a73cf4bd5..39b8d687809 100644 --- a/src/tools/rustfmt/src/chains.rs +++ b/src/tools/rustfmt/src/chains.rs @@ -70,10 +70,64 @@ use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::utils::{ - self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident, - trimmed_last_line_width, wrap_str, + self, filtered_str_fits, first_line_width, last_line_extendable, last_line_width, mk_sp, + rewrite_ident, trimmed_last_line_width, wrap_str, }; +/// Provides the original input contents from the span +/// of a chain element with trailing spaces trimmed. +fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option<String> { + context.snippet_provider.span_to_snippet(span).map(|s| { + s.lines() + .map(|l| l.trim_end()) + .collect::<Vec<_>>() + .join("\n") + }) +} + +fn format_chain_item( + item: &ChainItem, + context: &RewriteContext<'_>, + rewrite_shape: Shape, + allow_overflow: bool, +) -> Option<String> { + if allow_overflow { + item.rewrite(context, rewrite_shape) + .or_else(|| format_overflow_style(item.span, context)) + } else { + item.rewrite(context, rewrite_shape) + } +} + +fn get_block_child_shape( + prev_ends_with_block: bool, + context: &RewriteContext<'_>, + shape: Shape, +) -> Shape { + if prev_ends_with_block { + shape.block_indent(0) + } else { + shape.block_indent(context.config.tab_spaces()) + } + .with_max_width(context.config) +} + +fn get_visual_style_child_shape( + context: &RewriteContext<'_>, + shape: Shape, + offset: usize, + parent_overflowing: bool, +) -> Option<Shape> { + if !parent_overflowing { + shape + .with_max_width(context.config) + .offset_left(offset) + .map(|s| s.visual_indent(0)) + } else { + Some(shape.visual_indent(offset)) + } +} + pub(crate) fn rewrite_chain( expr: &ast::Expr, context: &RewriteContext<'_>, @@ -496,6 +550,8 @@ struct ChainFormatterShared<'a> { // The number of children in the chain. This is not equal to `self.children.len()` // because `self.children` will change size as we process the chain. child_count: usize, + // Whether elements are allowed to overflow past the max_width limit + allow_overflow: bool, } impl<'a> ChainFormatterShared<'a> { @@ -505,6 +561,8 @@ impl<'a> ChainFormatterShared<'a> { rewrites: Vec::with_capacity(chain.children.len() + 1), fits_single_line: false, child_count: chain.children.len(), + // TODO(calebcartwright) + allow_overflow: false, } } @@ -517,6 +575,14 @@ impl<'a> ChainFormatterShared<'a> { } } + fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { + for item in &self.children[..self.children.len() - 1] { + let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?; + self.rewrites.push(rewrite); + } + Some(()) + } + // Rewrite the last child. The last child of a chain requires special treatment. We need to // know whether 'overflowing' the last child make a better formatting: // @@ -729,22 +795,12 @@ impl<'a> ChainFormatter for ChainFormatterBlock<'a> { } fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> { - Some( - if self.root_ends_with_block { - shape.block_indent(0) - } else { - shape.block_indent(context.config.tab_spaces()) - } - .with_max_width(context.config), - ) + let block_end = self.root_ends_with_block; + Some(get_block_child_shape(block_end, context, shape)) } fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { - for item in &self.shared.children[..self.shared.children.len() - 1] { - let rewrite = item.rewrite(context, child_shape)?; - self.shared.rewrites.push(rewrite); - } - Some(()) + self.shared.format_children(context, child_shape) } fn format_last_child( @@ -808,15 +864,14 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> { .visual_indent(self.offset) .sub_width(self.offset)?; let rewrite = item.rewrite(context, child_shape)?; - match wrap_str(rewrite, context.config.max_width(), shape) { - Some(rewrite) => root_rewrite.push_str(&rewrite), - None => { - // We couldn't fit in at the visual indent, try the last - // indent. - let rewrite = item.rewrite(context, parent_shape)?; - root_rewrite.push_str(&rewrite); - self.offset = 0; - } + if filtered_str_fits(&rewrite, context.config.max_width(), shape) { + root_rewrite.push_str(&rewrite); + } else { + // We couldn't fit in at the visual indent, try the last + // indent. + let rewrite = item.rewrite(context, parent_shape)?; + root_rewrite.push_str(&rewrite); + self.offset = 0; } self.shared.children = &self.shared.children[1..]; @@ -827,18 +882,17 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> { } fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> { - shape - .with_max_width(context.config) - .offset_left(self.offset) - .map(|s| s.visual_indent(0)) + get_visual_style_child_shape( + context, + shape, + self.offset, + // TODO(calebcartwright): self.shared.permissibly_overflowing_parent, + false, + ) } fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { - for item in &self.shared.children[..self.shared.children.len() - 1] { - let rewrite = item.rewrite(context, child_shape)?; - self.shared.rewrites.push(rewrite); - } - Some(()) + self.shared.format_children(context, child_shape) } fn format_last_child( diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs index c5e61658ad1..54ca7676dfc 100644 --- a/src/tools/rustfmt/src/config/config_type.rs +++ b/src/tools/rustfmt/src/config/config_type.rs @@ -1,4 +1,5 @@ use crate::config::file_lines::FileLines; +use crate::config::macro_names::MacroSelectors; use crate::config::options::{IgnoreList, WidthHeuristics}; /// Trait for types that can be used in `Config`. @@ -6,6 +7,14 @@ pub(crate) trait ConfigType: Sized { /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a /// pipe-separated list of variants; for other types it returns `<type>`. fn doc_hint() -> String; + + /// Return `true` if the variant (i.e. value of this type) is stable. + /// + /// By default, return true for all values. Enums annotated with `#[config_type]` + /// are automatically implemented, based on the `#[unstable_variant]` annotation. + fn stable_variant(&self) -> bool { + true + } } impl ConfigType for bool { @@ -38,6 +47,12 @@ impl ConfigType for FileLines { } } +impl ConfigType for MacroSelectors { + fn doc_hint() -> String { + String::from("[<string>, ...]") + } +} + impl ConfigType for WidthHeuristics { fn doc_hint() -> String { String::new() @@ -51,6 +66,13 @@ impl ConfigType for IgnoreList { } macro_rules! create_config { + // Options passed in to the macro. + // + // - $i: the ident name of the option + // - $ty: the type of the option value + // - $def: the default value of the option + // - $stb: true if the option is stable + // - $dstring: description of the option ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => ( #[cfg(test)] use std::collections::HashSet; @@ -61,9 +83,12 @@ macro_rules! create_config { #[derive(Clone)] #[allow(unreachable_pub)] pub struct Config { - // For each config item, we store a bool indicating whether it has - // been accessed and the value, and a bool whether the option was - // manually initialised, or taken from the default, + // For each config item, we store: + // + // - 0: true if the value has been access + // - 1: true if the option was manually initialized + // - 2: the option value + // - 3: true if the option is unstable $($i: (Cell<bool>, bool, $ty, bool)),+ } @@ -102,6 +127,7 @@ macro_rules! create_config { | "array_width" | "chain_width" => self.0.set_heuristics(), "merge_imports" => self.0.set_merge_imports(), + "fn_args_layout" => self.0.set_fn_args_layout(), &_ => (), } } @@ -143,24 +169,20 @@ macro_rules! create_config { fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config { $( - if let Some(val) = parsed.$i { - if self.$i.3 { + if let Some(option_value) = parsed.$i { + let option_stable = self.$i.3; + if $crate::config::config_type::is_stable_option_and_value( + stringify!($i), option_stable, &option_value + ) { self.$i.1 = true; - self.$i.2 = val; - } else { - if crate::is_nightly_channel!() { - self.$i.1 = true; - self.$i.2 = val; - } else { - eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \ - available in nightly channel.", stringify!($i), val); - } + self.$i.2 = option_value; } } )+ self.set_heuristics(); self.set_ignore(dir); self.set_merge_imports(); + self.set_fn_args_layout(); self } @@ -221,12 +243,22 @@ macro_rules! create_config { match key { $( stringify!($i) => { - self.$i.1 = true; - self.$i.2 = val.parse::<$ty>() + let option_value = val.parse::<$ty>() .expect(&format!("Failed to parse override for {} (\"{}\") as a {}", stringify!($i), val, stringify!($ty))); + + // Users are currently allowed to set unstable + // options/variants via the `--config` options override. + // + // There is ongoing discussion about how to move forward here: + // https://github.com/rust-lang/rustfmt/pull/5379 + // + // For now, do not validate whether the option or value is stable, + // just always set it. + self.$i.1 = true; + self.$i.2 = option_value; } )+ _ => panic!("Unknown config key in override: {}", key) @@ -243,14 +275,21 @@ macro_rules! create_config { | "array_width" | "chain_width" => self.set_heuristics(), "merge_imports" => self.set_merge_imports(), + "fn_args_layout" => self.set_fn_args_layout(), &_ => (), } } #[allow(unreachable_pub)] pub fn is_hidden_option(name: &str) -> bool { - const HIDE_OPTIONS: [&str; 5] = - ["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"]; + const HIDE_OPTIONS: [&str; 6] = [ + "verbose", + "verbose_diff", + "file_lines", + "width_heuristics", + "merge_imports", + "fn_args_layout" + ]; HIDE_OPTIONS.contains(&name) } @@ -400,6 +439,18 @@ macro_rules! create_config { } } + fn set_fn_args_layout(&mut self) { + if self.was_set().fn_args_layout() { + eprintln!( + "Warning: the `fn_args_layout` option is deprecated. \ + Use `fn_params_layout`. instead" + ); + if !self.was_set().fn_params_layout() { + self.fn_params_layout.2 = self.fn_args_layout(); + } + } + } + #[allow(unreachable_pub)] /// Returns `true` if the config key was explicitly set and is the default value. pub fn is_default(&self, key: &str) -> bool { @@ -424,3 +475,38 @@ macro_rules! create_config { } ) } + +pub(crate) fn is_stable_option_and_value<T>( + option_name: &str, + option_stable: bool, + option_value: &T, +) -> bool +where + T: PartialEq + std::fmt::Debug + ConfigType, +{ + let nightly = crate::is_nightly_channel!(); + let variant_stable = option_value.stable_variant(); + match (nightly, option_stable, variant_stable) { + // Stable with an unstable option + (false, false, _) => { + eprintln!( + "Warning: can't set `{} = {:?}`, unstable features are only \ + available in nightly channel.", + option_name, option_value + ); + false + } + // Stable with a stable option, but an unstable variant + (false, true, false) => { + eprintln!( + "Warning: can't set `{} = {:?}`, unstable variants are only \ + available in nightly channel.", + option_name, option_value + ); + false + } + // Nightly: everything allowed + // Stable with stable option and variant: allowed + (true, _, _) | (false, true, true) => true, + } +} diff --git a/src/tools/rustfmt/src/config/macro_names.rs b/src/tools/rustfmt/src/config/macro_names.rs new file mode 100644 index 00000000000..26ad78d6dca --- /dev/null +++ b/src/tools/rustfmt/src/config/macro_names.rs @@ -0,0 +1,118 @@ +//! This module contains types and functions to support formatting specific macros. + +use itertools::Itertools; +use std::{fmt, str}; + +use serde::{Deserialize, Serialize}; +use serde_json as json; +use thiserror::Error; + +/// Defines the name of a macro. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +pub struct MacroName(String); + +impl MacroName { + pub fn new(other: String) -> Self { + Self(other) + } +} + +impl fmt::Display for MacroName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl From<MacroName> for String { + fn from(other: MacroName) -> Self { + other.0 + } +} + +/// Defines a selector to match against a macro. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +pub enum MacroSelector { + Name(MacroName), + All, +} + +impl fmt::Display for MacroSelector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Name(name) => name.fmt(f), + Self::All => write!(f, "*"), + } + } +} + +impl str::FromStr for MacroSelector { + type Err = std::convert::Infallible; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(match s { + "*" => MacroSelector::All, + name => MacroSelector::Name(MacroName(name.to_owned())), + }) + } +} + +/// A set of macro selectors. +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct MacroSelectors(pub Vec<MacroSelector>); + +impl fmt::Display for MacroSelectors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.iter().format(", ")) + } +} + +#[derive(Error, Debug)] +pub enum MacroSelectorsError { + #[error("{0}")] + Json(json::Error), +} + +// This impl is needed for `Config::override_value` to work for use in tests. +impl str::FromStr for MacroSelectors { + type Err = MacroSelectorsError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let raw: Vec<&str> = json::from_str(s).map_err(MacroSelectorsError::Json)?; + Ok(Self( + raw.into_iter() + .map(|raw| { + MacroSelector::from_str(raw).expect("MacroSelector from_str is infallible") + }) + .collect(), + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::str::FromStr; + + #[test] + fn macro_names_from_str() { + let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap(); + assert_eq!( + macro_names, + MacroSelectors( + [ + MacroSelector::Name(MacroName("foo".to_owned())), + MacroSelector::All, + MacroSelector::Name(MacroName("bar".to_owned())) + ] + .into_iter() + .collect() + ) + ); + } + + #[test] + fn macro_names_display() { + let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap(); + assert_eq!(format!("{}", macro_names), "foo, *, bar"); + } +} diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs index f49c18d3a46..14f27f3f8b6 100644 --- a/src/tools/rustfmt/src/config/mod.rs +++ b/src/tools/rustfmt/src/config/mod.rs @@ -13,15 +13,20 @@ pub use crate::config::file_lines::{FileLines, FileName, Range}; #[allow(unreachable_pub)] pub use crate::config::lists::*; #[allow(unreachable_pub)] +pub use crate::config::macro_names::{MacroSelector, MacroSelectors}; +#[allow(unreachable_pub)] pub use crate::config::options::*; #[macro_use] pub(crate) mod config_type; #[macro_use] +#[allow(unreachable_pub)] pub(crate) mod options; pub(crate) mod file_lines; +#[allow(unreachable_pub)] pub(crate) mod lists; +pub(crate) mod macro_names; // This macro defines configuration options used in rustfmt. Each option // is defined as follows: @@ -67,6 +72,8 @@ create_config! { format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros"; + skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false, + "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, "Format hexadecimal integer literals"; @@ -119,7 +126,9 @@ create_config! { force_multiline_blocks: bool, false, false, "Force multiline closure bodies and match arms to be wrapped in a block"; fn_args_layout: Density, Density::Tall, true, - "Control the layout of arguments in a function"; + "(deprecated: use fn_params_layout instead)"; + fn_params_layout: Density, Density::Tall, true, + "Control the layout of parameters in function signatures."; brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items"; control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false, "Brace style for control flow constructs"; @@ -175,7 +184,7 @@ create_config! { make_backup: bool, false, false, "Backup changed files"; print_misformatted_file_names: bool, false, true, "Prints the names of mismatched files that were formatted. Prints the names of \ - files that would be formated when used with `--check` mode. "; + files that would be formatted when used with `--check` mode. "; } #[derive(Error, Debug)] @@ -191,6 +200,7 @@ impl PartialConfig { cloned.width_heuristics = None; cloned.print_misformatted_file_names = None; cloned.merge_imports = None; + cloned.fn_args_layout = None; ::toml::to_string(&cloned).map_err(ToTomlError) } @@ -403,11 +413,21 @@ mod test { use super::*; use std::str; + use crate::config::macro_names::MacroName; use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; #[allow(dead_code)] mod mock { use super::super::*; + use rustfmt_config_proc_macro::config_type; + + #[config_type] + pub(crate) enum PartiallyUnstableOption { + V1, + V2, + #[unstable_variant] + V3, + } create_config! { // Options that are used by the generated functions @@ -427,6 +447,12 @@ mod test { "Merge imports"; merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)"; + // fn_args_layout renamed to fn_params_layout + fn_args_layout: Density, Density::Tall, true, + "(deprecated: use fn_params_layout instead)"; + fn_params_layout: Density, Density::Tall, true, + "Control the layout of parameters in a function signatures."; + // Width Heuristics use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different formatting for items and \ @@ -451,6 +477,63 @@ mod test { // Options that are used by the tests stable_option: bool, false, true, "A stable option"; unstable_option: bool, false, false, "An unstable option"; + partially_unstable_option: PartiallyUnstableOption, PartiallyUnstableOption::V1, true, + "A partially unstable option"; + } + + #[cfg(test)] + mod partially_unstable_option { + use super::{Config, PartialConfig, PartiallyUnstableOption}; + use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; + use std::path::Path; + + /// From the config file, we can fill with a stable variant + #[test] + fn test_from_toml_stable_value() { + let toml = r#" + partially_unstable_option = "V2" + "#; + let partial_config: PartialConfig = toml::from_str(toml).unwrap(); + let config = Config::default(); + let config = config.fill_from_parsed_config(partial_config, Path::new("")); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V2 + ); + } + + /// From the config file, we cannot fill with an unstable variant (stable only) + #[stable_only_test] + #[test] + fn test_from_toml_unstable_value_on_stable() { + let toml = r#" + partially_unstable_option = "V3" + "#; + let partial_config: PartialConfig = toml::from_str(toml).unwrap(); + let config = Config::default(); + let config = config.fill_from_parsed_config(partial_config, Path::new("")); + assert_eq!( + config.partially_unstable_option(), + // default value from config, i.e. fill failed + PartiallyUnstableOption::V1 + ); + } + + /// From the config file, we can fill with an unstable variant (nightly only) + #[nightly_only_test] + #[test] + fn test_from_toml_unstable_value_on_nightly() { + let toml = r#" + partially_unstable_option = "V3" + "#; + let partial_config: PartialConfig = toml::from_str(toml).unwrap(); + let config = Config::default(); + let config = config.fill_from_parsed_config(partial_config, Path::new("")); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V3 + ); + } } } @@ -489,6 +572,11 @@ mod test { assert_eq!(config.was_set().verbose(), false); } + const PRINT_DOCS_STABLE_OPTION: &str = "stable_option <boolean> Default: false"; + const PRINT_DOCS_UNSTABLE_OPTION: &str = "unstable_option <boolean> Default: false (unstable)"; + const PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION: &str = + "partially_unstable_option [V1|V2|V3 (unstable)] Default: V1"; + #[test] fn test_print_docs_exclude_unstable() { use self::mock::Config; @@ -497,10 +585,9 @@ mod test { Config::print_docs(&mut output, false); let s = str::from_utf8(&output).unwrap(); - - assert_eq!(s.contains("stable_option"), true); - assert_eq!(s.contains("unstable_option"), false); - assert_eq!(s.contains("(unstable)"), false); + assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true); + assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), false); + assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true); } #[test] @@ -511,9 +598,9 @@ mod test { Config::print_docs(&mut output, true); let s = str::from_utf8(&output).unwrap(); - assert_eq!(s.contains("stable_option"), true); - assert_eq!(s.contains("unstable_option"), true); - assert_eq!(s.contains("(unstable)"), true); + assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true); + assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), true); + assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true); } #[test] @@ -541,6 +628,7 @@ normalize_doc_attributes = false format_strings = false format_macro_matchers = false format_macro_bodies = true +skip_macro_invocations = [] hex_literal_case = "Preserve" empty_item_single_line = true struct_lit_single_line = true @@ -567,7 +655,7 @@ enum_discrim_align_threshold = 0 match_arm_blocks = true match_arm_leading_pipes = "Never" force_multiline_blocks = false -fn_args_layout = "Tall" +fn_params_layout = "Tall" brace_style = "SameLineWhere" control_brace_style = "AlwaysSameLine" trailing_semicolon = true @@ -921,4 +1009,45 @@ make_backup = false assert_eq!(config.single_line_if_else_max_width(), 100); } } + + #[cfg(test)] + mod partially_unstable_option { + use super::mock::{Config, PartiallyUnstableOption}; + use super::*; + + /// From the command line, we can override with a stable variant. + #[test] + fn test_override_stable_value() { + let mut config = Config::default(); + config.override_value("partially_unstable_option", "V2"); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V2 + ); + } + + /// From the command line, we can override with an unstable variant. + #[test] + fn test_override_unstable_value() { + let mut config = Config::default(); + config.override_value("partially_unstable_option", "V3"); + assert_eq!( + config.partially_unstable_option(), + PartiallyUnstableOption::V3 + ); + } + } + + #[test] + fn test_override_skip_macro_invocations() { + let mut config = Config::default(); + config.override_value("skip_macro_invocations", r#"["*", "println"]"#); + assert_eq!( + config.skip_macro_invocations(), + MacroSelectors(vec![ + MacroSelector::All, + MacroSelector::Name(MacroName::new("println".to_owned())) + ]) + ); + } } diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 868ff045ab7..3f0f217f890 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -29,9 +29,9 @@ use crate::spanned::Spanned; use crate::string::{rewrite_string, StringFormat}; use crate::types::{rewrite_path, PathContext}; use crate::utils::{ - colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes, - last_line_extendable, last_line_width, mk_sp, outer_attributes, semicolon_for_expr, - unicode_str_width, wrap_str, + colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with, + inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes, + semicolon_for_expr, unicode_str_width, wrap_str, }; use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; @@ -400,7 +400,10 @@ pub(crate) fn format_expr( } } ast::ExprKind::Underscore => Some("_".to_owned()), - ast::ExprKind::IncludedBytes(..) => unreachable!(), + ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) => { + // These do not occur in the AST because macros aren't expanded. + unreachable!() + } ast::ExprKind::Err => None, }; @@ -2050,8 +2053,7 @@ fn choose_rhs<R: Rewrite>( match (orig_rhs, new_rhs) { (Some(ref orig_rhs), Some(ref new_rhs)) - if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape) - .is_none() => + if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) => { Some(format!("{}{}", before_space_str, orig_rhs)) } diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs index d9dc8d004af..339e5cef5af 100644 --- a/src/tools/rustfmt/src/imports.rs +++ b/src/tools/rustfmt/src/imports.rs @@ -251,8 +251,8 @@ fn flatten_use_trees( use_trees: Vec<UseTree>, import_granularity: ImportGranularity, ) -> Vec<UseTree> { - // Return non-sorted single occurance of the use-trees text string; - // order is by first occurance of the use-tree. + // Return non-sorted single occurrence of the use-trees text string; + // order is by first occurrence of the use-tree. use_trees .into_iter() .flat_map(|tree| tree.flatten(import_granularity)) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index a2a73f0a5fb..25e8a024857 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1084,7 +1084,11 @@ pub(crate) fn format_trait( let item_snippet = context.snippet(item.span); if let Some(lo) = item_snippet.find('/') { // 1 = `{` - let comment_hi = body_lo - BytePos(1); + let comment_hi = if generics.params.len() > 0 { + generics.span.lo() - BytePos(1) + } else { + body_lo - BytePos(1) + }; let comment_lo = item.span.lo() + BytePos(lo as u32); if comment_lo < comment_hi { match recover_missing_comment_in_span( @@ -1241,7 +1245,7 @@ fn format_unit_struct( ) -> Option<String> { let header_str = format_header(context, p.prefix, p.ident, p.vis, offset); let generics_str = if let Some(generics) = p.generics { - let hi = context.snippet_provider.span_before(p.span, ";"); + let hi = context.snippet_provider.span_before_last(p.span, ";"); format_generics( context, generics, @@ -2602,7 +2606,7 @@ fn rewrite_params( ¶m_items, context .config - .fn_args_layout() + .fn_params_layout() .to_list_tactic(param_items.len()), Separator::Comma, one_line_budget, diff --git a/src/tools/rustfmt/src/lists.rs b/src/tools/rustfmt/src/lists.rs index e8785050782..a878e6cf9b2 100644 --- a/src/tools/rustfmt/src/lists.rs +++ b/src/tools/rustfmt/src/lists.rs @@ -297,9 +297,9 @@ where } else { inner_item.as_ref() }; - let mut item_last_line_width = item_last_line.len() + item_sep_len; + let mut item_last_line_width = unicode_str_width(item_last_line) + item_sep_len; if item_last_line.starts_with(&**indent_str) { - item_last_line_width -= indent_str.len(); + item_last_line_width -= unicode_str_width(indent_str); } if !item.is_substantial() { @@ -449,7 +449,7 @@ where } else if starts_with_newline(comment) { false } else { - comment.trim().contains('\n') || comment.trim().len() > width + comment.trim().contains('\n') || unicode_str_width(comment.trim()) > width }; rewrite_comment( @@ -465,7 +465,7 @@ where if !starts_with_newline(comment) { if formatting.align_comments { let mut comment_alignment = - post_comment_alignment(item_max_width, inner_item.len()); + post_comment_alignment(item_max_width, unicode_str_width(inner_item)); if first_line_width(&formatted_comment) + last_line_width(&result) + comment_alignment @@ -475,7 +475,7 @@ where item_max_width = None; formatted_comment = rewrite_post_comment(&mut item_max_width)?; comment_alignment = - post_comment_alignment(item_max_width, inner_item.len()); + post_comment_alignment(item_max_width, unicode_str_width(inner_item)); } for _ in 0..=comment_alignment { result.push(' '); @@ -533,7 +533,7 @@ where let mut first = true; for item in items.clone().into_iter().skip(i) { let item = item.as_ref(); - let inner_item_width = item.inner_as_ref().len(); + let inner_item_width = unicode_str_width(item.inner_as_ref()); if !first && (item.is_different_group() || item.post_comment.is_none() @@ -552,8 +552,8 @@ where max_width } -fn post_comment_alignment(item_max_width: Option<usize>, inner_item_len: usize) -> usize { - item_max_width.unwrap_or(0).saturating_sub(inner_item_len) +fn post_comment_alignment(item_max_width: Option<usize>, inner_item_width: usize) -> usize { + item_max_width.unwrap_or(0).saturating_sub(inner_item_width) } pub(crate) struct ListItems<'a, I, F1, F2, F3> diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index df949388037..d58f7547fef 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -35,8 +35,8 @@ use crate::shape::{Indent, Shape}; use crate::source_map::SpanUtils; use crate::spanned::Spanned; use crate::utils::{ - format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces, - rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt, + filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp, + remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout, NodeIdExt, }; use crate::visitor::FmtVisitor; @@ -157,7 +157,8 @@ pub(crate) fn rewrite_macro( ) -> Option<String> { let should_skip = context .skip_context - .skip_macro(context.snippet(mac.path.span)); + .macros + .skip(context.snippet(mac.path.span)); if should_skip { None } else { @@ -1265,15 +1266,14 @@ impl MacroBranch { } } }; - let new_body = wrap_str( - new_body_snippet.snippet.to_string(), - config.max_width(), - shape, - )?; + + if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) { + return None; + } // Indent the body since it is in a block. let indent_str = body_indent.to_string(&config); - let mut new_body = LineClasses::new(new_body.trim_end()) + let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end()) .enumerate() .fold( (String::new(), true), diff --git a/src/tools/rustfmt/src/skip.rs b/src/tools/rustfmt/src/skip.rs index 032922d421d..68f85b2ade4 100644 --- a/src/tools/rustfmt/src/skip.rs +++ b/src/tools/rustfmt/src/skip.rs @@ -2,33 +2,84 @@ use rustc_ast::ast; use rustc_ast_pretty::pprust; +use std::collections::HashSet; -/// Take care of skip name stack. You can update it by attributes slice or -/// by other context. Query this context to know if you need skip a block. +/// Track which blocks of code are to be skipped when formatting. +/// +/// You can update it by: +/// +/// - attributes slice +/// - manually feeding values into the underlying contexts +/// +/// Query this context to know if you need to skip a block. #[derive(Default, Clone)] pub(crate) struct SkipContext { - macros: Vec<String>, - attributes: Vec<String>, + pub(crate) macros: SkipNameContext, + pub(crate) attributes: SkipNameContext, } impl SkipContext { pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) { - self.macros.append(&mut get_skip_names("macros", attrs)); - self.attributes - .append(&mut get_skip_names("attributes", attrs)); + self.macros.extend(get_skip_names("macros", attrs)); + self.attributes.extend(get_skip_names("attributes", attrs)); } - pub(crate) fn update(&mut self, mut other: SkipContext) { - self.macros.append(&mut other.macros); - self.attributes.append(&mut other.attributes); + pub(crate) fn update(&mut self, other: SkipContext) { + let SkipContext { macros, attributes } = other; + self.macros.update(macros); + self.attributes.update(attributes); + } +} + +/// Track which names to skip. +/// +/// Query this context with a string to know whether to skip it. +#[derive(Clone)] +pub(crate) enum SkipNameContext { + All, + Values(HashSet<String>), +} + +impl Default for SkipNameContext { + fn default() -> Self { + Self::Values(Default::default()) + } +} + +impl Extend<String> for SkipNameContext { + fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) { + match self { + Self::All => {} + Self::Values(values) => values.extend(iter), + } + } +} + +impl SkipNameContext { + pub(crate) fn update(&mut self, other: Self) { + match (self, other) { + // If we're already skipping everything, nothing more can be added + (Self::All, _) => {} + // If we want to skip all, set it + (this, Self::All) => { + *this = Self::All; + } + // If we have some new values to skip, add them + (Self::Values(existing_values), Self::Values(new_values)) => { + existing_values.extend(new_values) + } + } } - pub(crate) fn skip_macro(&self, name: &str) -> bool { - self.macros.iter().any(|n| n == name) + pub(crate) fn skip(&self, name: &str) -> bool { + match self { + Self::All => true, + Self::Values(values) => values.contains(name), + } } - pub(crate) fn skip_attribute(&self, name: &str) -> bool { - self.attributes.iter().any(|n| n == name) + pub(crate) fn skip_all(&mut self) { + *self = Self::All; } } diff --git a/src/tools/rustfmt/src/test/configuration_snippet.rs b/src/tools/rustfmt/src/test/configuration_snippet.rs index c8fda7c8556..c70b3c5facd 100644 --- a/src/tools/rustfmt/src/test/configuration_snippet.rs +++ b/src/tools/rustfmt/src/test/configuration_snippet.rs @@ -27,8 +27,13 @@ impl ConfigurationSection { lazy_static! { static ref CONFIG_NAME_REGEX: regex::Regex = regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern"); + // Configuration values, which will be passed to `from_str`: + // + // - must be prefixed with `####` + // - must be wrapped in backticks + // - may by wrapped in double quotes (which will be stripped) static ref CONFIG_VALUE_REGEX: regex::Regex = - regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#) + regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#) .expect("failed creating configuration value pattern"); } diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs index 6b5bc2b30dd..cfad4a8ed0e 100644 --- a/src/tools/rustfmt/src/test/mod.rs +++ b/src/tools/rustfmt/src/test/mod.rs @@ -982,11 +982,7 @@ fn rustfmt() -> PathBuf { assert!( me.is_file() || me.with_extension("exe").is_file(), "{}", - if cfg!(release) { - "no rustfmt bin, try running `cargo build --release` before testing" - } else { - "no rustfmt bin, try running `cargo build` before testing" - } + "no rustfmt bin, try running `cargo build` or `cargo build --release` before testing" ); me } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index c1991e8d2c8..01e2fb6e61e 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -941,6 +941,28 @@ fn join_bounds_inner( ast::GenericBound::Trait(..) => last_line_extendable(s), }; + // Whether a GenericBound item is a PathSegment segment that includes internal array + // that contains more than one item + let is_item_with_multi_items_array = |item: &ast::GenericBound| match item { + ast::GenericBound::Trait(ref poly_trait_ref, ..) => { + let segments = &poly_trait_ref.trait_ref.path.segments; + if segments.len() > 1 { + true + } else { + if let Some(args_in) = &segments[0].args { + matches!( + args_in.deref(), + ast::GenericArgs::AngleBracketed(bracket_args) + if bracket_args.args.len() > 1 + ) + } else { + false + } + } + } + _ => false, + }; + let result = items.iter().enumerate().try_fold( (String::new(), None, false), |(strs, prev_trailing_span, prev_extendable), (i, item)| { @@ -1035,10 +1057,24 @@ fn join_bounds_inner( }, )?; - if !force_newline - && items.len() > 1 - && (result.0.contains('\n') || result.0.len() > shape.width) - { + // Whether to retry with a forced newline: + // Only if result is not already multiline and did not exceed line width, + // and either there is more than one item; + // or the single item is of type `Trait`, + // and any of the internal arrays contains more than one item; + let retry_with_force_newline = match context.config.version() { + Version::One => { + !force_newline + && items.len() > 1 + && (result.0.contains('\n') || result.0.len() > shape.width) + } + Version::Two if force_newline => false, + Version::Two if (!result.0.contains('\n') && result.0.len() <= shape.width) => false, + Version::Two if items.len() > 1 => true, + Version::Two => is_item_with_multi_items_array(&items[0]), + }; + + if retry_with_force_newline { join_bounds_inner(context, shape, items, need_indent, true) } else { Some(result.0) diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 3e884419f1a..1e89f3ae75f 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -384,14 +384,15 @@ macro_rules! skip_out_of_file_lines_range_visitor { // Wraps String in an Option. Returns Some when the string adheres to the // Rewrite constraints defined for the Rewrite trait and None otherwise. pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option<String> { - if is_valid_str(&filter_normal_code(&s), max_width, shape) { + if filtered_str_fits(&s, max_width, shape) { Some(s) } else { None } } -fn is_valid_str(snippet: &str, max_width: usize, shape: Shape) -> bool { +pub(crate) fn filtered_str_fits(snippet: &str, max_width: usize, shape: Shape) -> bool { + let snippet = &filter_normal_code(snippet); if !snippet.is_empty() { // First line must fits with `shape.width`. if first_line_width(snippet) > shape.width { @@ -462,6 +463,7 @@ pub(crate) fn first_line_ends_with(s: &str, c: char) -> bool { pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr: &str) -> bool { match expr.kind { ast::ExprKind::MacCall(..) + | ast::ExprKind::FormatArgs(..) | ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Array(..) diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 9c3cc7820d2..f4d84d1381f 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -8,7 +8,7 @@ use rustc_span::{symbol, BytePos, Pos, Span}; use crate::attr::*; use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}; use crate::config::Version; -use crate::config::{BraceStyle, Config}; +use crate::config::{BraceStyle, Config, MacroSelector}; use crate::coverage::transform_missing_snippet; use crate::items::{ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate, @@ -770,6 +770,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { snippet_provider: &'a SnippetProvider, report: FormatReport, ) -> FmtVisitor<'a> { + let mut skip_context = SkipContext::default(); + let mut macro_names = Vec::new(); + for macro_selector in config.skip_macro_invocations().0 { + match macro_selector { + MacroSelector::Name(name) => macro_names.push(name.to_string()), + MacroSelector::All => skip_context.macros.skip_all(), + } + } + skip_context.macros.extend(macro_names); FmtVisitor { parent_context: None, parse_sess: parse_session, @@ -784,7 +793,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { is_macro_def: false, macro_rewrite_failure: false, report, - skip_context: Default::default(), + skip_context, } } diff --git a/src/tools/rustfmt/tests/cargo-fmt/main.rs b/src/tools/rustfmt/tests/cargo-fmt/main.rs index 348876cd264..701c36fadea 100644 --- a/src/tools/rustfmt/tests/cargo-fmt/main.rs +++ b/src/tools/rustfmt/tests/cargo-fmt/main.rs @@ -4,6 +4,8 @@ use std::env; use std::path::Path; use std::process::Command; +use rustfmt_config_proc_macro::rustfmt_only_ci_test; + /// Run the cargo-fmt executable and return its output. fn cargo_fmt(args: &[&str]) -> (String, String) { let mut bin_dir = env::current_exe().unwrap(); @@ -47,7 +49,7 @@ macro_rules! assert_that { }; } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn version() { assert_that!(&["--version"], starts_with("rustfmt ")); @@ -56,7 +58,7 @@ fn version() { assert_that!(&["--", "--version"], starts_with("rustfmt ")); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn print_config() { assert_that!( @@ -65,7 +67,7 @@ fn print_config() { ); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn rustfmt_help() { assert_that!(&["--", "--help"], contains("Format Rust code")); @@ -73,7 +75,7 @@ fn rustfmt_help() { assert_that!(&["--", "--help=config"], contains("Configuration Options:")); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn cargo_fmt_out_of_line_test_modules() { // See also https://github.com/rust-lang/rustfmt/issues/5119 @@ -96,3 +98,22 @@ fn cargo_fmt_out_of_line_test_modules() { assert!(stdout.contains(&format!("Diff in {}", path.display()))) } } + +#[rustfmt_only_ci_test] +#[test] +fn cargo_fmt_emits_error_on_line_overflow_true() { + // See also https://github.com/rust-lang/rustfmt/issues/3164 + let args = [ + "--check", + "--manifest-path", + "tests/cargo-fmt/source/issue_3164/Cargo.toml", + "--", + "--config", + "error_on_line_overflow=true", + ]; + + let (_stdout, stderr) = cargo_fmt(&args); + assert!(stderr.contains( + "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" + )) +} diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml new file mode 100644 index 00000000000..580ef7e6e24 --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "issue_3164" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs new file mode 100644 index 00000000000..9330107ac8d --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs @@ -0,0 +1,13 @@ +#[allow(unused_macros)] +macro_rules! foo { + ($id:ident) => { + macro_rules! bar { + ($id2:tt) => { + #[cfg(any(target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2))] + fn $id() {} + }; + } + }; +} + +fn main() {} diff --git a/src/tools/rustfmt/tests/config/small_tabs.toml b/src/tools/rustfmt/tests/config/small_tabs.toml index c3cfd34317a..4c37100894f 100644 --- a/src/tools/rustfmt/tests/config/small_tabs.toml +++ b/src/tools/rustfmt/tests/config/small_tabs.toml @@ -3,7 +3,7 @@ comment_width = 80 tab_spaces = 2 newline_style = "Unix" brace_style = "SameLineWhere" -fn_args_layout = "Tall" +fn_params_layout = "Tall" trailing_comma = "Vertical" indent_style = "Block" reorder_imports = false diff --git a/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt b/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt index 92c9e302143..254102ebabd 100644 --- a/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt +++ b/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt @@ -9,7 +9,7 @@ The directory name './lib/c/d/' conflicts with the './lib/c/d.rs' file name. * mod g; Module resolution will fail if we look for './lib/c/d/e.rs' or './lib/c/d/e/mod.rs', -so we should fall back to looking for './lib/c/e.rs', which correctly finds the modlue, that +so we should fall back to looking for './lib/c/e.rs', which correctly finds the module, that rustfmt should format. './lib/c/d/f.rs' and './lib/c/d/g/mod.rs' exist at the default submodule paths so we should be able diff --git a/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/explanation.txt b/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/explanation.txt index d436a8076cd..90464def8eb 100644 --- a/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/explanation.txt +++ b/src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/explanation.txt @@ -9,7 +9,7 @@ The directory name './lib' conflicts with the './lib.rs' file name. * mod c; Module resolution will fail if we look for './lib/a.rs' or './lib/a/mod.rs', -so we should fall back to looking for './a.rs', which correctly finds the modlue that +so we should fall back to looking for './a.rs', which correctly finds the module that rustfmt should format. './lib/b.rs' and './lib/c/mod.rs' exist at the default submodule paths so we should be able diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs index 4c6d52726f3..7ff301e8019 100644 --- a/src/tools/rustfmt/tests/rustfmt/main.rs +++ b/src/tools/rustfmt/tests/rustfmt/main.rs @@ -5,6 +5,8 @@ use std::fs::remove_file; use std::path::Path; use std::process::Command; +use rustfmt_config_proc_macro::rustfmt_only_ci_test; + /// Run the rustfmt executable and return its output. fn rustfmt(args: &[&str]) -> (String, String) { let mut bin_dir = env::current_exe().unwrap(); @@ -47,7 +49,7 @@ macro_rules! assert_that { }; } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn print_config() { assert_that!( @@ -76,7 +78,7 @@ fn print_config() { remove_file("minimal-config").unwrap(); } -#[ignore] +#[rustfmt_only_ci_test] #[test] fn inline_config() { // single invocation @@ -157,3 +159,18 @@ fn mod_resolution_error_path_attribute_does_not_exist() { // The path attribute points to a file that does not exist assert!(stderr.contains("does_not_exist.rs does not exist")); } + +#[test] +fn rustfmt_emits_error_on_line_overflow_true() { + // See also https://github.com/rust-lang/rustfmt/issues/3164 + let args = [ + "--config", + "error_on_line_overflow=true", + "tests/cargo-fmt/source/issue_3164/src/main.rs", + ]; + + let (_stdout, stderr) = rustfmt(&args); + assert!(stderr.contains( + "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" + )) +} diff --git a/src/tools/rustfmt/tests/source/cfg_if/detect/arch/x86.rs b/src/tools/rustfmt/tests/source/cfg_if/detect/arch/x86.rs index d26f4ee894f..131cbb855f1 100644 --- a/src/tools/rustfmt/tests/source/cfg_if/detect/arch/x86.rs +++ b/src/tools/rustfmt/tests/source/cfg_if/detect/arch/x86.rs @@ -329,7 +329,7 @@ pub enum Feature { tbm, /// POPCNT (Population Count) popcnt, - /// FXSR (Floating-point context fast save and restor) + /// FXSR (Floating-point context fast save and restore) fxsr, /// XSAVE (Save Processor Extended States) xsave, diff --git a/src/tools/rustfmt/tests/source/comments_unicode.rs b/src/tools/rustfmt/tests/source/comments_unicode.rs new file mode 100644 index 00000000000..e65a245ba93 --- /dev/null +++ b/src/tools/rustfmt/tests/source/comments_unicode.rs @@ -0,0 +1,140 @@ +impl Default for WhitespaceCharacters { + fn default() -> Self { + Self { + space: '·', // U+00B7 + nbsp: '⍽', // U+237D + tab: '→', // U+2192 + newline: '⏎', // U+23CE + } + } +} + +const RAINBOWS: &[&str] = &[ + "rаinЬοѡ", // hue: 0 + "raіnЬοw", // hue: 2 + "rаіɴЬow", // hue: 2 + "raіɴЬoѡ", // hue: 8 + "ʀainЬow", // hue: 8 + "ʀaіɴboѡ", // hue: 8 + "ʀаіnbοw", // hue: 11 + "rainЬoѡ", // hue: 14 + "raіɴbow", // hue: 14 + "rаiɴЬow", // hue: 20 + "raіnЬow", // hue: 26 + "ʀaiɴbοw", // hue: 32 + "raіɴboѡ", // hue: 35 + "rаiɴbow", // hue: 35 + "rаіnbοw", // hue: 38 + "rаinЬow", // hue: 47 + "ʀaіnboѡ", // hue: 47 + "ʀaіnЬoѡ", // hue: 47 + "ʀаіɴbοw", // hue: 53 + "ʀaіnЬοѡ", // hue: 57 + "raiɴЬoѡ", // hue: 68 + "ʀainbοѡ", // hue: 68 + "ʀаinboѡ", // hue: 68 + "ʀаiɴbοw", // hue: 68 + "ʀаіnbow", // hue: 68 + "rаіnЬοѡ", // hue: 69 + "ʀainЬοw", // hue: 71 + "raiɴbow", // hue: 73 + "raіnЬoѡ", // hue: 74 + "rаіɴbοw", // hue: 77 + "raіnЬοѡ", // hue: 81 + "raiɴЬow", // hue: 83 + "ʀainbοw", // hue: 83 + "ʀаinbow", // hue: 83 + "ʀаiɴbοѡ", // hue: 83 + "ʀаіnboѡ", // hue: 83 + "ʀаіɴЬοѡ", // hue: 84 + "rainЬow", // hue: 85 + "ʀаiɴЬοw", // hue: 86 + "ʀаіnbοѡ", // hue: 89 + "ʀаіnЬοw", // hue: 92 + "rаiɴbοw", // hue: 95 + "ʀаіɴbοѡ", // hue: 98 + "ʀаiɴЬοѡ", // hue: 99 + "raіnbοw", // hue: 101 + "ʀаіɴЬοw", // hue: 101 + "ʀaiɴboѡ", // hue: 104 + "ʀаinbοѡ", // hue: 104 + "rаiɴbοѡ", // hue: 107 + "ʀаinЬοw", // hue: 107 + "rаiɴЬοw", // hue: 110 + "rаіnboѡ", // hue: 110 + "rаіnbοѡ", // hue: 113 + "ʀainЬοѡ", // hue: 114 + "rаіnЬοw", // hue: 116 + "ʀaіɴЬow", // hue: 116 + "rаinbοw", // hue: 122 + "ʀаіɴboѡ", // hue: 125 + "rаinbοѡ", // hue: 131 + "rainbow", // hue: 134 + "rаinЬοw", // hue: 134 + "ʀаiɴboѡ", // hue: 140 + "rainЬοѡ", // hue: 141 + "raіɴЬow", // hue: 143 + "ʀainЬoѡ", // hue: 143 + "ʀaіɴbow", // hue: 143 + "ʀainbow", // hue: 148 + "rаіɴboѡ", // hue: 149 + "ʀainboѡ", // hue: 155 + "ʀaіnbow", // hue: 155 + "ʀaіnЬow", // hue: 155 + "raiɴbοw", // hue: 158 + "ʀаiɴЬoѡ", // hue: 158 + "rainbοw", // hue: 160 + "rаinbow", // hue: 160 + "ʀaіɴbοѡ", // hue: 164 + "ʀаiɴbow", // hue: 164 + "ʀаіnЬoѡ", // hue: 164 + "ʀaiɴЬοѡ", // hue: 165 + "rаiɴboѡ", // hue: 167 + "ʀaіɴЬοw", // hue: 167 + "ʀaіɴЬοѡ", // hue: 171 + "raіnboѡ", // hue: 173 + "ʀаіɴЬoѡ", // hue: 173 + "rаіɴbοѡ", // hue: 176 + "ʀаinЬow", // hue: 176 + "rаiɴЬοѡ", // hue: 177 + "rаіɴЬοw", // hue: 179 + "ʀаinЬoѡ", // hue: 179 + "ʀаіɴbow", // hue: 179 + "rаiɴЬoѡ", // hue: 182 + "raіɴbοѡ", // hue: 188 + "rаіnЬoѡ", // hue: 188 + "raiɴЬοѡ", // hue: 189 + "raіɴЬοw", // hue: 191 + "ʀaіɴbοw", // hue: 191 + "ʀаіnЬow", // hue: 191 + "rainbοѡ", // hue: 194 + "rаinboѡ", // hue: 194 + "rаіnbow", // hue: 194 + "rainЬοw", // hue: 197 + "rаinЬoѡ", // hue: 206 + "rаіɴbow", // hue: 206 + "rаіɴЬοѡ", // hue: 210 + "ʀaiɴЬow", // hue: 212 + "raіɴbοw", // hue: 218 + "rаіnЬow", // hue: 218 + "ʀaiɴbοѡ", // hue: 221 + "ʀaiɴЬοw", // hue: 224 + "ʀaіnbοѡ", // hue: 227 + "raiɴboѡ", // hue: 230 + "ʀaіnbοw", // hue: 230 + "ʀaіnЬοw", // hue: 230 + "ʀаinЬοѡ", // hue: 231 + "rainboѡ", // hue: 232 + "raіnbow", // hue: 232 + "ʀаіɴЬow", // hue: 233 + "ʀaіɴЬoѡ", // hue: 239 + "ʀаіnЬοѡ", // hue: 246 + "raiɴbοѡ", // hue: 248 + "ʀаiɴЬow", // hue: 248 + "raіɴЬοѡ", // hue: 249 + "raiɴЬοw", // hue: 251 + "rаіɴЬoѡ", // hue: 251 + "ʀaiɴbow", // hue: 251 + "ʀаinbοw", // hue: 251 + "raіnbοѡ", // hue: 254 +]; diff --git a/src/tools/rustfmt/tests/source/configs/fn_args_layout/compressed.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/compressed.rs index 66a371c259f..eb573d3121f 100644 --- a/src/tools/rustfmt/tests/source/configs/fn_args_layout/compressed.rs +++ b/src/tools/rustfmt/tests/source/configs/fn_params_layout/compressed.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Function arguments density trait Lorem { diff --git a/src/tools/rustfmt/tests/source/configs/fn_args_layout/tall.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/tall.rs index f11e86fd313..4be34f0fe4a 100644 --- a/src/tools/rustfmt/tests/source/configs/fn_args_layout/tall.rs +++ b/src/tools/rustfmt/tests/source/configs/fn_params_layout/tall.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Tall +// rustfmt-fn_params_layout: Tall // Function arguments density trait Lorem { diff --git a/src/tools/rustfmt/tests/source/configs/fn_args_layout/vertical.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs index a23cc025225..674968023f9 100644 --- a/src/tools/rustfmt/tests/source/configs/fn_args_layout/vertical.rs +++ b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Function arguments density trait Lorem { diff --git a/src/tools/rustfmt/tests/source/enum.rs b/src/tools/rustfmt/tests/source/enum.rs index 0ed9651abe7..a7b9616929c 100644 --- a/src/tools/rustfmt/tests/source/enum.rs +++ b/src/tools/rustfmt/tests/source/enum.rs @@ -36,7 +36,7 @@ enum StructLikeVariants { Normal(u32, String, ), StructLike { x: i32, // Test comment // Pre-comment - #[Attr50] y: SomeType, // Aanother Comment + #[Attr50] y: SomeType, // Another Comment }, SL { a: A } } diff --git a/src/tools/rustfmt/tests/source/fn-custom-7.rs b/src/tools/rustfmt/tests/source/fn-custom-7.rs index d5330196bf7..3ecd8701727 100644 --- a/src/tools/rustfmt/tests/source/fn-custom-7.rs +++ b/src/tools/rustfmt/tests/source/fn-custom-7.rs @@ -1,5 +1,5 @@ // rustfmt-normalize_comments: true -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // rustfmt-brace_style: AlwaysNextLine // Case with only one variable. diff --git a/src/tools/rustfmt/tests/source/fn-custom.rs b/src/tools/rustfmt/tests/source/fn-custom.rs index 77ced4c5e0e..64ef0ecfaae 100644 --- a/src/tools/rustfmt/tests/source/fn-custom.rs +++ b/src/tools/rustfmt/tests/source/fn-custom.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Test some of the ways function signatures can be customised. // Test compressed layout of args. diff --git a/src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs b/src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs index 759bc83d015..fd6e3f0442e 100644 --- a/src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs +++ b/src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Empty list should stay on one line. fn do_bar( diff --git a/src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs b/src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs new file mode 100644 index 00000000000..9af114fbe57 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs @@ -0,0 +1,26 @@ +// rustfmt-format_macro_bodies: true + +// with comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + //comment 1 + 42 + //comment 2 + ), + }; + }}; +} + +// without comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + + 42 + ), + }; + }}; +} diff --git a/src/tools/rustfmt/tests/source/issue-4643.rs b/src/tools/rustfmt/tests/source/issue-4643.rs new file mode 100644 index 00000000000..382072d9004 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-4643.rs @@ -0,0 +1,23 @@ +// output doesn't get corrupted when using comments within generic type parameters of a trait + +pub trait Something< + A, + // some comment + B, + C +> { + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} + +pub trait SomethingElse< + A, + /* some comment */ + B, + C +> { + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} diff --git a/src/tools/rustfmt/tests/source/issue-4689/one.rs b/src/tools/rustfmt/tests/source/issue-4689/one.rs new file mode 100644 index 00000000000..d048eb10fb1 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-4689/one.rs @@ -0,0 +1,149 @@ +// rustfmt-version: One + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write1 + fmt::Write2 +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer1< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + Printer2< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +>, +> { +} +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +> + fmt::Write1 ++ fmt::Write2, +> { +} + +fn foo<F>(foo2: F) +where +F: Fn( +// this comment is deleted +) +{ +} +fn foo<F>(foo2: F) +where +F: Fn( +// this comment is deleted +) + fmt::Write +{ +} + +fn elaborate_bounds<F>(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +), +{ +} +fn elaborate_bounds<F>(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( +mut entries: entryyyyyyyy, +) -> ( +impl Fn( +AlphabeticalTraversal, +Seconddddddddddddddddddddddddddddddddddd +) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm ++ Sendddddddddddddddddddddddddddddddddddddddddddd +) { +} + +pub trait SomeTrait: +Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where +for<'b> &'b Self: Send ++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/src/tools/rustfmt/tests/source/issue-4689/two.rs b/src/tools/rustfmt/tests/source/issue-4689/two.rs new file mode 100644 index 00000000000..ea7feda825d --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-4689/two.rs @@ -0,0 +1,149 @@ +// rustfmt-version: Two + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write +{ +// +} +pub trait PrettyPrinter<'tcx>: +Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + fmt::Write1 + fmt::Write2 +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} +pub trait PrettyPrinter<'tcx>: +fmt::Write + Printer1< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> + Printer2< +'tcx, +Error = fmt::Error, +Path = Self, +Region = Self, +Type = Self, +DynExistential = Self, +Const = Self, +> +{ +// +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +>, +> { +} +fn f() -> Box< +FnMut() -> Thing< +WithType = LongItemName, +Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, +> + fmt::Write1 ++ fmt::Write2, +> { +} + +fn foo<F>(foo2: F) +where +F: Fn( +// this comment is deleted +) +{ +} +fn foo<F>(foo2: F) +where +F: Fn( +// this comment is deleted +) + fmt::Write +{ +} + +fn elaborate_bounds<F>(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +), +{ +} +fn elaborate_bounds<F>(mut mk_cand: F) +where +F: for<> FnMut( +&mut ProbeContext<>, +ty::PolyTraitRefffffffffffffffffffffffffffffffff<>, +tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, +) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( +mut entries: entryyyyyyyy, +) -> ( +impl Fn( +AlphabeticalTraversal, +Seconddddddddddddddddddddddddddddddddddd +) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm ++ Sendddddddddddddddddddddddddddddddddddddddddddd +) { +} + +pub trait SomeTrait: +Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where +for<'b> &'b Self: Send ++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/src/tools/rustfmt/tests/source/issue_1306.rs b/src/tools/rustfmt/tests/source/issue_1306.rs new file mode 100644 index 00000000000..03b78e34108 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_1306.rs @@ -0,0 +1,29 @@ +// rustfmt-max_width: 160 +// rustfmt-fn_call_width: 96 +// rustfmt-fn_args_layout: Compressed +// rustfmt-trailing_comma: Always +// rustfmt-wrap_comments: true + +fn foo() { + for elem in try!(gen_epub_book::ops::parse_descriptor_file(&mut try!(File::open(&opts.source_file.1).map_err(|_| { + gen_epub_book::Error::Io { + desc: "input file", + op: "open", + more: None, + } + })), + "input file")) { + println!("{}", elem); + } +} + +fn write_content() { + io::copy(try!(File::open(in_f).map_err(|_| { + Error::Io { + desc: "Content", + op: "open", + more: None, + } + })), + w); +} diff --git a/src/tools/rustfmt/tests/source/issue_3245.rs b/src/tools/rustfmt/tests/source/issue_3245.rs new file mode 100644 index 00000000000..0279246ed6a --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_3245.rs @@ -0,0 +1,4 @@ +fn main() { + let x = 1; + ;let y = 3; +} diff --git a/src/tools/rustfmt/tests/source/issue_3561.rs b/src/tools/rustfmt/tests/source/issue_3561.rs new file mode 100644 index 00000000000..8f6cd8f9fbc --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_3561.rs @@ -0,0 +1,6 @@ +fn main() {;7 +} + +fn main() { + ;7 +} diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs new file mode 100644 index 00000000000..d0437ee10fd --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs new file mode 100644 index 00000000000..1f6722344fe --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*","items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should also skip this invocation, as the wildcard covers it +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs new file mode 100644 index 00000000000..f3dd89dc4db --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: [] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs new file mode 100644 index 00000000000..7fa5d3a6f71 --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs new file mode 100644 index 00000000000..d5669532524 --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["unknown"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs new file mode 100644 index 00000000000..a920381a455 --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_invocations: ["foo","bar"] + +// Should skip this invocation +foo!( + const _: u8 = 0; +); + +// Should skip this invocation +bar!( + const _: u8 = 0; +); + +// Should not skip this invocation +baz!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs new file mode 100644 index 00000000000..61296869a50 --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should not skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs new file mode 100644 index 00000000000..9398918a9e1 --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs new file mode 100644 index 00000000000..4e3eb542dbe --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs new file mode 100644 index 00000000000..43cb8015de5 --- /dev/null +++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs @@ -0,0 +1,32 @@ +// rustfmt-skip_macro_invocations: ["aaa","ccc"] + +// These tests demonstrate a realistic use case with use aliases. +// The use statements should not impact functionality in any way. + +use crate::{aaa, bbb, ddd}; + +// No use alias, invocation in list +// Should skip this invocation +aaa!( + const _: u8 = 0; +); + +// Use alias, invocation in list +// Should skip this invocation +use crate::bbb as ccc; +ccc!( + const _: u8 = 0; +); + +// Use alias, invocation not in list +// Should not skip this invocation +use crate::ddd as eee; +eee!( + const _: u8 = 0; +); + +// No use alias, invocation not in list +// Should not skip this invocation +fff!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/source/tuple.rs b/src/tools/rustfmt/tests/source/tuple.rs index 9a0f979fbca..5189a7454f3 100644 --- a/src/tools/rustfmt/tests/source/tuple.rs +++ b/src/tools/rustfmt/tests/source/tuple.rs @@ -1,4 +1,4 @@ -// Test tuple litterals +// Test tuple literals fn foo() { let a = (a, a, a, a, a); diff --git a/src/tools/rustfmt/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs b/src/tools/rustfmt/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs index 78b3ce146f2..56064e4a4cc 100644 --- a/src/tools/rustfmt/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs +++ b/src/tools/rustfmt/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs @@ -11,6 +11,6 @@ /// fn foo() {} -/// A long commment for wrapping +/// A long comment for wrapping /// This is a long long long long long long long long long long long long long long long long long long long long sentence. fn bar() {} diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/arch/x86.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/arch/x86.rs index 02d5eed1c29..47210cae2aa 100644 --- a/src/tools/rustfmt/tests/target/cfg_if/detect/arch/x86.rs +++ b/src/tools/rustfmt/tests/target/cfg_if/detect/arch/x86.rs @@ -314,7 +314,7 @@ pub enum Feature { tbm, /// POPCNT (Population Count) popcnt, - /// FXSR (Floating-point context fast save and restor) + /// FXSR (Floating-point context fast save and restore) fxsr, /// XSAVE (Save Processor Extended States) xsave, diff --git a/src/tools/rustfmt/tests/target/comments_unicode.rs b/src/tools/rustfmt/tests/target/comments_unicode.rs new file mode 100644 index 00000000000..3e1b6b0a28f --- /dev/null +++ b/src/tools/rustfmt/tests/target/comments_unicode.rs @@ -0,0 +1,140 @@ +impl Default for WhitespaceCharacters { + fn default() -> Self { + Self { + space: '·', // U+00B7 + nbsp: '⍽', // U+237D + tab: '→', // U+2192 + newline: '⏎', // U+23CE + } + } +} + +const RAINBOWS: &[&str] = &[ + "rаinЬοѡ", // hue: 0 + "raіnЬοw", // hue: 2 + "rаіɴЬow", // hue: 2 + "raіɴЬoѡ", // hue: 8 + "ʀainЬow", // hue: 8 + "ʀaіɴboѡ", // hue: 8 + "ʀаіnbοw", // hue: 11 + "rainЬoѡ", // hue: 14 + "raіɴbow", // hue: 14 + "rаiɴЬow", // hue: 20 + "raіnЬow", // hue: 26 + "ʀaiɴbοw", // hue: 32 + "raіɴboѡ", // hue: 35 + "rаiɴbow", // hue: 35 + "rаіnbοw", // hue: 38 + "rаinЬow", // hue: 47 + "ʀaіnboѡ", // hue: 47 + "ʀaіnЬoѡ", // hue: 47 + "ʀаіɴbοw", // hue: 53 + "ʀaіnЬοѡ", // hue: 57 + "raiɴЬoѡ", // hue: 68 + "ʀainbοѡ", // hue: 68 + "ʀаinboѡ", // hue: 68 + "ʀаiɴbοw", // hue: 68 + "ʀаіnbow", // hue: 68 + "rаіnЬοѡ", // hue: 69 + "ʀainЬοw", // hue: 71 + "raiɴbow", // hue: 73 + "raіnЬoѡ", // hue: 74 + "rаіɴbοw", // hue: 77 + "raіnЬοѡ", // hue: 81 + "raiɴЬow", // hue: 83 + "ʀainbοw", // hue: 83 + "ʀаinbow", // hue: 83 + "ʀаiɴbοѡ", // hue: 83 + "ʀаіnboѡ", // hue: 83 + "ʀаіɴЬοѡ", // hue: 84 + "rainЬow", // hue: 85 + "ʀаiɴЬοw", // hue: 86 + "ʀаіnbοѡ", // hue: 89 + "ʀаіnЬοw", // hue: 92 + "rаiɴbοw", // hue: 95 + "ʀаіɴbοѡ", // hue: 98 + "ʀаiɴЬοѡ", // hue: 99 + "raіnbοw", // hue: 101 + "ʀаіɴЬοw", // hue: 101 + "ʀaiɴboѡ", // hue: 104 + "ʀаinbοѡ", // hue: 104 + "rаiɴbοѡ", // hue: 107 + "ʀаinЬοw", // hue: 107 + "rаiɴЬοw", // hue: 110 + "rаіnboѡ", // hue: 110 + "rаіnbοѡ", // hue: 113 + "ʀainЬοѡ", // hue: 114 + "rаіnЬοw", // hue: 116 + "ʀaіɴЬow", // hue: 116 + "rаinbοw", // hue: 122 + "ʀаіɴboѡ", // hue: 125 + "rаinbοѡ", // hue: 131 + "rainbow", // hue: 134 + "rаinЬοw", // hue: 134 + "ʀаiɴboѡ", // hue: 140 + "rainЬοѡ", // hue: 141 + "raіɴЬow", // hue: 143 + "ʀainЬoѡ", // hue: 143 + "ʀaіɴbow", // hue: 143 + "ʀainbow", // hue: 148 + "rаіɴboѡ", // hue: 149 + "ʀainboѡ", // hue: 155 + "ʀaіnbow", // hue: 155 + "ʀaіnЬow", // hue: 155 + "raiɴbοw", // hue: 158 + "ʀаiɴЬoѡ", // hue: 158 + "rainbοw", // hue: 160 + "rаinbow", // hue: 160 + "ʀaіɴbοѡ", // hue: 164 + "ʀаiɴbow", // hue: 164 + "ʀаіnЬoѡ", // hue: 164 + "ʀaiɴЬοѡ", // hue: 165 + "rаiɴboѡ", // hue: 167 + "ʀaіɴЬοw", // hue: 167 + "ʀaіɴЬοѡ", // hue: 171 + "raіnboѡ", // hue: 173 + "ʀаіɴЬoѡ", // hue: 173 + "rаіɴbοѡ", // hue: 176 + "ʀаinЬow", // hue: 176 + "rаiɴЬοѡ", // hue: 177 + "rаіɴЬοw", // hue: 179 + "ʀаinЬoѡ", // hue: 179 + "ʀаіɴbow", // hue: 179 + "rаiɴЬoѡ", // hue: 182 + "raіɴbοѡ", // hue: 188 + "rаіnЬoѡ", // hue: 188 + "raiɴЬοѡ", // hue: 189 + "raіɴЬοw", // hue: 191 + "ʀaіɴbοw", // hue: 191 + "ʀаіnЬow", // hue: 191 + "rainbοѡ", // hue: 194 + "rаinboѡ", // hue: 194 + "rаіnbow", // hue: 194 + "rainЬοw", // hue: 197 + "rаinЬoѡ", // hue: 206 + "rаіɴbow", // hue: 206 + "rаіɴЬοѡ", // hue: 210 + "ʀaiɴЬow", // hue: 212 + "raіɴbοw", // hue: 218 + "rаіnЬow", // hue: 218 + "ʀaiɴbοѡ", // hue: 221 + "ʀaiɴЬοw", // hue: 224 + "ʀaіnbοѡ", // hue: 227 + "raiɴboѡ", // hue: 230 + "ʀaіnbοw", // hue: 230 + "ʀaіnЬοw", // hue: 230 + "ʀаinЬοѡ", // hue: 231 + "rainboѡ", // hue: 232 + "raіnbow", // hue: 232 + "ʀаіɴЬow", // hue: 233 + "ʀaіɴЬoѡ", // hue: 239 + "ʀаіnЬοѡ", // hue: 246 + "raiɴbοѡ", // hue: 248 + "ʀаiɴЬow", // hue: 248 + "raіɴЬοѡ", // hue: 249 + "raiɴЬοw", // hue: 251 + "rаіɴЬoѡ", // hue: 251 + "ʀaiɴbow", // hue: 251 + "ʀаinbοw", // hue: 251 + "raіnbοѡ", // hue: 254 +]; diff --git a/src/tools/rustfmt/tests/target/configs/fn_args_layout/compressed.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/compressed.rs index f189446e25d..ff32f0f1d58 100644 --- a/src/tools/rustfmt/tests/target/configs/fn_args_layout/compressed.rs +++ b/src/tools/rustfmt/tests/target/configs/fn_params_layout/compressed.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Function arguments density trait Lorem { diff --git a/src/tools/rustfmt/tests/target/configs/fn_args_layout/tall.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/tall.rs index 20f308973ac..25a86799af0 100644 --- a/src/tools/rustfmt/tests/target/configs/fn_args_layout/tall.rs +++ b/src/tools/rustfmt/tests/target/configs/fn_params_layout/tall.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Tall +// rustfmt-fn_params_layout: Tall // Function arguments density trait Lorem { diff --git a/src/tools/rustfmt/tests/target/configs/fn_args_layout/vertical.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs index 6c695a75df9..7a0e42415f3 100644 --- a/src/tools/rustfmt/tests/target/configs/fn_args_layout/vertical.rs +++ b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Function arguments density trait Lorem { diff --git a/src/tools/rustfmt/tests/target/enum.rs b/src/tools/rustfmt/tests/target/enum.rs index 9a25126b44e..70fc8ab376c 100644 --- a/src/tools/rustfmt/tests/target/enum.rs +++ b/src/tools/rustfmt/tests/target/enum.rs @@ -43,7 +43,7 @@ enum StructLikeVariants { x: i32, // Test comment // Pre-comment #[Attr50] - y: SomeType, // Aanother Comment + y: SomeType, // Another Comment }, SL { a: A, diff --git a/src/tools/rustfmt/tests/target/fn-custom-7.rs b/src/tools/rustfmt/tests/target/fn-custom-7.rs index 2c20ac5a752..f6a1a90c3fc 100644 --- a/src/tools/rustfmt/tests/target/fn-custom-7.rs +++ b/src/tools/rustfmt/tests/target/fn-custom-7.rs @@ -1,5 +1,5 @@ // rustfmt-normalize_comments: true -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // rustfmt-brace_style: AlwaysNextLine // Case with only one variable. diff --git a/src/tools/rustfmt/tests/target/fn-custom.rs b/src/tools/rustfmt/tests/target/fn-custom.rs index 2eb2a973d24..506d9de3437 100644 --- a/src/tools/rustfmt/tests/target/fn-custom.rs +++ b/src/tools/rustfmt/tests/target/fn-custom.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // Test some of the ways function signatures can be customised. // Test compressed layout of args. diff --git a/src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs b/src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs index da0ac981d87..bfeca15c967 100644 --- a/src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs +++ b/src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs @@ -1,4 +1,4 @@ -// rustfmt-fn_args_layout: Vertical +// rustfmt-fn_params_layout: Vertical // Empty list should stay on one line. fn do_bar() -> u8 { diff --git a/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs b/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs new file mode 100644 index 00000000000..2038ed7f1d0 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs @@ -0,0 +1,6 @@ +// rustfmt-format_macro_matchers: false + +macro_rules! foo { + ($a:ident : $b:ty) => {}; + ($a:ident $b:ident $c:ident) => {}; +} diff --git a/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs b/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs new file mode 100644 index 00000000000..01d939add4d --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs @@ -0,0 +1,6 @@ +// rustfmt-format_macro_matchers: true + +macro_rules! foo { + ($a:ident : $b:ty) => {}; + ($a:ident $b:ident $c:ident) => {}; +} diff --git a/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs b/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs new file mode 100644 index 00000000000..1352b762e45 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs @@ -0,0 +1,26 @@ +// rustfmt-format_macro_bodies: false + +// with comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + //comment 1 + 42 + //comment 2 + ), + }; + }}; +} + +// without comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + + 42 + ), + }; + }}; +} diff --git a/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs b/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs new file mode 100644 index 00000000000..88d57159c85 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs @@ -0,0 +1,21 @@ +// rustfmt-format_macro_bodies: true + +// with comments +macro_rules! macros { + () => {{ + Struct { + field: ( + 42 + //comment 1 + 42 + //comment 2 + ), + }; + }}; +} + +// without comments +macro_rules! macros { + () => {{ + Struct { field: (42 + 42) }; + }}; +} diff --git a/src/tools/rustfmt/tests/target/issue-4643.rs b/src/tools/rustfmt/tests/target/issue-4643.rs new file mode 100644 index 00000000000..ef99e4db382 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-4643.rs @@ -0,0 +1,19 @@ +// output doesn't get corrupted when using comments within generic type parameters of a trait + +pub trait Something< + A, + // some comment + B, + C, +> +{ + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} + +pub trait SomethingElse<A, /* some comment */ B, C> { + fn a(&self, x: A) -> i32; + fn b(&self, x: B) -> i32; + fn c(&self, x: C) -> i32; +} diff --git a/src/tools/rustfmt/tests/target/issue-4689/one.rs b/src/tools/rustfmt/tests/target/issue-4689/one.rs new file mode 100644 index 00000000000..7735e34f3b5 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-4689/one.rs @@ -0,0 +1,150 @@ +// rustfmt-version: One + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, +> +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write1 + + fmt::Write2 +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer1< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + Printer2< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + >, +> { +} +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + > + fmt::Write1 + + fmt::Write2, +> { +} + +fn foo<F>(foo2: F) +where + F: Fn( + // this comment is deleted + ), +{ +} +fn foo<F>(foo2: F) +where + F: Fn( + // this comment is deleted + ) + fmt::Write, +{ +} + +fn elaborate_bounds<F>(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ), +{ +} +fn elaborate_bounds<F>(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( + mut entries: entryyyyyyyy, +) -> (impl Fn( + AlphabeticalTraversal, + Seconddddddddddddddddddddddddddddddddddd, +) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + + Sendddddddddddddddddddddddddddddddddddddddddddd) { +} + +pub trait SomeTrait: + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where + for<'b> &'b Self: Send + + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/src/tools/rustfmt/tests/target/issue-4689/two.rs b/src/tools/rustfmt/tests/target/issue-4689/two.rs new file mode 100644 index 00000000000..e3b5cd22810 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-4689/two.rs @@ -0,0 +1,152 @@ +// rustfmt-version: Two + +// Based on the issue description +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write +{ + // +} +pub trait PrettyPrinter<'tcx>: + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + fmt::Write1 + + fmt::Write2 +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} +pub trait PrettyPrinter<'tcx>: + fmt::Write + + Printer1< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > + Printer2< + 'tcx, + Error = fmt::Error, + Path = Self, + Region = Self, + Type = Self, + DynExistential = Self, + Const = Self, + > +{ + // +} + +// Some test cases to ensure other cases formatting were not changed +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + >, +> { +} +fn f() -> Box< + FnMut() -> Thing< + WithType = LongItemName, + Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger, + > + fmt::Write1 + + fmt::Write2, +> { +} + +fn foo<F>(foo2: F) +where + F: Fn( + // this comment is deleted + ), +{ +} +fn foo<F>(foo2: F) +where + F: Fn( + // this comment is deleted + ) + fmt::Write, +{ +} + +fn elaborate_bounds<F>(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ), +{ +} +fn elaborate_bounds<F>(mut mk_cand: F) +where + F: FnMut( + &mut ProbeContext, + ty::PolyTraitRefffffffffffffffffffffffffffffffff, + tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem, + ) + fmt::Write, +{ +} + +fn build_sorted_static_get_entry_names( + mut entries: entryyyyyyyy, +) -> ( + impl Fn( + AlphabeticalTraversal, + Seconddddddddddddddddddddddddddddddddddd, + ) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + + Sendddddddddddddddddddddddddddddddddddddddddddd +) { +} + +pub trait SomeTrait: + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +{ +} + +trait B = where + for<'b> &'b Self: Send + + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee + + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy; diff --git a/src/tools/rustfmt/tests/target/issue-4791/issue_4928.rs b/src/tools/rustfmt/tests/target/issue-4791/issue_4928.rs index 588656b535f..29f6bda9063 100644 --- a/src/tools/rustfmt/tests/target/issue-4791/issue_4928.rs +++ b/src/tools/rustfmt/tests/target/issue-4791/issue_4928.rs @@ -1,7 +1,7 @@ // rustfmt-brace_style: SameLineWhere // rustfmt-comment_width: 100 // rustfmt-edition: 2018 -// rustfmt-fn_args_layout: Compressed +// rustfmt-fn_params_layout: Compressed // rustfmt-hard_tabs: false // rustfmt-match_block_trailing_comma: true // rustfmt-max_width: 100 diff --git a/src/tools/rustfmt/tests/target/issue-5358.rs b/src/tools/rustfmt/tests/target/issue-5358.rs new file mode 100644 index 00000000000..d4bf4909ad7 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-5358.rs @@ -0,0 +1,4 @@ +// Test /* comment */ inside trait generics does not get duplicated. +trait Test</* comment */ T> {} + +trait TestTwo</* comment */ T, /* comment */ V> {} diff --git a/src/tools/rustfmt/tests/target/issue_1306.rs b/src/tools/rustfmt/tests/target/issue_1306.rs new file mode 100644 index 00000000000..6bb514cdfe5 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_1306.rs @@ -0,0 +1,33 @@ +// rustfmt-max_width: 160 +// rustfmt-fn_call_width: 96 +// rustfmt-fn_args_layout: Compressed +// rustfmt-trailing_comma: Always +// rustfmt-wrap_comments: true + +fn foo() { + for elem in try!(gen_epub_book::ops::parse_descriptor_file( + &mut try!(File::open(&opts.source_file.1).map_err(|_| { + gen_epub_book::Error::Io { + desc: "input file", + op: "open", + more: None, + } + })), + "input file" + )) { + println!("{}", elem); + } +} + +fn write_content() { + io::copy( + try!(File::open(in_f).map_err(|_| { + Error::Io { + desc: "Content", + op: "open", + more: None, + } + })), + w, + ); +} diff --git a/src/tools/rustfmt/tests/target/issue_3033.rs b/src/tools/rustfmt/tests/target/issue_3033.rs new file mode 100644 index 00000000000..e12249a6da6 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_3033.rs @@ -0,0 +1,2 @@ +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding:: + BluetoothRemoteGATTServerMethods; diff --git a/src/tools/rustfmt/tests/target/issue_3245.rs b/src/tools/rustfmt/tests/target/issue_3245.rs new file mode 100644 index 00000000000..8f442f1181a --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_3245.rs @@ -0,0 +1,4 @@ +fn main() { + let x = 1; + let y = 3; +} diff --git a/src/tools/rustfmt/tests/target/issue_3561.rs b/src/tools/rustfmt/tests/target/issue_3561.rs new file mode 100644 index 00000000000..846a14d86a5 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_3561.rs @@ -0,0 +1,7 @@ +fn main() { + 7 +} + +fn main() { + 7 +} diff --git a/src/tools/rustfmt/tests/target/issue_4350.rs b/src/tools/rustfmt/tests/target/issue_4350.rs new file mode 100644 index 00000000000..a94c5c32188 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_4350.rs @@ -0,0 +1,13 @@ +//rustfmt-format_macro_bodies: true + +macro_rules! mto_text_left { + ($buf:ident, $n:ident, $pos:ident, $state:ident) => {{ + let cursor = loop { + state = match iter.next() { + None if $pos == DP::Start => break last_char_idx($buf), + None /*some comment */ => break 0, + }; + }; + Ok(saturate_cursor($buf, cursor)) + }}; +} diff --git a/src/tools/rustfmt/tests/target/issue_5668.rs b/src/tools/rustfmt/tests/target/issue_5668.rs new file mode 100644 index 00000000000..bbd9a530b81 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5668.rs @@ -0,0 +1,8 @@ +type Foo = impl Send; +struct Struct< + const C: usize = { + let _: Foo = (); + //~^ ERROR: mismatched types + 0 + }, +>; diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs new file mode 100644 index 00000000000..d0437ee10fd --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs new file mode 100644 index 00000000000..1f6722344fe --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["*","items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should also skip this invocation, as the wildcard covers it +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs new file mode 100644 index 00000000000..4a398cc59c6 --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: [] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs new file mode 100644 index 00000000000..c4d577269c6 --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs @@ -0,0 +1,11 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should skip this invocation +items!( + const _: u8 = 0; +); + +// Should not skip this invocation +renamed_items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs new file mode 100644 index 00000000000..7ab1440395c --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["unknown"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs new file mode 100644 index 00000000000..c6b41ff93d7 --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs @@ -0,0 +1,16 @@ +// rustfmt-skip_macro_invocations: ["foo","bar"] + +// Should skip this invocation +foo!( + const _: u8 = 0; +); + +// Should skip this invocation +bar!( + const _: u8 = 0; +); + +// Should not skip this invocation +baz!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs new file mode 100644 index 00000000000..6e372c72695 --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["items"] + +// Should not skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs new file mode 100644 index 00000000000..9398918a9e1 --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should skip this invocation +self::items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs new file mode 100644 index 00000000000..aa57a2a655c --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs @@ -0,0 +1,6 @@ +// rustfmt-skip_macro_invocations: ["self::items"] + +// Should not skip this invocation +items!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs new file mode 100644 index 00000000000..799dd8c08af --- /dev/null +++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs @@ -0,0 +1,32 @@ +// rustfmt-skip_macro_invocations: ["aaa","ccc"] + +// These tests demonstrate a realistic use case with use aliases. +// The use statements should not impact functionality in any way. + +use crate::{aaa, bbb, ddd}; + +// No use alias, invocation in list +// Should skip this invocation +aaa!( + const _: u8 = 0; +); + +// Use alias, invocation in list +// Should skip this invocation +use crate::bbb as ccc; +ccc!( + const _: u8 = 0; +); + +// Use alias, invocation not in list +// Should not skip this invocation +use crate::ddd as eee; +eee!( + const _: u8 = 0; +); + +// No use alias, invocation not in list +// Should not skip this invocation +fff!( + const _: u8 = 0; +); diff --git a/src/tools/rustfmt/tests/target/tuple.rs b/src/tools/rustfmt/tests/target/tuple.rs index 68bb2f3bc28..24fcf8cfd7c 100644 --- a/src/tools/rustfmt/tests/target/tuple.rs +++ b/src/tools/rustfmt/tests/target/tuple.rs @@ -1,4 +1,4 @@ -// Test tuple litterals +// Test tuple literals fn foo() { let a = (a, a, a, a, a); diff --git a/src/tools/rustfmt/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs b/src/tools/rustfmt/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs index d61d4d7c216..6ccecc7e0bb 100644 --- a/src/tools/rustfmt/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs +++ b/src/tools/rustfmt/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs @@ -10,7 +10,7 @@ /// ``` fn foo() {} -/// A long commment for wrapping +/// A long comment for wrapping /// This is a long long long long long long long long long long long long long /// long long long long long long long sentence. fn bar() {} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index bc2edf634de..8ce19c8b514 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -59,7 +59,6 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"), ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"), ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"), - ("cranelift-egraph", "Apache-2.0 WITH LLVM-exception"), ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"), ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"), ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"), @@ -286,7 +285,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "cranelift-codegen", "cranelift-codegen-meta", "cranelift-codegen-shared", - "cranelift-egraph", "cranelift-entity", "cranelift-frontend", "cranelift-isle", @@ -321,10 +319,12 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", "windows-sys", + "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", + "windows_x86_64_gnullvm", "windows_x86_64_msvc", ]; diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 5b84b51a035..6bb4d32f87d 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -31,7 +31,7 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E06 // Error codes that don't yet have a UI test. This list will eventually be removed. const IGNORE_UI_TEST_CHECK: &[&str] = - &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729", "E0789"]; + &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729"]; macro_rules! verbose_print { ($verbose:expr, $($fmt:tt)*) => { diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index e9740e30da4..bc11e108124 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -109,3 +109,28 @@ pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () { // as long as it doesn't cause a verifier error by using `bitcast`. transmute(x) } + +pub enum Either<T, U> { A(T), B(U) } + +// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`, +// with the `ptr` field representing both `&i32` and `fn()` depending on the variant. +// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`. + +// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%0, {{.+\*|ptr}}{{.+}}%x) +#[no_mangle] +#[inline(never)] +pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> { + x +} + +// The incorrectness described above would result in us producing (after optimizations) +// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`. + +// CHECK-LABEL: @call_with_fn_ptr +#[no_mangle] +pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> { + // CHECK-NOT: ptrtoint + // CHECK-NOT: inttoptr + // CHECK: call addrspace(1) void @should_not_combine_addrspace + should_not_combine_addrspace(Either::B(f)) +} diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs index bdd312878ec..d82b737de0b 100644 --- a/tests/codegen/debug-vtable.rs +++ b/tests/codegen/debug-vtable.rs @@ -9,6 +9,14 @@ // compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 // ignore-tidy-linelength +// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled. +// This helps debuggers more reliably map from dyn pointer to concrete type. +// CHECK: @vtable.0 = private constant <{ +// CHECK: @vtable.1 = private constant <{ +// CHECK: @vtable.2 = private constant <{ +// CHECK: @vtable.3 = private constant <{ +// CHECK: @vtable.4 = private constant <{ + // NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize" // MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" // NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()" diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-nonzero-eq.rs index 598dcc19b49..835decd3e5f 100644 --- a/tests/codegen/option-nonzero-eq.rs +++ b/tests/codegen/option-nonzero-eq.rs @@ -3,6 +3,7 @@ #![crate_type = "lib"] extern crate core; +use core::cmp::Ordering; use core::num::{NonZeroU32, NonZeroI64}; use core::ptr::NonNull; @@ -32,3 +33,12 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool { // CHECK-NEXT: ret i1 l == r } + +// CHECK-lABEL: @ordering_eq +#[no_mangle] +pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool { + // CHECK: start: + // CHECK-NEXT: icmp eq i8 + // CHECK-NEXT: ret i1 + l == r +} diff --git a/tests/debuginfo/embedded-visualizer.rs b/tests/debuginfo/embedded-visualizer.rs index 0269015b466..2898e75e0ee 100644 --- a/tests/debuginfo/embedded-visualizer.rs +++ b/tests/debuginfo/embedded-visualizer.rs @@ -1,6 +1,7 @@ // compile-flags:-g // min-gdb-version: 8.1 // ignore-lldb +// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows // === CDB TESTS ================================================================================== diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index c41c9ee21df..c122112e6c7 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -1,6 +1,7 @@ // compile-flags:-g // min-gdb-version: 8.1 +// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows // Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping<T>` and // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`. diff --git a/tests/debuginfo/vec-slices.rs b/tests/debuginfo/vec-slices.rs index 7d88e45caf2..de4099a7f50 100644 --- a/tests/debuginfo/vec-slices.rs +++ b/tests/debuginfo/vec-slices.rs @@ -1,4 +1,3 @@ -// ignore-windows // min-lldb-version: 310 // compile-flags:-g diff --git a/tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff deleted file mode 100644 index 9780332d8bf..00000000000 --- a/tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff +++ /dev/null @@ -1,29 +0,0 @@ -- // MIR for `encode` before SimplifyBranchSame -+ // MIR for `encode` after SimplifyBranchSame - - fn encode(_1: Type) -> Type { - debug v => _1; // in scope 0 at $DIR/76803_regression.rs:+0:15: +0:16 - let mut _0: Type; // return place in scope 0 at $DIR/76803_regression.rs:+0:27: +0:31 - let mut _2: isize; // in scope 0 at $DIR/76803_regression.rs:+2:9: +2:16 - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:+1:11: +1:12 - switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:+1:5: +1:12 - } - - bb1: { - _0 = move _1; // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15 - goto -> bb3; // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15 - } - - bb2: { - Deinit(_0); // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27 - discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27 - goto -> bb3; // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27 - } - - bb3: { - return; // scope 0 at $DIR/76803_regression.rs:+5:2: +5:2 - } - } - diff --git a/tests/mir-opt/76803_regression.rs b/tests/mir-opt/76803_regression.rs deleted file mode 100644 index 05dc3c97841..00000000000 --- a/tests/mir-opt/76803_regression.rs +++ /dev/null @@ -1,19 +0,0 @@ -// compile-flags: -Z mir-opt-level=1 -// EMIT_MIR 76803_regression.encode.SimplifyBranchSame.diff - -#[derive(Debug, Eq, PartialEq)] -pub enum Type { - A, - B, -} - -pub fn encode(v: Type) -> Type { - match v { - Type::A => Type::B, - _ => v, - } -} - -fn main() { - assert_eq!(Type::B, encode(Type::A)); -} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir index 05edc4797d4..1449247aeda 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -1,8 +1,22 @@ // MIR for `b::{closure#0}` 0 generator_resume /* generator_layout = GeneratorLayout { field_tys: { - _0: impl std::future::Future<Output = ()>, - _1: impl std::future::Future<Output = ()>, + _0: GeneratorSavedTy { + ty: impl std::future::Future<Output = ()>, + source_info: SourceInfo { + span: $DIR/async_await.rs:15:8: 15:14 (#9), + scope: scope[0], + }, + ignore_for_traits: false, + }, + _1: GeneratorSavedTy { + ty: impl std::future::Future<Output = ()>, + source_info: SourceInfo { + span: $DIR/async_await.rs:16:8: 16:14 (#12), + scope: scope[0], + }, + ignore_for_traits: false, + }, }, variant_fields: { Unresumed(0): [], diff --git a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir new file mode 100644 index 00000000000..4c921272885 --- /dev/null +++ b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir @@ -0,0 +1,14 @@ +// MIR for `arrays` after built + +fn arrays() -> usize { + let mut _0: usize; // return place in scope 0 at $DIR/arrays.rs:+0:32: +0:37 + let mut _1: [i32; C]; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = [const 5_i32; C]; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _2 = Len(_1); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _0 = _2; // scope 0 at $DIR/arrays.rs:+4:9: +4:16 + return; // scope 0 at $DIR/arrays.rs:+5:9: +5:17 + } +} diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs new file mode 100644 index 00000000000..8e0a1fd7a43 --- /dev/null +++ b/tests/mir-opt/building/custom/arrays.rs @@ -0,0 +1,19 @@ +#![feature(custom_mir, core_intrinsics, inline_const)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR arrays.arrays.built.after.mir +#[custom_mir(dialect = "built")] +fn arrays<const C: usize>() -> usize { + mir!({ + let x = [5_i32; C]; + let c = Len(x); + RET = c; + Return() + }) +} + +fn main() { + assert_eq!(arrays::<20>(), 20); +} diff --git a/tests/mir-opt/building/custom/enums.rs b/tests/mir-opt/building/custom/enums.rs index e5cd4563778..eca5b792ec0 100644 --- a/tests/mir-opt/building/custom/enums.rs +++ b/tests/mir-opt/building/custom/enums.rs @@ -86,6 +86,7 @@ fn switch_option_repr(option: Bool) -> bool { #[custom_mir(dialect = "runtime", phase = "initial")] fn set_discr(option: &mut Option<()>) { mir!({ + Deinit(*option); SetDiscriminant(*option, 0); Return() }) diff --git a/tests/mir-opt/building/custom/enums.set_discr.built.after.mir b/tests/mir-opt/building/custom/enums.set_discr.built.after.mir index 7de9ed0983f..6d07473658a 100644 --- a/tests/mir-opt/building/custom/enums.set_discr.built.after.mir +++ b/tests/mir-opt/building/custom/enums.set_discr.built.after.mir @@ -4,7 +4,8 @@ fn set_discr(_1: &mut Option<()>) -> () { let mut _0: (); // return place in scope 0 at $DIR/enums.rs:+0:39: +0:39 bb0: { - discriminant((*_1)) = 0; // scope 0 at $DIR/enums.rs:+2:9: +2:36 - return; // scope 0 at $DIR/enums.rs:+3:9: +3:17 + Deinit((*_1)); // scope 0 at $DIR/enums.rs:+2:9: +2:24 + discriminant((*_1)) = 0; // scope 0 at $DIR/enums.rs:+3:9: +3:36 + return; // scope 0 at $DIR/enums.rs:+4:9: +4:17 } } diff --git a/tests/mir-opt/building/custom/operators.f.built.after.mir b/tests/mir-opt/building/custom/operators.f.built.after.mir new file mode 100644 index 00000000000..cb43d5e6ed7 --- /dev/null +++ b/tests/mir-opt/building/custom/operators.f.built.after.mir @@ -0,0 +1,30 @@ +// MIR for `f` after built + +fn f(_1: i32, _2: bool) -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/operators.rs:+0:30: +0:33 + let mut _3: (i32, bool); // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = Neg(_1); // scope 0 at $DIR/operators.rs:+2:9: +2:15 + _2 = Not(_2); // scope 0 at $DIR/operators.rs:+3:9: +3:15 + _1 = Add(_1, _1); // scope 0 at $DIR/operators.rs:+4:9: +4:18 + _1 = Sub(_1, _1); // scope 0 at $DIR/operators.rs:+5:9: +5:18 + _1 = Mul(_1, _1); // scope 0 at $DIR/operators.rs:+6:9: +6:18 + _1 = Div(_1, _1); // scope 0 at $DIR/operators.rs:+7:9: +7:18 + _1 = Rem(_1, _1); // scope 0 at $DIR/operators.rs:+8:9: +8:18 + _1 = BitXor(_1, _1); // scope 0 at $DIR/operators.rs:+9:9: +9:18 + _1 = BitAnd(_1, _1); // scope 0 at $DIR/operators.rs:+10:9: +10:18 + _1 = Shl(_1, _1); // scope 0 at $DIR/operators.rs:+11:9: +11:19 + _1 = Shr(_1, _1); // scope 0 at $DIR/operators.rs:+12:9: +12:19 + _2 = Eq(_1, _1); // scope 0 at $DIR/operators.rs:+13:9: +13:19 + _2 = Lt(_1, _1); // scope 0 at $DIR/operators.rs:+14:9: +14:18 + _2 = Le(_1, _1); // scope 0 at $DIR/operators.rs:+15:9: +15:19 + _2 = Ge(_1, _1); // scope 0 at $DIR/operators.rs:+16:9: +16:19 + _2 = Gt(_1, _1); // scope 0 at $DIR/operators.rs:+17:9: +17:18 + _3 = CheckedAdd(_1, _1); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _2 = (_3.1: bool); // scope 0 at $DIR/operators.rs:+19:9: +19:18 + _1 = (_3.0: i32); // scope 0 at $DIR/operators.rs:+20:9: +20:18 + _0 = _1; // scope 0 at $DIR/operators.rs:+21:9: +21:16 + return; // scope 0 at $DIR/operators.rs:+22:9: +22:17 + } +} diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs new file mode 100644 index 00000000000..db7a48317d9 --- /dev/null +++ b/tests/mir-opt/building/custom/operators.rs @@ -0,0 +1,31 @@ +// compile-flags: --crate-type=lib +#![feature(custom_mir, core_intrinsics, inline_const)] +use std::intrinsics::mir::*; + +// EMIT_MIR operators.f.built.after.mir +#[custom_mir(dialect = "built")] +pub fn f(a: i32, b: bool) -> i32 { + mir!({ + a = -a; + b = !b; + a = a + a; + a = a - a; + a = a * a; + a = a / a; + a = a % a; + a = a ^ a; + a = a & a; + a = a << a; + a = a >> a; + b = a == a; + b = a < a; + b = a <= a; + b = a >= a; + b = a > a; + let res = Checked(a + a); + b = res.1; + a = res.0; + RET = a; + Return() + }) +} diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index dd548adde7e..5e587be1f16 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -64,17 +64,8 @@ _3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16 StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12 StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20 - StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16 - _6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16 - StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - _7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 _5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20 - StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 - _8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 _4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:24 - StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10 _9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:+6:13: +6:28 @@ -117,9 +108,6 @@ StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:+14:1: +14:2 return; // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2 } } diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff index 8485703e39f..e085a88b2da 100644 --- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff @@ -21,32 +21,25 @@ StorageLive(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10 _1 = const 0_i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14 StorageLive(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11 - StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -- _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 +- _4 = Eq(_1, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 + _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 } bb1: { -- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + _5 = Eq(_1, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 +- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 ++ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 } bb2: { -- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 + _2 = Rem(const 1_i32, _1); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2 - StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2 return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 27e41d4869d..38d402b8f21 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -23,24 +23,21 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + _2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35 - StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36 StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 27e41d4869d..38d402b8f21 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -23,24 +23,21 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + _2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35 - StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36 StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 } bb1: { diff --git a/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff b/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff index 0de80091753..549b4711e87 100644 --- a/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff +++ b/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff @@ -12,18 +12,12 @@ bb0: { StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 - _4 = _2; // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 -- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 +- _3 = BitOr(_2, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 + _3 = const true; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:+1:14: +1:15 StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 - _6 = _1; // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 -- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 -+ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 +- _5 = BitAnd(_1, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29 ++ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 + _0 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29 StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff b/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff index 629c8e60148..1cfe47d0a86 100644 --- a/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff +++ b/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff @@ -7,11 +7,8 @@ let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 bb0: { - StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 - _2 = _1; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 -- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 +- _0 = Mul(_1, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 + _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 - StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:7: +1:8 return; // scope 0 at $DIR/mult_by_zero.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff index 8a73f0390e1..924a267f3d8 100644 --- a/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -13,14 +13,13 @@ StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 _4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 // mir::Constant - // + span: $DIR/ref_deref.rs:6:6: 6:10 + // + span: $DIR/ref_deref.rs:5:6: 5:10 // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _2 = _4; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 -+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 + _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - nop; // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff deleted file mode 100644 index 015ec4d078c..00000000000 --- a/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `main` before PromoteTemps -+ // MIR for `main` after PromoteTemps - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - let _3: i32; // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -+ let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - - bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -- StorageLive(_3); // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -- _3 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -- _2 = &_3; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -+ _4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -+ // mir::Constant -+ // + span: $DIR/ref_deref.rs:6:6: 6:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } -+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 -- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2 - } - } - diff --git a/tests/mir-opt/const_prop/ref_deref.rs b/tests/mir-opt/const_prop/ref_deref.rs index d2549c8b6aa..76e56916af0 100644 --- a/tests/mir-opt/const_prop/ref_deref.rs +++ b/tests/mir-opt/const_prop/ref_deref.rs @@ -1,5 +1,4 @@ -// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop -// EMIT_MIR ref_deref.main.PromoteTemps.diff +// unit-test: ConstProp // EMIT_MIR ref_deref.main.ConstProp.diff fn main() { diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index ec3d9043315..59095b44837 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -13,13 +13,13 @@ StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _4 = const _; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 // mir::Constant - // + span: $DIR/ref_deref_project.rs:6:6: 6:17 + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - nop; // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff deleted file mode 100644 index cd0616e65ba..00000000000 --- a/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `main` before PromoteTemps -+ // MIR for `main` after PromoteTemps - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -+ let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - - bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -- StorageLive(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -- _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -- _2 = &(_3.1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -+ _4 = const _; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -+ // mir::Constant -+ // + span: $DIR/ref_deref_project.rs:6:6: 6:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } -+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 -- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2 - } - } - diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs index 2fdd4e15319..04fc7f8daa1 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.rs +++ b/tests/mir-opt/const_prop/ref_deref_project.rs @@ -1,5 +1,4 @@ -// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop -// EMIT_MIR ref_deref_project.main.PromoteTemps.diff +// unit-test: ConstProp // EMIT_MIR ref_deref_project.main.ConstProp.diff fn main() { diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff index d518eff04eb..e3f5b120a32 100644 --- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff @@ -14,10 +14,7 @@ StorageLive(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10 _1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14 StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 - StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -- _2 = consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 -+ _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 +- _2 = consume(_1) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 + _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 @@ -25,9 +22,7 @@ } bb1: { - StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15 StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16 - StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2 return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 9017fd18e48..b99b83b0cba 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -20,7 +20,7 @@ StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 // mir::Constant - // + span: $DIR/slice_len.rs:6:6: 6:19 + // + span: $DIR/slice_len.rs:7:6: 7:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 @@ -33,7 +33,7 @@ - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 } bb1: { @@ -43,7 +43,7 @@ StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 9017fd18e48..b99b83b0cba 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -20,7 +20,7 @@ StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 // mir::Constant - // + span: $DIR/slice_len.rs:6:6: 6:19 + // + span: $DIR/slice_len.rs:7:6: 7:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 @@ -33,7 +33,7 @@ - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 } bb1: { @@ -43,7 +43,7 @@ StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs index eaaf34b960e..8183def0c63 100644 --- a/tests/mir-opt/const_prop/slice_len.rs +++ b/tests/mir-opt/const_prop/slice_len.rs @@ -1,4 +1,5 @@ -// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop +// unit-test: ConstProp +// compile-flags: -Zmir-enable-passes=+InstCombine // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR slice_len.main.ConstProp.diff diff --git a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff index ea9fec0aa15..b6b542fb794 100644 --- a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff +++ b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff @@ -4,15 +4,16 @@ fn bar() -> () { let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10 let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let mut _2: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 + let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 + let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 + let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 scope 1 { debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 scope 2 { } scope 3 { - debug y => _3; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 } } @@ -20,16 +21,20 @@ StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 (_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 - StorageLive(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - _2 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - (*_2) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26 - StorageDead(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27 - StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 - StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 - _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18 - _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25 - StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25 - StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 + StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 + StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 + _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 + (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26 + StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27 + _2 = const (); // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 + StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6 + StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 + _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18 + _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25 + StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25 + _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2 + StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 return; // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2 } diff --git a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff index 043f4047417..e43735fd9e1 100644 --- a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff +++ b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff @@ -27,6 +27,7 @@ _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18 _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25 StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25 + _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2 StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2 return; // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2 diff --git a/tests/mir-opt/const_prop_miscompile.rs b/tests/mir-opt/const_prop_miscompile.rs index bc54556b349..dbbe5ee0840 100644 --- a/tests/mir-opt/const_prop_miscompile.rs +++ b/tests/mir-opt/const_prop_miscompile.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp #![feature(raw_ref_op)] // EMIT_MIR const_prop_miscompile.foo.ConstProp.diff diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff new file mode 100644 index 00000000000..b183865a9bc --- /dev/null +++ b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff @@ -0,0 +1,34 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f() -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/borrowed_local.rs:+0:11: +0:15 + let mut _1: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: &u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _4: &u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = const 5_u8; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _2 = &_1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _3 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _4 = &_3; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _0 = cmp_ref(_2, _4) -> bb1; // scope 0 at $DIR/borrowed_local.rs:+8:13: +8:45 + // mir::Constant + // + span: $DIR/borrowed_local.rs:23:29: 23:36 + // + literal: Const { ty: for<'a, 'b> fn(&'a u8, &'b u8) -> bool {cmp_ref}, val: Value(<ZST>) } + } + + bb1: { +- _0 = opaque::<u8>(_3) -> bb2; // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38 ++ _0 = opaque::<u8>(_1) -> bb2; // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38 + // mir::Constant + // + span: $DIR/borrowed_local.rs:27:28: 27:34 + // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) } + } + + bb2: { + return; // scope 0 at $DIR/borrowed_local.rs:+15:13: +15:21 + } + } + diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs new file mode 100644 index 00000000000..c4b980e2b35 --- /dev/null +++ b/tests/mir-opt/copy-prop/borrowed_local.rs @@ -0,0 +1,39 @@ +// unit-test: CopyProp + +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +fn opaque(_: impl Sized) -> bool { true } + +fn cmp_ref(a: &u8, b: &u8) -> bool { + std::ptr::eq(a as *const u8, b as *const u8) +} + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f() -> bool { + mir!( + { + let a = 5_u8; + let r1 = &a; + let b = a; + // We cannot propagate the place `a`. + let r2 = &b; + Call(RET, next, cmp_ref(r1, r2)) + } + next = { + // But we can propagate the value `a`. + Call(RET, ret, opaque(b)) + } + ret = { + Return() + } + ) +} + +fn main() { + assert!(!f()); +} + +// EMIT_MIR borrowed_local.f.CopyProp.diff diff --git a/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff new file mode 100644 index 00000000000..8b116532d9f --- /dev/null +++ b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff @@ -0,0 +1,65 @@ +- // MIR for `foo` before CopyProp ++ // MIR for `foo` after CopyProp + + fn foo() -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/branch.rs:+0:13: +0:16 + let _1: i32; // in scope 0 at $DIR/branch.rs:+1:9: +1:10 + let mut _3: bool; // in scope 0 at $DIR/branch.rs:+3:16: +3:22 + let _4: i32; // in scope 0 at $DIR/branch.rs:+6:9: +6:14 + scope 1 { + debug x => _1; // in scope 1 at $DIR/branch.rs:+1:9: +1:10 + let _2: i32; // in scope 1 at $DIR/branch.rs:+3:9: +3:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/branch.rs:+3:9: +3:10 + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/branch.rs:+1:9: +1:10 + _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:+1:13: +1:18 + // mir::Constant + // + span: $DIR/branch.rs:13:13: 13:16 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) } + } + + bb1: { + StorageLive(_2); // scope 1 at $DIR/branch.rs:+3:9: +3:10 + StorageLive(_3); // scope 1 at $DIR/branch.rs:+3:16: +3:22 + _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:+3:16: +3:22 + // mir::Constant + // + span: $DIR/branch.rs:15:16: 15:20 + // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) } + } + + bb2: { + switchInt(move _3) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22 + } + + bb3: { + _2 = _1; // scope 1 at $DIR/branch.rs:+4:9: +4:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6 + } + + bb4: { + StorageLive(_4); // scope 1 at $DIR/branch.rs:+6:9: +6:14 + _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:+6:9: +6:14 + // mir::Constant + // + span: $DIR/branch.rs:18:9: 18:12 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) } + } + + bb5: { + StorageDead(_4); // scope 1 at $DIR/branch.rs:+6:14: +6:15 + _2 = _1; // scope 1 at $DIR/branch.rs:+7:9: +7:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6 + } + + bb6: { + StorageDead(_3); // scope 1 at $DIR/branch.rs:+8:5: +8:6 + _0 = _2; // scope 2 at $DIR/branch.rs:+10:5: +10:6 + StorageDead(_2); // scope 1 at $DIR/branch.rs:+11:1: +11:2 + StorageDead(_1); // scope 0 at $DIR/branch.rs:+11:1: +11:2 + return; // scope 0 at $DIR/branch.rs:+11:2: +11:2 + } + } + diff --git a/tests/mir-opt/copy-prop/branch.rs b/tests/mir-opt/copy-prop/branch.rs new file mode 100644 index 00000000000..50b1e00fad4 --- /dev/null +++ b/tests/mir-opt/copy-prop/branch.rs @@ -0,0 +1,27 @@ +//! Tests that we bail out when there are multiple assignments to the same local. +// unit-test: CopyProp +fn val() -> i32 { + 1 +} + +fn cond() -> bool { + true +} + +// EMIT_MIR branch.foo.CopyProp.diff +fn foo() -> i32 { + let x = val(); + + let y = if cond() { + x + } else { + val(); + x + }; + + y +} + +fn main() { + foo(); +} diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff new file mode 100644 index 00000000000..69acebf7642 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff @@ -0,0 +1,21 @@ +- // MIR for `arg_src` before CopyProp ++ // MIR for `arg_src` after CopyProp + + fn arg_src(_1: i32) -> i32 { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:12: +0:17 + let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30 + let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + scope 1 { + debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 + _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12 + _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff new file mode 100644 index 00000000000..ac4e9a2bfa7 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff @@ -0,0 +1,28 @@ +- // MIR for `bar` before CopyProp ++ // MIR for `bar` after CopyProp + + fn bar(_1: u8) -> () { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19 + let _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + // mir::Constant + // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10 + // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:12: +1:13 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 + _1 = const 5_u8; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10 + _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff new file mode 100644 index 00000000000..7ab6ebb7d53 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff @@ -0,0 +1,18 @@ +- // MIR for `baz` before CopyProp ++ // MIR for `baz` after CopyProp + + fn baz(_1: i32) -> i32 { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 + let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:23: +0:26 + let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff new file mode 100644 index 00000000000..0a3e985e7c2 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff @@ -0,0 +1,28 @@ +- // MIR for `foo` before CopyProp ++ // MIR for `foo` after CopyProp + + fn foo(_1: u8) -> () { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19 + let mut _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + // mir::Constant + // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 + // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17 + _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:17 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17 + _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.rs b/tests/mir-opt/copy-prop/copy_propagation_arg.rs new file mode 100644 index 00000000000..cc98985f1fd --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.rs @@ -0,0 +1,40 @@ +// Check that CopyProp does not propagate an assignment to a function argument +// (doing so can break usages of the original argument value) +// unit-test: CopyProp +fn dummy(x: u8) -> u8 { + x +} + +// EMIT_MIR copy_propagation_arg.foo.CopyProp.diff +fn foo(mut x: u8) { + // calling `dummy` to make a use of `x` that copyprop cannot eliminate + x = dummy(x); // this will assign a local to `x` +} + +// EMIT_MIR copy_propagation_arg.bar.CopyProp.diff +fn bar(mut x: u8) { + dummy(x); + x = 5; +} + +// EMIT_MIR copy_propagation_arg.baz.CopyProp.diff +fn baz(mut x: i32) -> i32 { + // self-assignment to a function argument should be eliminated + x = x; + x +} + +// EMIT_MIR copy_propagation_arg.arg_src.CopyProp.diff +fn arg_src(mut x: i32) -> i32 { + let y = x; + x = 123; // Don't propagate this assignment to `y` + y +} + +fn main() { + // Make sure the function actually gets instantiated. + foo(0); + bar(0); + baz(0); + arg_src(0); +} diff --git a/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff new file mode 100644 index 00000000000..bc5083e1ad0 --- /dev/null +++ b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff @@ -0,0 +1,60 @@ +- // MIR for `main` before CopyProp ++ // MIR for `main` after CopyProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11 + let mut _1: i32; // in scope 0 at $DIR/cycle.rs:+1:9: +1:14 + let mut _4: i32; // in scope 0 at $DIR/cycle.rs:+4:9: +4:10 + let _5: (); // in scope 0 at $DIR/cycle.rs:+6:5: +6:12 + let mut _6: i32; // in scope 0 at $DIR/cycle.rs:+6:10: +6:11 + scope 1 { + debug x => _1; // in scope 1 at $DIR/cycle.rs:+1:9: +1:14 + let _2: i32; // in scope 1 at $DIR/cycle.rs:+2:9: +2:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/cycle.rs:+2:9: +2:10 + let _3: i32; // in scope 2 at $DIR/cycle.rs:+3:9: +3:10 + scope 3 { +- debug z => _3; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10 ++ debug z => _2; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:14 + _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:+1:17: +1:22 + // mir::Constant + // + span: $DIR/cycle.rs:9:17: 9:20 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) } + } + + bb1: { + StorageLive(_2); // scope 1 at $DIR/cycle.rs:+2:9: +2:10 + _2 = _1; // scope 1 at $DIR/cycle.rs:+2:13: +2:14 +- StorageLive(_3); // scope 2 at $DIR/cycle.rs:+3:9: +3:10 +- _3 = _2; // scope 2 at $DIR/cycle.rs:+3:13: +3:14 +- StorageLive(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10 +- _4 = _3; // scope 3 at $DIR/cycle.rs:+4:9: +4:10 +- _1 = move _4; // scope 3 at $DIR/cycle.rs:+4:5: +4:10 +- StorageDead(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10 ++ _1 = _2; // scope 3 at $DIR/cycle.rs:+4:5: +4:10 + StorageLive(_5); // scope 3 at $DIR/cycle.rs:+6:5: +6:12 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:+6:10: +6:11 + _6 = _1; // scope 3 at $DIR/cycle.rs:+6:10: +6:11 + _5 = std::mem::drop::<i32>(move _6) -> bb2; // scope 3 at $DIR/cycle.rs:+6:5: +6:12 + // mir::Constant + // + span: $DIR/cycle.rs:14:5: 14:9 + // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) } + } + + bb2: { + StorageDead(_6); // scope 3 at $DIR/cycle.rs:+6:11: +6:12 + StorageDead(_5); // scope 3 at $DIR/cycle.rs:+6:12: +6:13 + _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +7:2 +- StorageDead(_3); // scope 2 at $DIR/cycle.rs:+7:1: +7:2 +- StorageDead(_2); // scope 1 at $DIR/cycle.rs:+7:1: +7:2 + StorageDead(_1); // scope 0 at $DIR/cycle.rs:+7:1: +7:2 + return; // scope 0 at $DIR/cycle.rs:+7:2: +7:2 + } + } + diff --git a/tests/mir-opt/copy-prop/cycle.rs b/tests/mir-opt/copy-prop/cycle.rs new file mode 100644 index 00000000000..b74c397269d --- /dev/null +++ b/tests/mir-opt/copy-prop/cycle.rs @@ -0,0 +1,15 @@ +//! Tests that cyclic assignments don't hang CopyProp, and result in reasonable code. +// unit-test: CopyProp +fn val() -> i32 { + 1 +} + +// EMIT_MIR cycle.main.CopyProp.diff +fn main() { + let mut x = val(); + let y = x; + let z = y; + x = z; + + drop(x); +} diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir new file mode 100644 index 00000000000..918817da56c --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir @@ -0,0 +1,30 @@ +// MIR for `f` after CopyProp + +fn f(_1: usize) -> usize { + debug a => _1; // in scope 0 at $DIR/dead_stores_79191.rs:+0:6: +0:11 + let mut _0: usize; // return place in scope 0 at $DIR/dead_stores_79191.rs:+0:23: +0:28 + let _2: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10 + let mut _3: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+3:9: +3:10 + let mut _4: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+4:8: +4:9 + scope 1 { + debug b => _2; // in scope 1 at $DIR/dead_stores_79191.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/dead_stores_79191.rs:+1:13: +1:14 + _1 = const 5_usize; // scope 1 at $DIR/dead_stores_79191.rs:+2:5: +2:10 + _1 = _2; // scope 1 at $DIR/dead_stores_79191.rs:+3:5: +3:10 + StorageLive(_4); // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9 + _4 = _1; // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9 + _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_79191.rs:+4:5: +4:10 + // mir::Constant + // + span: $DIR/dead_stores_79191.rs:12:5: 12:7 + // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_4); // scope 1 at $DIR/dead_stores_79191.rs:+4:9: +4:10 + return; // scope 0 at $DIR/dead_stores_79191.rs:+5:2: +5:2 + } +} diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.rs b/tests/mir-opt/copy-prop/dead_stores_79191.rs new file mode 100644 index 00000000000..e3493b8b7a1 --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_79191.rs @@ -0,0 +1,17 @@ +// unit-test: CopyProp + +fn id<T>(x: T) -> T { + x +} + +// EMIT_MIR dead_stores_79191.f.CopyProp.after.mir +fn f(mut a: usize) -> usize { + let b = a; + a = 5; + a = b; + id(a) +} + +fn main() { + f(0); +} diff --git a/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir new file mode 100644 index 00000000000..cf21fadd437 --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir @@ -0,0 +1,30 @@ +// MIR for `f` after CopyProp + +fn f(_1: usize) -> usize { + debug a => _1; // in scope 0 at $DIR/dead_stores_better.rs:+0:10: +0:15 + let mut _0: usize; // return place in scope 0 at $DIR/dead_stores_better.rs:+0:27: +0:32 + let _2: usize; // in scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10 + let mut _3: usize; // in scope 0 at $DIR/dead_stores_better.rs:+3:9: +3:10 + let mut _4: usize; // in scope 0 at $DIR/dead_stores_better.rs:+4:8: +4:9 + scope 1 { + debug b => _2; // in scope 1 at $DIR/dead_stores_better.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14 + _1 = const 5_usize; // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10 + _1 = _2; // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10 + StorageLive(_4); // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9 + _4 = _1; // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9 + _0 = id::<usize>(move _4) -> bb1; // scope 1 at $DIR/dead_stores_better.rs:+4:5: +4:10 + // mir::Constant + // + span: $DIR/dead_stores_better.rs:16:5: 16:7 + // + literal: Const { ty: fn(usize) -> usize {id::<usize>}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_4); // scope 1 at $DIR/dead_stores_better.rs:+4:9: +4:10 + return; // scope 0 at $DIR/dead_stores_better.rs:+5:2: +5:2 + } +} diff --git a/tests/mir-opt/copy-prop/dead_stores_better.rs b/tests/mir-opt/copy-prop/dead_stores_better.rs new file mode 100644 index 00000000000..8465b3c9853 --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_better.rs @@ -0,0 +1,21 @@ +// This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates +// that that pass enables this one to do more optimizations. + +// unit-test: CopyProp +// compile-flags: -Zmir-enable-passes=+DeadStoreElimination + +fn id<T>(x: T) -> T { + x +} + +// EMIT_MIR dead_stores_better.f.CopyProp.after.mir +pub fn f(mut a: usize) -> usize { + let b = a; + a = 5; + a = b; + id(a) +} + +fn main() { + f(0); +} diff --git a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff new file mode 100644 index 00000000000..d76bf1cfe7e --- /dev/null +++ b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff @@ -0,0 +1,40 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: T) -> () { + debug a => _1; // in scope 0 at $DIR/move_arg.rs:+0:19: +0:20 + let mut _0: (); // return place in scope 0 at $DIR/move_arg.rs:+0:25: +0:25 + let _2: T; // in scope 0 at $DIR/move_arg.rs:+1:9: +1:10 + let _3: (); // in scope 0 at $DIR/move_arg.rs:+2:5: +2:12 + let mut _4: T; // in scope 0 at $DIR/move_arg.rs:+2:7: +2:8 + let mut _5: T; // in scope 0 at $DIR/move_arg.rs:+2:10: +2:11 + scope 1 { +- debug b => _2; // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10 ++ debug b => _1; // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10 + } + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/move_arg.rs:+1:9: +1:10 +- _2 = _1; // scope 0 at $DIR/move_arg.rs:+1:13: +1:14 + StorageLive(_3); // scope 1 at $DIR/move_arg.rs:+2:5: +2:12 +- StorageLive(_4); // scope 1 at $DIR/move_arg.rs:+2:7: +2:8 +- _4 = _1; // scope 1 at $DIR/move_arg.rs:+2:7: +2:8 +- StorageLive(_5); // scope 1 at $DIR/move_arg.rs:+2:10: +2:11 +- _5 = _2; // scope 1 at $DIR/move_arg.rs:+2:10: +2:11 +- _3 = g::<T>(move _4, move _5) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12 ++ _3 = g::<T>(_1, _1) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12 + // mir::Constant + // + span: $DIR/move_arg.rs:7:5: 7:6 + // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) } + } + + bb1: { +- StorageDead(_5); // scope 1 at $DIR/move_arg.rs:+2:11: +2:12 +- StorageDead(_4); // scope 1 at $DIR/move_arg.rs:+2:11: +2:12 + StorageDead(_3); // scope 1 at $DIR/move_arg.rs:+2:12: +2:13 + _0 = const (); // scope 0 at $DIR/move_arg.rs:+0:25: +3:2 +- StorageDead(_2); // scope 0 at $DIR/move_arg.rs:+3:1: +3:2 + return; // scope 0 at $DIR/move_arg.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/copy-prop/move_arg.rs b/tests/mir-opt/copy-prop/move_arg.rs new file mode 100644 index 00000000000..40ae1d8f466 --- /dev/null +++ b/tests/mir-opt/copy-prop/move_arg.rs @@ -0,0 +1,15 @@ +// Test that we do not move multiple times from the same local. +// unit-test: CopyProp + +// EMIT_MIR move_arg.f.CopyProp.diff +pub fn f<T: Copy>(a: T) { + let b = a; + g(a, b); +} + +#[inline(never)] +pub fn g<T: Copy>(_: T, _: T) {} + +fn main() { + f(5) +} diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff b/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff new file mode 100644 index 00000000000..61fdd6f8c05 --- /dev/null +++ b/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff @@ -0,0 +1,19 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: bool) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/mutate_through_pointer.rs:+0:18: +0:22 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: *const bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _4: *mut bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _3 = &raw const _2; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _4 = &raw mut (*_3); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + (*_4) = const false; // scope 0 at $DIR/mutate_through_pointer.rs:+5:9: +5:20 + _0 = _1; // scope 0 at $DIR/mutate_through_pointer.rs:+6:9: +6:16 + return; // scope 0 at $DIR/mutate_through_pointer.rs:+7:9: +7:17 + } + } + diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.rs b/tests/mir-opt/copy-prop/mutate_through_pointer.rs new file mode 100644 index 00000000000..609e49d6bc9 --- /dev/null +++ b/tests/mir-opt/copy-prop/mutate_through_pointer.rs @@ -0,0 +1,22 @@ +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f(c: bool) -> bool { + mir!({ + let a = c; + let p = core::ptr::addr_of!(a); + let p2 = core::ptr::addr_of_mut!(*p); + *p2 = false; + RET = c; + Return() + }) +} + +fn main() { + assert_eq!(true, f(true)); +} + +// EMIT_MIR mutate_through_pointer.f.CopyProp.diff diff --git a/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff b/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff new file mode 100644 index 00000000000..9760fd3740f --- /dev/null +++ b/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff @@ -0,0 +1,29 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: bool) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/non_dominate.rs:+0:18: +0:22 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + goto -> bb1; // scope 0 at $DIR/non_dominate.rs:+4:11: +4:20 + } + + bb1: { + _3 = _1; // scope 0 at $DIR/non_dominate.rs:+5:17: +5:22 + switchInt(_3) -> [0: bb3, otherwise: bb2]; // scope 0 at $DIR/non_dominate.rs:+5:24: +5:58 + } + + bb2: { + _2 = _3; // scope 0 at $DIR/non_dominate.rs:+8:17: +8:22 + _1 = const false; // scope 0 at $DIR/non_dominate.rs:+8:24: +8:33 + goto -> bb1; // scope 0 at $DIR/non_dominate.rs:+8:35: +8:44 + } + + bb3: { + _0 = _2; // scope 0 at $DIR/non_dominate.rs:+9:17: +9:24 + return; // scope 0 at $DIR/non_dominate.rs:+9:26: +9:34 + } + } + diff --git a/tests/mir-opt/copy-prop/non_dominate.rs b/tests/mir-opt/copy-prop/non_dominate.rs new file mode 100644 index 00000000000..c0ea838e1c8 --- /dev/null +++ b/tests/mir-opt/copy-prop/non_dominate.rs @@ -0,0 +1,26 @@ +// unit-test: CopyProp + +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f(c: bool) -> bool { + mir!( + let a: bool; + let b: bool; + { Goto(bb1) } + bb1 = { b = c; match b { false => bb3, _ => bb2 }} + // This assignment to `a` does not dominate the use in `bb3`. + // It should not be replaced by `b`. + bb2 = { a = b; c = false; Goto(bb1) } + bb3 = { RET = a; Return() } + ) +} + +fn main() { + assert_eq!(true, f(true)); +} + +// EMIT_MIR non_dominate.f.CopyProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff index 02aafd7acc4..6870d7d6c45 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff @@ -20,19 +20,11 @@ _1 = const u8::MAX; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 StorageLive(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 _2 = const 1_u8; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 - StorageLive(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - _3 = const u8::MAX; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - _4 = const 1_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL } bb1: { - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 - StorageDead(_1); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 return; // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2 } } diff --git a/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir b/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir index d7f66a6bf4d..1a7fb916e56 100644 --- a/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir +++ b/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir @@ -11,7 +11,7 @@ fn const_dividend(_1: i32) -> i32 { } bb1: { - _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 + _0 = Div(const 256_i32, _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir b/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir index 7b7ab197825..5526a194be5 100644 --- a/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir +++ b/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir @@ -5,7 +5,7 @@ fn const_divisor(_1: i32) -> i32 { let mut _0: i32; // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36 bb0: { - _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 + _0 = Div(_1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index c1c2cde71ab..df9f8dcf1a4 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -83,55 +83,39 @@ _10 = ((_7 as Some).0: usize); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 _11 = &mut (*_1); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 - StorageLive(_12); // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51 - _12 = _2; // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51 StorageLive(_13); // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57 _13 = _6; // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57 StorageLive(_14); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79 StorageLive(_15); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 - StorageLive(_16); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68 - _16 = _10; // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68 - _15 = move _16 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 - StorageDead(_16); // scope 3 at $DIR/funky_arms.rs:+15:74: +15:75 + _15 = _10 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79 StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79 - StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _17 = _3; // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 + _0 = float_to_exponential_common_exact::<T>(move _11, _2, move _13, move _14, _3) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 // mir::Constant // + span: $DIR/funky_arms.rs:26:9: 26:42 // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) } } bb7: { - StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6 goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 } bb8: { StorageLive(_18); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 _18 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 - StorageLive(_19); // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 - _19 = _2; // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 StorageLive(_20); // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 _20 = _6; // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 - StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _21 = _3; // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 + _0 = float_to_exponential_common_shortest::<T>(move _18, _2, move _20, _3) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 // mir::Constant // + span: $DIR/funky_arms.rs:28:9: 28:45 // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) } } bb9: { - StorageDead(_21); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_20); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - StorageDead(_19); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_18); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 } diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index a8e090020c3..afe51864214 100644 --- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir +++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -1,7 +1,14 @@ // MIR for `main::{closure#0}` 0 generator_drop /* generator_layout = GeneratorLayout { field_tys: { - _0: std::string::String, + _0: GeneratorSavedTy { + ty: std::string::String, + source_info: SourceInfo { + span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0), + scope: scope[0], + }, + ignore_for_traits: false, + }, }, variant_fields: { Unresumed(0): [], diff --git a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index b3d3c768a5d..2f096c3e0a1 100644 --- a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir +++ b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -1,7 +1,14 @@ // MIR for `main::{closure#0}` 0 generator_resume /* generator_layout = GeneratorLayout { field_tys: { - _0: HasDrop, + _0: GeneratorSavedTy { + ty: HasDrop, + source_info: SourceInfo { + span: $DIR/generator_tiny.rs:20:13: 20:15 (#0), + scope: scope[0], + }, + ignore_for_traits: false, + }, }, variant_fields: { Unresumed(0): [], diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff index 8ea1a0757f2..64c3e47ff46 100644 --- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff +++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff @@ -35,8 +35,8 @@ _4 = &(*_2); // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24 - _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn_trait.rs:+2:5: +2:25 + StorageLive(_5); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15 -+ _5 = move _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15 -+ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22 ++ _5 = _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15 ++ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(_5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn_trait.rs:34:5: 34:22 - // + literal: Const { ty: for<'a> fn(&'a <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) } diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff index a71d73b7453..3fa9c3e88f6 100644 --- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff +++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff @@ -17,7 +17,7 @@ _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15 StorageDead(_3); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15 - _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:16 -+ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22 ++ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(_2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn_trait.rs:27:5: 27:13 - // + literal: Const { ty: for<'a> fn(&'a (dyn Cache<V = <C as Cache>::V> + 'a)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) } diff --git a/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 3502c25864b..20f737cc29f 100644 --- a/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -26,7 +26,7 @@ fn bar() -> bool { _3 = const 1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 StorageLive(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 _4 = const -1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 - _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11 + _0 = Eq(_3, _4); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11 StorageDead(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 StorageDead(_3); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 StorageDead(_2); // scope 1 at $DIR/inline_any_operand.rs:+2:12: +2:13 diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.diff b/tests/mir-opt/inline/inline_generator.main.Inline.diff index f27b64c3054..57574acf923 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.diff @@ -92,7 +92,7 @@ + + bb3: { + StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 -+ switchInt(move _7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 ++ switchInt(_7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 + } + + bb4: { @@ -118,7 +118,7 @@ + StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + StorageDead(_8); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39 + Deinit(_1); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 -+ ((_1 as Complete).0: bool) = move _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 ++ ((_1 as Complete).0: bool) = _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + discriminant(_1) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + _12 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + discriminant((*_12)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 diff --git a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 73aea719eed..b7c5bbecb68 100644 --- a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -15,7 +15,7 @@ fn test2(_1: &dyn X) -> bool { _3 = &(*_1); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11 _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11 StorageDead(_3); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11 - _0 = <dyn X as X>::y(move _2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10 + _0 = <dyn X as X>::y(_2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline_trait_method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) } diff --git a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff new file mode 100644 index 00000000000..8ff64c1ea15 --- /dev/null +++ b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff @@ -0,0 +1,42 @@ +- // MIR for `generic` before InstCombine ++ // MIR for `generic` after InstCombine + + fn generic() -> () { + let mut _0: (); // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +0:21 + let _1: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46 + let _2: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47 + let _3: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46 + _1 = assert_inhabited::<T>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46 + // mir::Constant + // + span: $DIR/intrinsic_asserts.rs:25:5: 25:44 + // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<T>}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47 + StorageLive(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47 + _2 = assert_zero_valid::<T>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47 + // mir::Constant + // + span: $DIR/intrinsic_asserts.rs:26:5: 26:45 + // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<T>}, val: Value(<ZST>) } + } + + bb2: { + StorageDead(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48 + StorageLive(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 + _3 = assert_mem_uninitialized_valid::<T>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60 + // mir::Constant + // + span: $DIR/intrinsic_asserts.rs:27:5: 27:58 + // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<T>}, val: Value(<ZST>) } + } + + bb3: { + StorageDead(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +4:2 + return; // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff new file mode 100644 index 00000000000..ddc01590315 --- /dev/null +++ b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff @@ -0,0 +1,47 @@ +- // MIR for `panics` before InstCombine ++ // MIR for `panics` after InstCombine + + fn panics() -> () { + let mut _0: (); // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +0:17 + let _1: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 + let _2: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 + let _3: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 +- _1 = assert_inhabited::<Never>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 ++ _1 = assert_inhabited::<Never>(); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50 + // mir::Constant + // + span: $DIR/intrinsic_asserts.rs:17:5: 17:48 + // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<Never>}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51 + StorageLive(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 +- _2 = assert_zero_valid::<&u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 ++ _2 = assert_zero_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49 + // mir::Constant + // + span: $DIR/intrinsic_asserts.rs:18:5: 18:47 + // + user_ty: UserType(0) + // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<&u8>}, val: Value(<ZST>) } + } + + bb2: { + StorageDead(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50 + StorageLive(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 +- _3 = assert_mem_uninitialized_valid::<&u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 ++ _3 = assert_mem_uninitialized_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62 + // mir::Constant + // + span: $DIR/intrinsic_asserts.rs:19:5: 19:60 + // + user_ty: UserType(1) + // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<&u8>}, val: Value(<ZST>) } + } + + bb3: { + StorageDead(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +4:2 + return; // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff new file mode 100644 index 00000000000..568fbf1a0d6 --- /dev/null +++ b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff @@ -0,0 +1,45 @@ +- // MIR for `removable` before InstCombine ++ // MIR for `removable` after InstCombine + + fn removable() -> () { + let mut _0: (); // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +0:20 + let _1: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 + let _2: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 + let _3: (); // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 +- _1 = assert_inhabited::<()>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 +- // mir::Constant +- // + span: $DIR/intrinsic_asserts.rs:7:5: 7:45 +- // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<()>}, val: Value(<ZST>) } ++ goto -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47 + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48 + StorageLive(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 +- _2 = assert_zero_valid::<u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 +- // mir::Constant +- // + span: $DIR/intrinsic_asserts.rs:8:5: 8:46 +- // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<u8>}, val: Value(<ZST>) } ++ goto -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48 + } + + bb2: { + StorageDead(_2); // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49 + StorageLive(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 +- _3 = assert_mem_uninitialized_valid::<u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 +- // mir::Constant +- // + span: $DIR/intrinsic_asserts.rs:9:5: 9:59 +- // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<u8>}, val: Value(<ZST>) } ++ goto -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61 + } + + bb3: { + StorageDead(_3); // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62 + nop; // scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +4:2 + return; // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/intrinsic_asserts.rs b/tests/mir-opt/intrinsic_asserts.rs new file mode 100644 index 00000000000..8fb99cdf6e0 --- /dev/null +++ b/tests/mir-opt/intrinsic_asserts.rs @@ -0,0 +1,28 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// All these assertions pass, so all the intrinsic calls should be deleted. +// EMIT_MIR intrinsic_asserts.removable.InstCombine.diff +pub fn removable() { + core::intrinsics::assert_inhabited::<()>(); + core::intrinsics::assert_zero_valid::<u8>(); + core::intrinsics::assert_mem_uninitialized_valid::<u8>(); +} + +enum Never {} + +// These assertions all diverge, so their target blocks should become None. +// EMIT_MIR intrinsic_asserts.panics.InstCombine.diff +pub fn panics() { + core::intrinsics::assert_inhabited::<Never>(); + core::intrinsics::assert_zero_valid::<&u8>(); + core::intrinsics::assert_mem_uninitialized_valid::<&u8>(); +} + +// Whether or not these asserts pass isn't known, so they shouldn't be modified. +// EMIT_MIR intrinsic_asserts.generic.InstCombine.diff +pub fn generic<T>() { + core::intrinsics::assert_inhabited::<T>(); + core::intrinsics::assert_zero_valid::<T>(); + core::intrinsics::assert_mem_uninitialized_valid::<T>(); +} diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff index b2706e5a436..30bf2c0684e 100644 --- a/tests/mir-opt/issue_101973.inner.ConstProp.diff +++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff @@ -15,7 +15,7 @@ let mut _10: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 let mut _11: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:14:5: 14:17 - debug x => _5; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14 + debug x => _1; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14 let mut _12: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27 let mut _13: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20 let mut _14: (u32, bool); // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20 @@ -34,17 +34,14 @@ StorageLive(_2); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65 StorageLive(_3); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58 StorageLive(_4); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17 - StorageLive(_5); // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16 - _5 = _1; // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16 StorageLive(_12); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27 StorageLive(_13); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 - _14 = CheckedShr(_5, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 + _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 assert(!move (_14.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 } bb1: { _8 = move (_10.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 - StorageDead(_9); // scope 0 at $DIR/issue_101973.rs:+1:44: +1:45 _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageDead(_8); // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52 _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 @@ -54,11 +51,7 @@ bb2: { _6 = move (_11.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageDead(_7); // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57 - StorageLive(_15); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - _15 = _4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - StorageLive(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - _16 = _6; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - _3 = rotate_right::<u32>(move _15, move _16) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + _3 = rotate_right::<u32>(_4, _6) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL // + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::<u32>}, val: Value(<ZST>) } @@ -70,21 +63,14 @@ StorageDead(_13); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27 _4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27 StorageDead(_12); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27 - StorageDead(_5); // scope 0 at $DIR/issue_101973.rs:+1:16: +1:17 StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 - StorageLive(_9); // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39 - _9 = _1; // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39 - _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 + _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 } bb4: { - StorageDead(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - StorageDead(_15); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - StorageDead(_6); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58 - StorageDead(_4); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58 _2 = move _3 as i32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65 StorageDead(_3); // scope 0 at $DIR/issue_101973.rs:+1:64: +1:65 _0 = move _2 as i64 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:72 diff --git a/tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff b/tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff deleted file mode 100644 index bf3bcfdb594..00000000000 --- a/tests/mir-opt/issue_73223.main.SimplifyArmIdentity.diff +++ /dev/null @@ -1,156 +0,0 @@ -- // MIR for `main` before SimplifyArmIdentity -+ // MIR for `main` after SimplifyArmIdentity - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue_73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue_73223.rs:+1:9: +1:14 - let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - let mut _3: isize; // in scope 0 at $DIR/issue_73223.rs:+2:9: +2:16 - let _4: i32; // in scope 0 at $DIR/issue_73223.rs:+2:14: +2:15 - let mut _6: i32; // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27 - let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _8: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _13: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _14: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _16: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _19: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _21: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _22: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 1 { - debug split => _1; // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14 - let _5: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14 - scope 3 { - debug _prev => _5; // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14 - let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _10: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _23: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 4 { - debug left_val => _9; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _10; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _15: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 5 { - debug kind => _15; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - } - } - } - scope 2 { - debug v => _4; // in scope 2 at $DIR/issue_73223.rs:+2:14: +2:15 - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/issue_73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - _3 = const 1_isize; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - goto -> bb3; // scope 0 at $DIR/issue_73223.rs:+1:17: +1:30 - } - - bb1: { - StorageDead(_2); // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7 - StorageDead(_1); // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2 - } - - bb2: { - unreachable; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30 - } - - bb3: { - StorageLive(_4); // scope 0 at $DIR/issue_73223.rs:+2:14: +2:15 - _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue_73223.rs:+2:14: +2:15 - _1 = _4; // scope 2 at $DIR/issue_73223.rs:+2:20: +2:21 - StorageDead(_4); // scope 0 at $DIR/issue_73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7 - StorageLive(_5); // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14 - StorageLive(_6); // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27 - _6 = _1; // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27 - Deinit(_5); // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28 - ((_5 as Some).0: i32) = move _6; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28 - discriminant(_5) = 1; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28 - StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28 - StorageLive(_24); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_25); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _7 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = const _; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _8 = _23; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_24); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_25); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _24 = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _25 = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = _24; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = _25; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _13 = (*_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _12 = Eq(move _13, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_14); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _11 = Not(move _12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(move _11) -> [0: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb4: { - StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - discriminant(_15) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_17); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _17 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } - StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _19 = _9; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _18 = _19; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_20); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = _10; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = _21; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - discriminant(_22) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _18, move _20, move _22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a i32, &'b i32, Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) } - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } - } - - bb5: { - StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_24); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_25); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2 - } - } - diff --git a/tests/mir-opt/issue_73223.rs b/tests/mir-opt/issue_73223.rs deleted file mode 100644 index be114cab719..00000000000 --- a/tests/mir-opt/issue_73223.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - let split = match Some(1) { - Some(v) => v, - None => return, - }; - - let _prev = Some(split); - assert_eq!(split, 1); -} - - -// EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff diff --git a/tests/mir-opt/issue_76432.rs b/tests/mir-opt/issue_76432.rs index c8b405ca8ea..fbbfd4ceb11 100644 --- a/tests/mir-opt/issue_76432.rs +++ b/tests/mir-opt/issue_76432.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmir-enable-passes=-NormalizeArrayLen // Check that we do not insert StorageDead at each target if StorageDead was never seen // EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index c24543daeac..c14780052fb 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -29,24 +29,11 @@ bb0: { StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - _6 = _1; // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - _7 = _1; // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - _8 = _1; // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 + _5 = [_1, _1, _1]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 _4 = &_5; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _3 = _4; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30 + _2 = _4 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 _9 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 - _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff index 9bc7060e958..59de067f4a4 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff @@ -13,7 +13,6 @@ let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 bb0: { StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 @@ -23,13 +22,10 @@ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 } diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff index cf427cfd1e6..17574b1b635 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff @@ -16,7 +16,6 @@ let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 bb0: { StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 @@ -26,13 +25,10 @@ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 } diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff index 3ed68f5f725..66feff62f42 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff @@ -6,19 +6,15 @@ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 bb0: { StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 } diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff index f0e0cdcfdc0..c0a277edc46 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff @@ -6,19 +6,15 @@ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 bb0: { StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff new file mode 100644 index 00000000000..8b35fd57fa0 --- /dev/null +++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff @@ -0,0 +1,50 @@ +- // MIR for `array_len_raw` before NormalizeArrayLen ++ // MIR for `array_len_raw` after NormalizeArrayLen + + fn array_len_raw(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:38: +0:41 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:55: +0:60 + let _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + let _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:27 + let _7: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:14: +3:19 + scope 1 { + debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12 + let _5: *const [u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 2 { + debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 3 { + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _4 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _3 = &(*_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:24: +1:25 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:26 + StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + _5 = &raw const (*_2); // scope 1 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + StorageLive(_7); // scope 2 at $DIR/lower_array_len.rs:+3:14: +3:19 + _7 = &(*_5); // scope 3 at $DIR/lower_array_len.rs:+3:14: +3:19 + _6 = &(*_7); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 +- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 ++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + } + + bb1: { + StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:26: +3:27 + StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff new file mode 100644 index 00000000000..8bdd2ede6bc --- /dev/null +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff @@ -0,0 +1,44 @@ +- // MIR for `array_len_reborrow` before NormalizeArrayLen ++ // MIR for `array_len_reborrow` after NormalizeArrayLen + + fn array_len_reborrow(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:50 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:64: +0:69 + let _2: &mut [u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + let mut _3: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + let mut _4: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:14 + scope 1 { + debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12 + let _5: &[u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 2 { + debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _4 = &mut _1; // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _3 = &mut (*_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _2 = move _3 as &mut [u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:32: +1:33 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:33: +1:34 + StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + _5 = &(*_2); // scope 1 at $DIR/lower_array_len.rs:+2:15: +2:20 + StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + _6 = &(*_5); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 +- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 ++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + } + + bb1: { + StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:13: +3:14 + StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs index ea0224b21d7..972d46cb8e2 100644 --- a/tests/mir-opt/lower_array_len.rs +++ b/tests/mir-opt/lower_array_len.rs @@ -31,10 +31,26 @@ pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize { arr.len() } +// EMIT_MIR lower_array_len.array_len_reborrow.NormalizeArrayLen.diff +pub fn array_len_reborrow<const N: usize>(mut arr: [u8; N]) -> usize { + let arr: &mut [_] = &mut arr; + let arr = &*arr; + arr.len() +} + +// EMIT_MIR lower_array_len.array_len_raw.NormalizeArrayLen.diff +pub fn array_len_raw<const N: usize>(arr: [u8; N]) -> usize { + let arr: &[_] = &arr; + let arr = std::ptr::addr_of!(*arr); + unsafe { &*arr }.len() +} + fn main() { let _ = array_bound(3, &[0, 1, 2, 3]); let mut tmp = [0, 1, 2, 3, 4]; let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); let _ = array_len(&[0]); let _ = array_len_by_value([0, 2]); + let _ = array_len_reborrow([0, 2]); + let _ = array_len_raw([0, 2]); } diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir deleted file mode 100644 index 701c2ad705a..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir +++ /dev/null @@ -1,45 +0,0 @@ -// MIR for `array_bound` after PreCodegen - -fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - } - - bb1: { - _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 - } - - bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir deleted file mode 100644 index 0440cfce289..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir +++ /dev/null @@ -1,58 +0,0 @@ -// MIR for `array_bound_mut` after PreCodegen - -fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - } - - bb1: { - _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - _8 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - _9 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - _10 = Lt(const 0_usize, _9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - } - - bb4: { - (*_2)[_8] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22 - StorageDead(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 - } - - bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir deleted file mode 100644 index 4b19f679558..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir +++ /dev/null @@ -1,11 +0,0 @@ -// MIR for `array_len` after PreCodegen - -fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57 - - bb0: { - _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir deleted file mode 100644 index 4dc0ba9a268..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir +++ /dev/null @@ -1,11 +0,0 @@ -// MIR for `array_len_by_value` after PreCodegen - -fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65 - - bb0: { - _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.rs b/tests/mir-opt/lower_array_len_e2e.rs deleted file mode 100644 index d8e4e521ee6..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.rs +++ /dev/null @@ -1,39 +0,0 @@ -// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts - -// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir -pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 { - if index < slice.len() { - slice[index] - } else { - 42 - } -} - -// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir -pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 { - if index < slice.len() { - slice[index] - } else { - slice[0] = 42; - - 42 - } -} - -// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir -pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize { - arr.len() -} - -// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir -pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize { - arr.len() -} - -fn main() { - let _ = array_bound(3, &[0, 1, 2, 3]); - let mut tmp = [0, 1, 2, 3, 4]; - let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); - let _ = array_len(&[0]); - let _ = array_len_by_value([0, 2]); -} diff --git a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir index 916f99049c6..760f48d956d 100644 --- a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir @@ -37,7 +37,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> { bb3: { _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - _4 = Add(move _5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 + _4 = Add(_5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 Deinit(_0); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 discriminant(_0) = 1; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 diff --git a/tests/mir-opt/simplify_match.main.ConstProp.diff b/tests/mir-opt/simplify_match.main.ConstProp.diff index 70bfbf1b3e3..35ffc4963cb 100644 --- a/tests/mir-opt/simplify_match.main.ConstProp.diff +++ b/tests/mir-opt/simplify_match.main.ConstProp.diff @@ -10,13 +10,9 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify_match.rs:+1:11: +1:31 StorageLive(_2); // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18 _2 = const false; // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26 -- _1 = _2; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29 -+ _1 = const false; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29 - StorageDead(_2); // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31 -- switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 +- switchInt(_2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 + switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 } @@ -32,7 +28,6 @@ } bb3: { - StorageDead(_1); // scope 0 at $DIR/simplify_match.rs:+5:1: +5:2 return; // scope 0 at $DIR/simplify_match.rs:+5:2: +5:2 } } diff --git a/tests/mir-opt/slice_filter.rs b/tests/mir-opt/slice_filter.rs new file mode 100644 index 00000000000..97c18af31de --- /dev/null +++ b/tests/mir-opt/slice_filter.rs @@ -0,0 +1,18 @@ +fn main() { + let input = vec![]; + let _variant_a_result = variant_a(&input); + let _variant_b_result = variant_b(&input); +} + +pub fn variant_a(input: &[(usize, usize, usize, usize)]) -> usize { + input.iter().filter(|(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count() +} + +pub fn variant_b(input: &[(usize, usize, usize, usize)]) -> usize { + input.iter().filter(|&&(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count() +} + +// EMIT_MIR slice_filter.variant_a-{closure#0}.CopyProp.diff +// EMIT_MIR slice_filter.variant_a-{closure#0}.DestinationPropagation.diff +// EMIT_MIR slice_filter.variant_b-{closure#0}.CopyProp.diff +// EMIT_MIR slice_filter.variant_b-{closure#0}.DestinationPropagation.diff diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff new file mode 100644 index 00000000000..d1f6fd97dc7 --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff @@ -0,0 +1,279 @@ +- // MIR for `variant_a::{closure#0}` before CopyProp ++ // MIR for `variant_a::{closure#0}` after CopyProp + + fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40 + let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46 + let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41 + let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56 + let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51 + let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76 + let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66 + let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61 + let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76 + let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71 + let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 + scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46 + debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _31: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _32: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _31; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _32; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _33: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _34: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66 + debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _35: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _36: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _37: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _38: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _35; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _36; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _37; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _38; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _39: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _40: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56 + debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _41: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _42: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _43: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _44: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _41; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _42; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _43; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _44; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _45: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _46: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76 + debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _47: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _48: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _49: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _50: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _47; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _48; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _49; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _50; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _51: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _52: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 + StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageLive(_29); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + _31 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _29 = _31; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_30); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + _32 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _30 = _32; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _33 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _33 = (*_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _34 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _34 = (*_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _8 = Le(move _33, move _34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_30); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_29); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb2: { + StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 + StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageLive(_35); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + _37 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _35 = _37; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_36); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + _38 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _36 = _38; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _39 = (*_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _39 = (*_37); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _40 = (*_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _40 = (*_38); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _17 = Le(move _39, move _40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_36); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_35); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb3: { + StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76 + } + + bb4: { + _7 = const false; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb5: { + StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 + StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageLive(_41); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + _43 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _41 = _43; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_42); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + _44 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _42 = _44; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _45 = (*_41); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _45 = (*_43); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _46 = (*_42); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _46 = (*_44); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _12 = Le(move _45, move _46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_42); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_41); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb6: { + _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb7: { + StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 + StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageLive(_47); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + _49 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _47 = _49; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_48); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + _50 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _48 = _50; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _51 = (*_47); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _51 = (*_49); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _52 = (*_48); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _52 = (*_50); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _21 = Le(move _51, move _52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_48); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_47); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb8: { + StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + } + diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff new file mode 100644 index 00000000000..259cd411896 --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff @@ -0,0 +1,241 @@ +- // MIR for `variant_a::{closure#0}` before DestinationPropagation ++ // MIR for `variant_a::{closure#0}` after DestinationPropagation + + fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40 + let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46 + let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41 + let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56 + let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51 + let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76 + let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66 + let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61 + let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76 + let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71 + let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 + scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46 + debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _31: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _32: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66 + debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _33: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _34: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _33; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _34; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _35: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _36: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56 + debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _37: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _38: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _37; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _38; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _39: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _40: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76 + debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _41: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _42: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _41; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _42; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _43: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _44: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 +- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 + StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _29 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + _30 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _31 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _32 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _8 = Le(move _31, move _32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb2: { +- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 + StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _33 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + _34 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _35 = (*_33); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _36 = (*_34); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _17 = Le(move _35, move _36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb3: { +- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76 + } + + bb4: { +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb5: { +- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 + StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _37 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + _38 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _39 = (*_37); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _40 = (*_38); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _12 = Le(move _39, move _40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 ++ switchInt(move _12) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb6: { +- _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 ++ _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb7: { +- StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 + StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _41 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + _42 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _43 = (*_41); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _44 = (*_42); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _21 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _0 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb8: { +- StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + } + diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff new file mode 100644 index 00000000000..c3b8e7d2eba --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff @@ -0,0 +1,139 @@ +- // MIR for `variant_b::{closure#0}` before CopyProp ++ // MIR for `variant_b::{closure#0}` after CopyProp + + fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42 + let _3: usize; // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + let _4: usize; // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + let _5: usize; // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + let _6: usize; // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48 + let mut _9: usize; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:43 + let mut _10: usize; // in scope 0 at $DIR/slice_filter.rs:+0:47: +0:48 + let mut _11: bool; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58 + let mut _12: usize; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:53 + let mut _13: usize; // in scope 0 at $DIR/slice_filter.rs:+0:57: +0:58 + let mut _14: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78 + let mut _15: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68 + let mut _16: usize; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:63 + let mut _17: usize; // in scope 0 at $DIR/slice_filter.rs:+0:67: +0:68 + let mut _18: bool; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78 + let mut _19: usize; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:73 + let mut _20: usize; // in scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 + let mut _21: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _22: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _23: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _24: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _21 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _3 = ((*_21).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _22 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _4 = ((*_22).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _23 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _5 = ((*_23).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _24 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _6 = ((*_24).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 +- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43 +- _9 = _3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43 +- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 +- _10 = _5; // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 +- _8 = Le(move _9, move _10); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 +- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 ++ _8 = Le(_3, _5); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb2: { + StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 +- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63 +- _16 = _5; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63 +- StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 +- _17 = _3; // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 +- _15 = Le(move _16, move _17); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 +- StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 +- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 ++ _15 = Le(_5, _3); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 + switchInt(move _15) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb3: { + StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 + return; // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78 + } + + bb4: { + _7 = const false; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb5: { + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 +- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53 +- _12 = _6; // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53 +- StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- _13 = _4; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- _11 = Le(move _12, move _13); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 +- StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 ++ _11 = Le(_6, _4); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 + _7 = move _11; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb6: { + _14 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb7: { + StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73 +- _19 = _4; // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73 +- StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- _20 = _6; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- _18 = Le(move _19, move _20); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ _18 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 + _14 = move _18; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb8: { + StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + _0 = move _14; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + } + diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff new file mode 100644 index 00000000000..a43e84d29c7 --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff @@ -0,0 +1,113 @@ +- // MIR for `variant_b::{closure#0}` before DestinationPropagation ++ // MIR for `variant_b::{closure#0}` after DestinationPropagation + + fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42 + let _3: usize; // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + let _4: usize; // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + let _5: usize; // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + let _6: usize; // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48 + let mut _9: bool; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58 + let mut _10: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78 + let mut _11: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68 + let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78 + let mut _13: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _14: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _15: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _16: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _13 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _3 = ((*_13).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _14 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _4 = ((*_14).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _15 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _5 = ((*_15).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _16 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _6 = ((*_16).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 +- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 + _8 = Le(_3, _5); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb2: { +- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 + _11 = Le(_5, _3); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 + switchInt(move _11) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb3: { +- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + return; // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78 + } + + bb4: { +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb5: { +- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 + _9 = Le(_6, _4); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 +- _7 = move _9; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 ++ switchInt(move _9) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb6: { +- _10 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 ++ _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb7: { +- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- _12 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- _10 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 ++ _0 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb8: { +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- _0 = move _10; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + } + diff --git a/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir b/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir index b254bfeb7c9..7c67d2abcf7 100644 --- a/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir +++ b/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir @@ -5,11 +5,11 @@ fn new(_1: Result<T, E>) -> Result<T, E> { let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46 let mut _2: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 let mut _3: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22 - let mut _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49 - let mut _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47 + let _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 + let _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 let mut _6: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37 let _7: T; // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 - let mut _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50 + let _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 scope 1 { debug v => _4; // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21 } @@ -30,6 +30,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> { } bb1: { + StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 Deinit(_2); // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 ((_2 as Break).0: E) = move _5; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 @@ -39,6 +40,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> { } bb2: { + StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 _4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 Deinit(_2); // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 ((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 @@ -48,6 +50,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> { } bb3: { + StorageLive(_8); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 _8 = move ((_2 as Break).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 Deinit(_0); // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 ((_0 as Err).0: E) = move _8; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 @@ -61,6 +64,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> { } bb5: { + StorageLive(_7); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 ((_0 as Ok).0: T) = move _7; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 diff --git a/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir b/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir index cdbc0681cb8..4a838e14026 100644 --- a/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir +++ b/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir @@ -5,7 +5,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> { let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46 let mut _2: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18 let _3: T; // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 - let mut _4: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35 + let _4: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 scope 1 { debug v => _3; // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17 } @@ -19,6 +19,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> { } bb1: { + StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 _4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 Deinit(_0); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 ((_0 as Err).0: E) = move _4; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 @@ -31,6 +32,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> { } bb3: { + StorageLive(_3); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 ((_0 as Ok).0: T) = move _3; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir index b95d91b13dd..318119bd477 100644 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -4,9 +4,7 @@ fn while_loop(_1: bool) -> () { debug c => _1; // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16 let mut _0: (); // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24 let mut _2: bool; // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22 - let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - let mut _4: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23 - let mut _5: bool; // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22 + let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23 bb0: { goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 @@ -14,41 +12,35 @@ fn while_loop(_1: bool) -> () { bb1: { StorageLive(_2); // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 - StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - _3 = _1; // scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 + _2 = get_bool(_1) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 // mir::Constant // + span: $DIR/while_storage.rs:10:11: 10:19 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) } } bb2: { - StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+1:21: +1:22 switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 } bb3: { - StorageLive(_4); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 - StorageLive(_5); // scope 0 at $DIR/while_storage.rs:+2:21: +2:22 - _5 = _1; // scope 0 at $DIR/while_storage.rs:+2:21: +2:22 - _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + _3 = get_bool(_1) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 // mir::Constant // + span: $DIR/while_storage.rs:11:12: 11:20 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) } } bb4: { - StorageDead(_5); // scope 0 at $DIR/while_storage.rs:+2:22: +2:23 - switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 } bb5: { - StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 + StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 goto -> bb7; // scope 0 at no-location } bb6: { - StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 + StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 } diff --git a/tests/pretty/dollar-crate.pp b/tests/pretty/dollar-crate.pp index 3af37955f23..60fddb630d9 100644 --- a/tests/pretty/dollar-crate.pp +++ b/tests/pretty/dollar-crate.pp @@ -8,6 +8,4 @@ extern crate std; // pretty-mode:expanded // pp-exact:dollar-crate.pp -fn main() { - { ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); }; -} +fn main() { { ::std::io::_print(format_args!("rust\n")); }; } diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 18e6d75b1d5..e0fa1fe2824 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -32,12 +32,13 @@ fn bar() ({ ({ let res = ((::alloc::fmt::format as - for<'a> fn(Arguments<'a>) -> String {format})(((::core::fmt::Arguments::new_v1 + for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1 as - fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" + fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" as &str)] as [&str; 1]) as &[&str; 1]), - (&([] as [ArgumentV1<'_>; 0]) as &[ArgumentV1<'_>; 0])) as - Arguments<'_>)) as String); + (&([] as [core::fmt::ArgumentV1<'_>; 0]) as + &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as + String); (res as String) } as String); } as ()) diff --git a/tests/run-make-fulldeps/split-debuginfo/Makefile b/tests/run-make-fulldeps/split-debuginfo/Makefile index 1831ab38fab..44cda0d3d11 100644 --- a/tests/run-make-fulldeps/split-debuginfo/Makefile +++ b/tests/run-make-fulldeps/split-debuginfo/Makefile @@ -254,12 +254,12 @@ unpacked-remapped-single: $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \ -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1 - ls $(TMPDIR)/*.o + rm $(TMPDIR)/*.o ls $(TMPDIR)/*.dwo && exit 1 || exit 0 ls $(TMPDIR)/*.dwp && exit 1 || exit 0 rm $(TMPDIR)/$(call BIN,foo) -unpacked-crosscrate: packed-crosscrate-split packed-crosscrate-single +unpacked-crosscrate: unpacked-crosscrate-split unpacked-crosscrate-single # - Debuginfo in `.dwo` files # - (bar) `.rlib` file created, contains `.dwo` diff --git a/tests/run-make/native-link-modifier-bundle/Makefile b/tests/run-make/native-link-modifier-bundle/Makefile index 7c78d7783e0..e8a1121bfcd 100644 --- a/tests/run-make/native-link-modifier-bundle/Makefile +++ b/tests/run-make/native-link-modifier-bundle/Makefile @@ -5,7 +5,12 @@ include ../../run-make-fulldeps/tools.mk # We're using the llvm-nm instead of the system nm to ensure it is compatible # with the LLVM bitcode generated by rustc. +# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm. +ifndef IS_WINDOWS NM = "$(LLVM_BIN_DIR)"/llvm-nm +else +NM = nm +endif all: $(call NATIVE_STATICLIB,native-staticlib) # Build a staticlib and a rlib, the `native_func` symbol will be bundled into them diff --git a/tests/run-make/overwrite-input/Makefile b/tests/run-make/overwrite-input/Makefile new file mode 100644 index 00000000000..03b03eb147d --- /dev/null +++ b/tests/run-make/overwrite-input/Makefile @@ -0,0 +1,13 @@ +include ../../run-make-fulldeps/tools.mk + +all: + $(RUSTC) main.rs -o main.rs 2> $(TMPDIR)/file.stderr || echo "failed successfully" + $(RUSTC) main.rs -o . 2> $(TMPDIR)/folder.stderr || echo "failed successfully" + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/file.stderr file.stderr + cp "$(TMPDIR)"/folder.stderr folder.stderr +else + $(DIFF) file.stderr "$(TMPDIR)"/file.stderr + $(DIFF) folder.stderr "$(TMPDIR)"/folder.stderr +endif diff --git a/tests/run-make/overwrite-input/file.stderr b/tests/run-make/overwrite-input/file.stderr new file mode 100644 index 00000000000..9936962b4ee --- /dev/null +++ b/tests/run-make/overwrite-input/file.stderr @@ -0,0 +1,6 @@ +warning: ignoring --out-dir flag due to -o flag + +error: the input file "main.rs" would be overwritten by the generated executable + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/run-make/overwrite-input/folder.stderr b/tests/run-make/overwrite-input/folder.stderr new file mode 100644 index 00000000000..81b1e7367c7 --- /dev/null +++ b/tests/run-make/overwrite-input/folder.stderr @@ -0,0 +1,6 @@ +warning: ignoring --out-dir flag due to -o flag + +error: the generated executable for the input file "main.rs" conflicts with the existing directory "." + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/run-make/overwrite-input/main.rs b/tests/run-make/overwrite-input/main.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/overwrite-input/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/overwrite-input/main.stderr b/tests/run-make/overwrite-input/main.stderr new file mode 100644 index 00000000000..9936962b4ee --- /dev/null +++ b/tests/run-make/overwrite-input/main.stderr @@ -0,0 +1,6 @@ +warning: ignoring --out-dir flag due to -o flag + +error: the input file "main.rs" would be overwritten by the generated executable + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile index 9e603f95835..722a49b02cb 100644 --- a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile +++ b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile @@ -4,15 +4,19 @@ include ../../run-make-fulldeps/tools.mk +# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility +# with the LLVM bitcode generated by rustc but on Windows piping/IO redirection under MSYS2 is wonky with llvm-objdump. +OBJDUMP = objdump + all: $(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic $(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic # Make sure we don't find an import to the functions we expect to be inlined. - "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function" - "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline" + $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function" + $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline" # Make sure we do find an import to the functions we expect to be imported. - "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function" + $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function" $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) ifdef IS_MSVC diff --git a/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile b/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile index 4574cf17f0e..37b8d809a27 100644 --- a/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile +++ b/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile @@ -6,7 +6,12 @@ # We're using the llvm-nm instead of the system nm to ensure it is compatible # with the LLVM bitcode generated by rustc. +# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm. +ifndef IS_WINDOWS NM = "$(LLVM_BIN_DIR)"/llvm-nm +else +NM = nm +endif all: # Build strange-named dep. diff --git a/tests/run-make/rlib-format-packed-bundled-libs/Makefile b/tests/run-make/rlib-format-packed-bundled-libs/Makefile index 0b991ac42e3..7fb6ce8d1e4 100644 --- a/tests/run-make/rlib-format-packed-bundled-libs/Makefile +++ b/tests/run-make/rlib-format-packed-bundled-libs/Makefile @@ -6,7 +6,12 @@ # We're using the llvm-nm instead of the system nm to ensure it is compatible # with the LLVM bitcode generated by rustc. +# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm. +ifndef IS_WINDOWS NM = "$(LLVM_BIN_DIR)"/llvm-nm +else +NM = nm +endif all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3) $(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml index 05f8ddc716e..3f4f65890b4 100644 --- a/tests/rustdoc-gui/label-next-to-symbol.goml +++ b/tests/rustdoc-gui/label-next-to-symbol.goml @@ -20,7 +20,7 @@ assert-css: ( // table like view assert-css: (".item-right.docblock-short", { "padding-left": "0px" }) compare-elements-position-near: ( - "//*[@class='item-left module-item']//a[text()='replaced_function']", + "//*[@class='item-left']//a[text()='replaced_function']", ".item-left .stab.deprecated", {"y": 2}, ) @@ -32,7 +32,7 @@ compare-elements-position: ( // Ensure no wrap compare-elements-position: ( - "//*[@class='item-left module-item']//a[text()='replaced_function']/..", + "//*[@class='item-left']//a[text()='replaced_function']/..", "//*[@class='item-right docblock-short'][text()='a thing with a label']", ("y"), ) @@ -43,7 +43,7 @@ size: (600, 600) // staggered layout with 2em spacing assert-css: (".item-right.docblock-short", { "padding-left": "32px" }) compare-elements-position-near: ( - "//*[@class='item-left module-item']//a[text()='replaced_function']", + "//*[@class='item-left']//a[text()='replaced_function']", ".item-left .stab.deprecated", {"y": 2}, ) @@ -55,7 +55,7 @@ compare-elements-position: ( // Ensure wrap compare-elements-position-false: ( - "//*[@class='item-left module-item']//a[text()='replaced_function']/..", + "//*[@class='item-left']//a[text()='replaced_function']/..", "//*[@class='item-right docblock-short'][text()='a thing with a label']", ("y"), ) diff --git a/tests/rustdoc-gui/mobile.goml b/tests/rustdoc-gui/mobile.goml index 895864d8944..3e444cbd6dc 100644 --- a/tests/rustdoc-gui/mobile.goml +++ b/tests/rustdoc-gui/mobile.goml @@ -28,7 +28,7 @@ goto: "file://" + |DOC_PATH| + "/settings.html" size: (400, 600) // Ignored for now https://github.com/rust-lang/rust/issues/93784. // compare-elements-position-near-false: ( -// "#preferred-light-theme .setting-name", -// "#preferred-light-theme .choice", +// "#preferred-light-theme .setting-radio-name", +// "#preferred-light-theme .setting-radio", // {"y": 16}, // ) diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml index cd3676a9871..5940962a8dd 100644 --- a/tests/rustdoc-gui/module-items-font.goml +++ b/tests/rustdoc-gui/module-items-font.goml @@ -1,7 +1,7 @@ // This test checks that the correct font is used on module items (in index.html pages). goto: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-css: ( - ".item-table .module-item a", + ".item-table .item-left > a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL, ) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 419cc5ebac3..a8417288578 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -43,12 +43,12 @@ wait-for: "#settings" // We check that the "Use system theme" is disabled. assert-property: ("#theme-system-preference", {"checked": "false"}) // Meaning that only the "theme" menu is showing up. -assert: ".setting-line:not(.hidden) #theme" -assert: ".setting-line.hidden #preferred-dark-theme" -assert: ".setting-line.hidden #preferred-light-theme" +assert: "#theme.setting-line:not(.hidden)" +assert: "#preferred-dark-theme.setting-line.hidden" +assert: "#preferred-light-theme.setting-line.hidden" // We check that the correct theme is selected. -assert-property: ("#theme .choices #theme-dark", {"checked": "true"}) +assert-property: ("#theme .setting-radio-choices #theme-dark", {"checked": "true"}) // Some style checks... move-cursor-to: "#settings-menu > a" @@ -109,31 +109,31 @@ assert-css: ( "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", }, ) -// Now we check the setting-name for radio buttons is on a different line than the label. +// Now we check the setting-radio-name is on a different line than the label. compare-elements-position-near: ( - "#theme .setting-name", - "#theme .choices", + "#theme .setting-radio-name", + "#theme .setting-radio-choices", {"x": 1} ) compare-elements-position-near-false: ( - "#theme .setting-name", - "#theme .choices", + "#theme .setting-radio-name", + "#theme .setting-radio-choices", {"y": 1} ) // Now we check that the label positions are all on the same line. compare-elements-position-near: ( - "#theme .choices #theme-light", - "#theme .choices #theme-dark", + "#theme .setting-radio-choices #theme-light", + "#theme .setting-radio-choices #theme-dark", {"y": 1} ) compare-elements-position-near: ( - "#theme .choices #theme-dark", - "#theme .choices #theme-ayu", + "#theme .setting-radio-choices #theme-dark", + "#theme .setting-radio-choices #theme-ayu", {"y": 1} ) compare-elements-position-near: ( - "#theme .choices #theme-ayu", - "#theme .choices #theme-system-preference", + "#theme .setting-radio-choices #theme-ayu", + "#theme .setting-radio-choices #theme-system-preference", {"y": 1} ) @@ -180,17 +180,17 @@ assert-css: ( // We now switch the display. click: "#theme-system-preference" // Wait for the hidden element to show up. -wait-for: ".setting-line:not(.hidden) #preferred-dark-theme" -assert: ".setting-line:not(.hidden) #preferred-light-theme" +wait-for: "#preferred-dark-theme.setting-line:not(.hidden)" +assert: "#preferred-light-theme.setting-line:not(.hidden)" // We check their text as well. -assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme") -assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme") +assert-text: ("#preferred-dark-theme .setting-radio-name", "Preferred dark theme") +assert-text: ("#preferred-light-theme .setting-radio-name", "Preferred light theme") // We now check that clicking on the toggles' text is like clicking on the checkbox. // To test it, we use the "Disable keyboard shortcuts". local-storage: {"rustdoc-disable-shortcuts": "false"} -click: ".setting-line:last-child .settings-toggle .label" +click: ".setting-line:last-child .setting-check span" assert-local-storage: {"rustdoc-disable-shortcuts": "true"} // Make sure that "Disable keyboard shortcuts" actually took effect. @@ -200,7 +200,7 @@ assert-false: "#help-button .popover" wait-for-css: ("#settings-menu .popover", {"display": "block"}) // Now turn keyboard shortcuts back on, and see if they work. -click: ".setting-line:last-child .settings-toggle .label" +click: ".setting-line:last-child .setting-check span" assert-local-storage: {"rustdoc-disable-shortcuts": "false"} press-key: "Escape" press-key: "?" diff --git a/tests/rustdoc-gui/src-font-size.goml b/tests/rustdoc-gui/src-font-size.goml index 9233f37444b..bab66dae70c 100644 --- a/tests/rustdoc-gui/src-font-size.goml +++ b/tests/rustdoc-gui/src-font-size.goml @@ -4,13 +4,13 @@ goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" show-text: true // Check the impl headers. -assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) -assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL) +assert-css: (".impl .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl .code-header", {"font-size": "18px", "font-weight": 600}, ALL) // Check the impl items. -assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) -assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL) +assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL) // Check that we can click on source link store-document-property: (url, "URL") -click: ".impl-items .has-srclink .srclink" +click: ".impl-items .srclink" assert-document-property-false: {"URL": |url|} diff --git a/tests/rustdoc-gui/theme-change.goml b/tests/rustdoc-gui/theme-change.goml index cc47f1f450c..31c9d99aa83 100644 --- a/tests/rustdoc-gui/theme-change.goml +++ b/tests/rustdoc-gui/theme-change.goml @@ -43,7 +43,7 @@ assert-local-storage: { "rustdoc-theme": "ayu" } assert-local-storage-false: { "rustdoc-use-system-theme": "true" } click: "#theme-system-preference" -wait-for: ".setting-line:not(.hidden) #preferred-light-theme" +wait-for: "#preferred-light-theme.setting-line:not(.hidden)" assert-local-storage: { "rustdoc-use-system-theme": "true" } // We click on both preferred light and dark themes to be sure that there is a change. click: "#preferred-light-theme-dark" @@ -52,16 +52,16 @@ wait-for-css: ("body", { "background-color": |background_dark| }) reload: // Ensure that the "preferred themes" are still displayed. -wait-for: ".setting-line:not(.hidden) #preferred-light-theme" +wait-for: "#preferred-light-theme.setting-line:not(.hidden)" click: "#theme-light" wait-for-css: ("body", { "background-color": |background_light| }) assert-local-storage: { "rustdoc-theme": "light" } // Ensure it's now hidden again -wait-for: ".setting-line.hidden #preferred-light-theme" +wait-for: "#preferred-light-theme.setting-line.hidden" // And ensure the theme was rightly set. wait-for-css: ("body", { "background-color": |background_light| }) assert-local-storage: { "rustdoc-theme": "light" } reload: wait-for: "#settings" -assert: ".setting-line.hidden #preferred-light-theme" +assert: "#preferred-light-theme.setting-line.hidden" diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml index d3a672ddde6..3ecb25c82a4 100644 --- a/tests/rustdoc-gui/unsafe-fn.goml +++ b/tests/rustdoc-gui/unsafe-fn.goml @@ -4,8 +4,8 @@ goto: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true compare-elements-property: ( - "//a[@title='test_docs::safe_fn fn']/..", - "//a[@title='test_docs::unsafe_fn fn']/..", + "//a[@title='fn test_docs::safe_fn']/..", + "//a[@title='fn test_docs::unsafe_fn']/..", ["clientHeight"] ) diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 4bdecdc1b79..4f07fca82d1 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -20,6 +20,7 @@ -Z dlltool=val -- import library generation tool (windows-gnu only) -Z dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no) -Z drop-tracking=val -- enables drop tracking in generators (default: no) + -Z drop-tracking-mir=val -- enables drop tracking on MIR in generators (default: no) -Z dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no) -Z dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no) -Z dump-drop-tracking-cfg=val -- dump drop-tracking control-flow graph as a `.dot` file (default: no) @@ -172,6 +173,7 @@ -Z threads=val -- use a thread pool with N threads -Z time-llvm-passes=val -- measure time of each LLVM pass (default: no) -Z time-passes=val -- measure time of each rustc pass (default: no) + -Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests -Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details) -Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no) -Z track-diagnostics=val -- tracks where in rustc a diagnostic was emitted diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors.no_const_anchor.html index 75e67330a3e..a8587829d3e 100644 --- a/tests/rustdoc/anchors.no_const_anchor.html +++ b/tests/rustdoc/anchors.no_const_anchor.html @@ -1 +1 @@ -<section id="associatedconstant.YOLO" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> \ No newline at end of file +<section id="associatedconstant.YOLO" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors.no_const_anchor2.html index c0025197602..4c5e45fea2d 100644 --- a/tests/rustdoc/anchors.no_const_anchor2.html +++ b/tests/rustdoc/anchors.no_const_anchor2.html @@ -1 +1 @@ -<section id="associatedconstant.X" class="associatedconstant has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section> \ No newline at end of file +<section id="associatedconstant.X" class="associatedconstant"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors.no_method_anchor.html index b9ec8bf4c09..44957a5b71a 100644 --- a/tests/rustdoc/anchors.no_method_anchor.html +++ b/tests/rustdoc/anchors.no_method_anchor.html @@ -1 +1 @@ -<section id="method.new" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section> \ No newline at end of file +<section id="method.new" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors.no_trait_method_anchor.html index 4308ddad412..75c2caf87a8 100644 --- a/tests/rustdoc/anchors.no_trait_method_anchor.html +++ b/tests/rustdoc/anchors.no_trait_method_anchor.html @@ -1 +1 @@ -<section id="method.bar" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section> \ No newline at end of file +<section id="method.bar" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors.no_tymethod_anchor.html index 91eed8a3742..38575eadfa9 100644 --- a/tests/rustdoc/anchors.no_tymethod_anchor.html +++ b/tests/rustdoc/anchors.no_tymethod_anchor.html @@ -1 +1 @@ -<section id="tymethod.foo" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section> \ No newline at end of file +<section id="tymethod.foo" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors.no_type_anchor.html index 2c66d5aa315..dd65d98fee6 100644 --- a/tests/rustdoc/anchors.no_type_anchor.html +++ b/tests/rustdoc/anchors.no_type_anchor.html @@ -1 +1 @@ -<section id="associatedtype.T" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section> \ No newline at end of file +<section id="associatedtype.T" class="method"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section> \ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors.no_type_anchor2.html index 72a1186bf7e..f8b59160f15 100644 --- a/tests/rustdoc/anchors.no_type_anchor2.html +++ b/tests/rustdoc/anchors.no_type_anchor2.html @@ -1 +1 @@ -<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> +<section id="associatedtype.Y" class="associatedtype"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> \ No newline at end of file diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async-fn.rs index fb7ebb5f822..8cafb5a2497 100644 --- a/tests/rustdoc/async-fn.rs +++ b/tests/rustdoc/async-fn.rs @@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } impl Foo { // @has async_fn/struct.Foo.html - // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' + // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {} // taken from `tokio` as an example of a method that was particularly bad before - // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" + // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {} - // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)" + // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)" pub async fn mut_self(&mut self) {} } diff --git a/tests/rustdoc/cfg_doc_reexport.rs b/tests/rustdoc/cfg_doc_reexport.rs index addb6709db1..89c7f0a6f34 100644 --- a/tests/rustdoc/cfg_doc_reexport.rs +++ b/tests/rustdoc/cfg_doc_reexport.rs @@ -5,8 +5,8 @@ #![no_core] // @has 'foo/index.html' -// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar' -// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar' +// @has - '//*[@class="item-left"]/*[@class="stab portability"]' 'foobar' +// @has - '//*[@class="item-left"]/*[@class="stab portability"]' 'bar' #[doc(cfg(feature = "foobar"))] mod imp_priv { diff --git a/tests/rustdoc/const-fn.rs b/tests/rustdoc/const-fn.rs index 4366ad4d0ad..18863abaeac 100644 --- a/tests/rustdoc/const-fn.rs +++ b/tests/rustdoc/const-fn.rs @@ -8,7 +8,7 @@ pub const fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method has-srclink"]' 'const fn new()' +// @has - '//*[@class="method"]' 'const fn new()' pub struct Foo(usize); impl Foo { diff --git a/tests/rustdoc/const-generics/const-generic-slice.rs b/tests/rustdoc/const-generics/const-generic-slice.rs index 4279de91f56..80a9ab3f12e 100644 --- a/tests/rustdoc/const-generics/const-generic-slice.rs +++ b/tests/rustdoc/const-generics/const-generic-slice.rs @@ -5,7 +5,7 @@ pub trait Array { } // @has foo/trait.Array.html -// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]' +// @has - '//*[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]' impl<T, const N: usize> Array for [T; N] { type Item = T; } diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc/deprecated.rs index b3178da98ee..5cbe4d59108 100644 --- a/tests/rustdoc/deprecated.rs +++ b/tests/rustdoc/deprecated.rs @@ -1,4 +1,4 @@ -// @has deprecated/index.html '//*[@class="item-left module-item"]/span[@class="stab deprecated"]' \ +// @has deprecated/index.html '//*[@class="item-left"]/span[@class="stab deprecated"]' \ // 'Deprecated' // @has - '//*[@class="item-right docblock-short"]' 'Deprecated docs' diff --git a/tests/rustdoc/doc-assoc-item.rs b/tests/rustdoc/doc-assoc-item.rs index 4f15418650c..4d5c9f83e1e 100644 --- a/tests/rustdoc/doc-assoc-item.rs +++ b/tests/rustdoc/doc-assoc-item.rs @@ -8,7 +8,7 @@ pub trait Bar { fn foo(foo: Self::Fuu); } -// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' +// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' impl<T: Bar<Fuu = u32>> Foo<T> { pub fn new(t: T) -> Foo<T> { Foo { diff --git a/tests/rustdoc/doc-cfg.rs b/tests/rustdoc/doc-cfg.rs index 4cddb0b76d4..1cfbfec6fcd 100644 --- a/tests/rustdoc/doc-cfg.rs +++ b/tests/rustdoc/doc-cfg.rs @@ -12,7 +12,7 @@ pub struct Portable; // @has doc_cfg/unix_only/index.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ // 'Available on Unix only.' -// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AARM\Z' +// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\AARM\Z' // @count - '//*[@class="stab portability"]' 2 #[doc(cfg(unix))] pub mod unix_only { @@ -42,7 +42,7 @@ pub mod unix_only { // @has doc_cfg/wasi_only/index.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ // 'Available on WASI only.' -// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AWebAssembly\Z' +// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\AWebAssembly\Z' // @count - '//*[@class="stab portability"]' 2 #[doc(cfg(target_os = "wasi"))] pub mod wasi_only { @@ -74,7 +74,7 @@ pub mod wasi_only { // the portability header is different on the module view versus the full view // @has doc_cfg/index.html -// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\Aavx\Z' +// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\Aavx\Z' // @has doc_cfg/fn.uses_target_feature.html // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ diff --git a/tests/rustdoc/duplicate-cfg.rs b/tests/rustdoc/duplicate-cfg.rs index 18f3900b263..1ac2e523249 100644 --- a/tests/rustdoc/duplicate-cfg.rs +++ b/tests/rustdoc/duplicate-cfg.rs @@ -2,8 +2,8 @@ #![feature(doc_cfg)] // @has 'foo/index.html' -// @matches '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]' '^sync$' -// @has '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' +// @matches '-' '//*[@class="item-left"]//*[@class="stab portability"]' '^sync$' +// @has '-' '//*[@class="item-left"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' // @has 'foo/struct.Foo.html' // @has '-' '//*[@class="stab portability"]' 'sync' diff --git a/tests/rustdoc/duplicate_impls/issue-33054.rs b/tests/rustdoc/duplicate_impls/issue-33054.rs index c1f95ac91c3..4c2071b8322 100644 --- a/tests/rustdoc/duplicate_impls/issue-33054.rs +++ b/tests/rustdoc/duplicate_impls/issue-33054.rs @@ -3,8 +3,8 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//h3[@class="code-header"]' 'impl Foo' // @has - '//h3[@class="code-header"]' 'impl Bar for Foo' -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//h3[@class="code-header"]' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 diff --git a/tests/rustdoc/duplicated_impl.rs b/tests/rustdoc/duplicated_impl.rs index 4e901b31c90..f32cf310055 100644 --- a/tests/rustdoc/duplicated_impl.rs +++ b/tests/rustdoc/duplicated_impl.rs @@ -7,7 +7,7 @@ // blanket implementations. // @has 'foo/struct.Whatever.html' -// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1 +// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl"]' 1 pub trait Something<T> { } pub struct Whatever; diff --git a/tests/rustdoc/empty-impl-block-private-with-doc.rs b/tests/rustdoc/empty-impl-block-private-with-doc.rs index 43971996163..e6cff97b184 100644 --- a/tests/rustdoc/empty-impl-block-private-with-doc.rs +++ b/tests/rustdoc/empty-impl-block-private-with-doc.rs @@ -10,7 +10,7 @@ pub struct Foo; // There are 3 impl blocks with public item and one that should not be displayed // by default because it only contains private items (but not in this case because // we used `--document-private-items`). -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4 +// @count - '//*[@class="impl"]' 'impl Foo' 4 // Impl block only containing private items should not be displayed unless the // `--document-private-items` flag is used. diff --git a/tests/rustdoc/empty-impl-block-private.rs b/tests/rustdoc/empty-impl-block-private.rs index 5caf020658c..d44b4a47cee 100644 --- a/tests/rustdoc/empty-impl-block-private.rs +++ b/tests/rustdoc/empty-impl-block-private.rs @@ -7,7 +7,7 @@ pub struct Foo; // There are 3 impl blocks with public item and one that should not be displayed // because it only contains private items. -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3 +// @count - '//*[@class="impl"]' 'impl Foo' 3 // Impl block only containing private items should not be displayed. /// Private diff --git a/tests/rustdoc/empty-impl-block.rs b/tests/rustdoc/empty-impl-block.rs index 95d4db06b31..da780580bd0 100644 --- a/tests/rustdoc/empty-impl-block.rs +++ b/tests/rustdoc/empty-impl-block.rs @@ -8,7 +8,7 @@ pub struct Foo; /// Hello empty impl block! impl Foo {} // We ensure that this empty impl block without doc isn't rendered. -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1 +// @count - '//*[@class="impl"]' 'impl Foo' 1 impl Foo {} // Just to ensure that empty trait impl blocks are rendered. diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc/glob-shadowing.rs index 66a31c42bcf..2668b333497 100644 --- a/tests/rustdoc/glob-shadowing.rs +++ b/tests/rustdoc/glob-shadowing.rs @@ -1,5 +1,5 @@ // @has 'glob_shadowing/index.html' -// @count - '//div[@class="item-left module-item"]' 6 +// @count - '//div[@class="item-left"]' 6 // @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe' // @has - '//div[@class="item-right docblock-short"]' 'sub2::describe' diff --git a/tests/rustdoc/impl-parts.rs b/tests/rustdoc/impl-parts.rs index 90cbb77cb6b..f7738060e99 100644 --- a/tests/rustdoc/impl-parts.rs +++ b/tests/rustdoc/impl-parts.rs @@ -5,7 +5,7 @@ pub auto trait AnAutoTrait {} pub struct Foo<T> { field: T } -// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone," // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone," diff --git a/tests/rustdoc/inline_cross/issue-31948-1.rs b/tests/rustdoc/inline_cross/issue-31948-1.rs index 6e89167b3a4..571eaf6be96 100644 --- a/tests/rustdoc/inline_cross/issue-31948-1.rs +++ b/tests/rustdoc/inline_cross/issue-31948-1.rs @@ -5,8 +5,8 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_1/struct.Wobble.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/tests/rustdoc/inline_cross/issue-31948-2.rs b/tests/rustdoc/inline_cross/issue-31948-2.rs index 141e07656a0..7eae21046cc 100644 --- a/tests/rustdoc/inline_cross/issue-31948-2.rs +++ b/tests/rustdoc/inline_cross/issue-31948-2.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_2/struct.Wobble.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/tests/rustdoc/inline_cross/issue-31948.rs b/tests/rustdoc/inline_cross/issue-31948.rs index 96fc6ca47e7..9c271bf4ad4 100644 --- a/tests/rustdoc/inline_cross/issue-31948.rs +++ b/tests/rustdoc/inline_cross/issue-31948.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948/struct.Foo.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' -// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' +// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::Foo; diff --git a/tests/rustdoc/inline_cross/macros.rs b/tests/rustdoc/inline_cross/macros.rs index 5daa0d4baad..d5b0de5725b 100644 --- a/tests/rustdoc/inline_cross/macros.rs +++ b/tests/rustdoc/inline_cross/macros.rs @@ -6,9 +6,9 @@ extern crate macros; -// @has foo/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \ +// @has foo/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab deprecated"]' \ // Deprecated -// @has - '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \ +// @has - '//*[@class="item-left unstable deprecated"]/span[@class="stab unstable"]' \ // Experimental // @has foo/macro.my_macro.html diff --git a/tests/rustdoc/issue-107350.rs b/tests/rustdoc/issue-107350.rs new file mode 100644 index 00000000000..75f378ed249 --- /dev/null +++ b/tests/rustdoc/issue-107350.rs @@ -0,0 +1,18 @@ +// This is a regression test for <https://github.com/rust-lang/rust/issues/107350>. +// It shouldn't loop indefinitely. + +#![crate_name = "foo"] + +// @has 'foo/oops/enum.OhNo.html' + +pub mod oops { + pub use crate::oops::OhNo; + + mod inner { + pub enum OhNo { + Item = 1, + } + } + + pub use self::inner::*; +} diff --git a/tests/rustdoc/issue-21474.rs b/tests/rustdoc/issue-21474.rs index 43ce13fd9b1..5de26abace6 100644 --- a/tests/rustdoc/issue-21474.rs +++ b/tests/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ mod inner { pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 pub struct What; diff --git a/tests/rustdoc/issue-32374.rs b/tests/rustdoc/issue-32374.rs index 8d2c27cf3d7..8296d7a81f2 100644 --- a/tests/rustdoc/issue-32374.rs +++ b/tests/rustdoc/issue-32374.rs @@ -2,9 +2,9 @@ #![doc(issue_tracker_base_url = "https://issue_url/")] #![unstable(feature = "test", issue = "32374")] -// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \ +// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab deprecated"]' \ // 'Deprecated' -// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \ +// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab unstable"]' \ // 'Experimental' // @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs' diff --git a/tests/rustdoc/issue-33302.rs b/tests/rustdoc/issue-33302.rs index b4c52e2f17a..7af00c77836 100644 --- a/tests/rustdoc/issue-33302.rs +++ b/tests/rustdoc/issue-33302.rs @@ -22,7 +22,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // '//*[@class="impl"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]' // @has - '//*[@id="associatedconstant.D"]' 'const D: i32' impl T<[i32; ($n * $n)]> for S { @@ -30,7 +30,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // '//*[@class="impl"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)' // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32' impl T<(i32,)> for S { @@ -38,7 +38,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S' + // '//*[@class="impl"]' 'impl T<(i32, i32)> for S' // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)' // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32' impl T<(i32, i32)> for S { diff --git a/tests/rustdoc/issue-45584.rs b/tests/rustdoc/issue-45584.rs index 86479e6fb2e..8a5f0413826 100644 --- a/tests/rustdoc/issue-45584.rs +++ b/tests/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar<T, U> {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1" impl Bar<Foo1, &'static Foo1> for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/tests/rustdoc/issue-50159.rs b/tests/rustdoc/issue-50159.rs index 04bc4f304d6..13bedd5dbb0 100644 --- a/tests/rustdoc/issue-50159.rs +++ b/tests/rustdoc/issue-50159.rs @@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> { // @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send' // @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Switch<B: Signal> { pub inner: <B as Signal2>::Item2, } diff --git a/tests/rustdoc/issue-51236.rs b/tests/rustdoc/issue-51236.rs index 1c7aa9c7eef..04664805a88 100644 --- a/tests/rustdoc/issue-51236.rs +++ b/tests/rustdoc/issue-51236.rs @@ -7,7 +7,7 @@ pub mod traits { } // @has issue_51236/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send" pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>, diff --git a/tests/rustdoc/issue-53812.rs b/tests/rustdoc/issue-53812.rs index c68ffd52186..dc1eb304c3d 100644 --- a/tests/rustdoc/issue-53812.rs +++ b/tests/rustdoc/issue-53812.rs @@ -12,9 +12,9 @@ macro_rules! array_impls { } // @has issue_53812/trait.MyIterator.html -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][5]' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 } diff --git a/tests/rustdoc/issue-54705.rs b/tests/rustdoc/issue-54705.rs index 7b7290ab4b7..a886eb0de24 100644 --- a/tests/rustdoc/issue-54705.rs +++ b/tests/rustdoc/issue-54705.rs @@ -1,10 +1,10 @@ pub trait ScopeHandle<'scope> {} // @has issue_54705/struct.ScopeFutureContents.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, diff --git a/tests/rustdoc/issue-55321.rs b/tests/rustdoc/issue-55321.rs index 22a18ef90e1..d3c2070d915 100644 --- a/tests/rustdoc/issue-55321.rs +++ b/tests/rustdoc/issue-55321.rs @@ -1,9 +1,9 @@ #![feature(negative_impls)] // @has issue_55321/struct.A.html -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for A" -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Sync for A" pub struct A(); @@ -11,8 +11,8 @@ impl !Send for A {} impl !Sync for A {} // @has issue_55321/struct.B.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Send for B<T>" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Sync for B<T>" pub struct B<T: ?Sized>(A, Box<T>); diff --git a/tests/rustdoc/issue-55364.rs b/tests/rustdoc/issue-55364.rs index 14a6f5041f2..b987da30ed2 100644 --- a/tests/rustdoc/issue-55364.rs +++ b/tests/rustdoc/issue-55364.rs @@ -29,8 +29,8 @@ pub mod subone { // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo' // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar' // Though there should be such links later -// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' -// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' +// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' +// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' /// See either [foo] or [bar]. pub mod subtwo { diff --git a/tests/rustdoc/issue-56822.rs b/tests/rustdoc/issue-56822.rs index b4eef344b5f..c9a74335702 100644 --- a/tests/rustdoc/issue-56822.rs +++ b/tests/rustdoc/issue-56822.rs @@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> { } // @has issue_56822/struct.Parser.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'a> Send for Parser<'a>" pub struct Parser<'a> { field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output diff --git a/tests/rustdoc/issue-60726.rs b/tests/rustdoc/issue-60726.rs index fbb0f82ae39..e337e4a4f7a 100644 --- a/tests/rustdoc/issue-60726.rs +++ b/tests/rustdoc/issue-60726.rs @@ -26,9 +26,9 @@ where {} // @has issue_60726/struct.IntoIter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Send for IntoIter<T>" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Sync for IntoIter<T>" pub struct IntoIter<T>{ hello:DynTrait<FooInterface<T>>, diff --git a/tests/rustdoc/issue-76501.rs b/tests/rustdoc/issue-76501.rs index a90e0fea092..5caea0ec992 100644 --- a/tests/rustdoc/issue-76501.rs +++ b/tests/rustdoc/issue-76501.rs @@ -8,7 +8,7 @@ pub const fn bloop() -> i32 { pub struct Struct {} impl Struct { - // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \ + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' \ // 'pub const fn blurp() -> i32' /// A useless function that always returns 1. pub const fn blurp() -> i32 { diff --git a/tests/rustdoc/issue-78673.rs b/tests/rustdoc/issue-78673.rs index 2e4bec2544c..d09141c3204 100644 --- a/tests/rustdoc/issue-78673.rs +++ b/tests/rustdoc/issue-78673.rs @@ -7,8 +7,8 @@ pub trait AnAmazingTrait {} impl<T: Something> AnAmazingTrait for T {} // @has 'issue_78673/struct.MyStruct.html' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct' -// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct' +// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T' pub struct MyStruct; impl AnAmazingTrait for MyStruct {} @@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {} // generic structs may have _both_ specific and blanket impls that apply // @has 'issue_78673/struct.AnotherStruct.html' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for T' pub struct AnotherStruct<T>(T); impl<T: Something> Something for AnotherStruct<T> {} diff --git a/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs b/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs index d3a7a870b58..9bce25846d8 100644 --- a/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs +++ b/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs @@ -11,6 +11,6 @@ pub mod sub { #[doc(inline)] pub use sub::*; -// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1 +// @count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1 // @count foo/prelude/index.html '//div[@class="item-row"]' 0 pub mod prelude {} diff --git a/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs b/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs index b8369250993..d0960dfef43 100644 --- a/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs +++ b/tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs @@ -8,7 +8,7 @@ pub mod sub { } } -// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1 +// @count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1 // @count foo/prelude/index.html '//div[@class="item-row"]' 0 pub mod prelude {} diff --git a/tests/rustdoc/issue-95873.rs b/tests/rustdoc/issue-95873.rs index ff33fb63a0b..3df93eb7cf1 100644 --- a/tests/rustdoc/issue-95873.rs +++ b/tests/rustdoc/issue-95873.rs @@ -1,2 +1,2 @@ -// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;" +// @has issue_95873/index.html "//*[@class='item-left']" "pub use ::std as x;" pub use ::std as x; diff --git a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs index 41e64726a32..ba29a77ebdf 100644 --- a/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs +++ b/tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs @@ -9,6 +9,6 @@ extern crate issue_99221_aux; pub use issue_99221_aux::*; -// @count foo/index.html '//a[@class="struct"][@title="foo::Print struct"]' 1 +// @count foo/index.html '//a[@class="struct"][@title="struct foo::Print"]' 1 pub struct Print; diff --git a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs index 3208fea05b3..b56ec6e11ea 100644 --- a/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs +++ b/tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs @@ -9,7 +9,7 @@ extern crate issue_99734_aux; pub use issue_99734_aux::*; -// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1 +// @count foo/index.html '//a[@class="fn"][@title="fn foo::main"]' 1 extern "C" { pub fn main() -> std::ffi::c_int; diff --git a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs index b2f9b8b4657..8f5d6fa3d56 100644 --- a/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs +++ b/tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs @@ -9,6 +9,6 @@ extern crate issue_99734_aux; pub use issue_99734_aux::*; -// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1 +// @count foo/index.html '//a[@class="mod"][@title="mod foo::task"]' 1 pub mod task {} diff --git a/tests/rustdoc/mut-params.rs b/tests/rustdoc/mut-params.rs index 3b862e651c9..431db51d95f 100644 --- a/tests/rustdoc/mut-params.rs +++ b/tests/rustdoc/mut-params.rs @@ -5,7 +5,7 @@ pub struct Foo; -// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2 +// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut' impl Foo { pub fn foo(mut self) {} diff --git a/tests/rustdoc/negative-impl.rs b/tests/rustdoc/negative-impl.rs index af19c784d6d..51223af6737 100644 --- a/tests/rustdoc/negative-impl.rs +++ b/tests/rustdoc/negative-impl.rs @@ -5,10 +5,10 @@ pub struct Alpha; // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>" pub struct Bravo<B>(B); -// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for Alpha" impl !Send for Alpha {} -// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\ +// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//h3[@class="code-header"]' "\ // impl<B> !Send for Bravo<B>" impl<B> !Send for Bravo<B> {} diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc/playground-arg.rs index 69c89626539..f3811fe0b0a 100644 --- a/tests/rustdoc/playground-arg.rs +++ b/tests/rustdoc/playground-arg.rs @@ -10,4 +10,4 @@ pub fn dummy() {} // ensure that `extern crate foo;` was inserted into code snips automatically: -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run" diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs index 877ea1cfba1..5c7fa33efc5 100644 --- a/tests/rustdoc/playground.rs +++ b/tests/rustdoc/playground.rs @@ -22,6 +22,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run" -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run" diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive-reference.rs index c3a5eb6d324..10efbefd2b1 100644 --- a/tests/rustdoc/primitive-reference.rs +++ b/tests/rustdoc/primitive-reference.rs @@ -13,7 +13,7 @@ // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' // There should be only one implementation listed. -// @count - '//*[@class="impl has-srclink"]' 1 +// @count - '//*[@class="impl"]' 1 // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \ // 'impl<A, B> Foo<&A> for &B' #[doc(primitive = "reference")] diff --git a/tests/rustdoc/pub-method.rs b/tests/rustdoc/pub-method.rs index 0dca3f672cd..7115a01d079 100644 --- a/tests/rustdoc/pub-method.rs +++ b/tests/rustdoc/pub-method.rs @@ -10,8 +10,8 @@ pub fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method has-srclink"]' 'pub fn new()' -// @has - '//*[@class="method has-srclink"]' 'fn not_pub()' +// @has - '//*[@class="method"]' 'pub fn new()' +// @has - '//*[@class="method"]' 'fn not_pub()' pub struct Foo(usize); impl Foo { diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport-check.rs index db1f90c6999..acac0c99197 100644 --- a/tests/rustdoc/reexport-check.rs +++ b/tests/rustdoc/reexport-check.rs @@ -4,12 +4,12 @@ extern crate reexport_check; // @!has 'foo/index.html' '//code' 'pub use self::i32;' -// @has 'foo/index.html' '//div[@class="item-left deprecated module-item"]' 'i32' +// @has 'foo/index.html' '//div[@class="item-left deprecated"]' 'i32' // @has 'foo/i32/index.html' #[allow(deprecated, deprecated_in_future)] pub use std::i32; // @!has 'foo/index.html' '//code' 'pub use self::string::String;' -// @has 'foo/index.html' '//div[@class="item-left module-item"]' 'String' +// @has 'foo/index.html' '//div[@class="item-left"]' 'String' pub use std::string::String; // @has 'foo/index.html' '//div[@class="item-right docblock-short"]' 'Docs in original' diff --git a/tests/rustdoc/synthetic_auto/basic.rs b/tests/rustdoc/synthetic_auto/basic.rs index 7c6a388653c..043ac241488 100644 --- a/tests/rustdoc/synthetic_auto/basic.rs +++ b/tests/rustdoc/synthetic_auto/basic.rs @@ -1,8 +1,8 @@ // @has basic/struct.Foo.html // @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send' // @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync' -// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Foo<T> { field: T, } diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc/synthetic_auto/complex.rs index 43393c21fdd..4c39f0bf1e0 100644 --- a/tests/rustdoc/synthetic_auto/complex.rs +++ b/tests/rustdoc/synthetic_auto/complex.rs @@ -20,7 +20,7 @@ mod foo { } // @has complex/struct.NotOuter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static" diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc/synthetic_auto/lifetimes.rs index 33170a84435..71265b3078a 100644 --- a/tests/rustdoc/synthetic_auto/lifetimes.rs +++ b/tests/rustdoc/synthetic_auto/lifetimes.rs @@ -9,10 +9,10 @@ where {} // @has lifetimes/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Sync for Foo<'c, K>where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/tests/rustdoc/synthetic_auto/manual.rs b/tests/rustdoc/synthetic_auto/manual.rs index 77c04ad2ad9..7fc8447df3e 100644 --- a/tests/rustdoc/synthetic_auto/manual.rs +++ b/tests/rustdoc/synthetic_auto/manual.rs @@ -1,12 +1,12 @@ // @has manual/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Sync for Foo<T>where T: Sync' // -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Send for Foo<T>' // -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4 pub struct Foo<T> { field: T, } diff --git a/tests/rustdoc/synthetic_auto/negative.rs b/tests/rustdoc/synthetic_auto/negative.rs index 2c2c848a5e0..97da2d57424 100644 --- a/tests/rustdoc/synthetic_auto/negative.rs +++ b/tests/rustdoc/synthetic_auto/negative.rs @@ -3,10 +3,10 @@ pub struct Inner<T: Copy> { } // @has negative/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Send for Outer<T>" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> !Sync for Outer<T>" pub struct Outer<T: Copy> { inner_field: Inner<T>, diff --git a/tests/rustdoc/synthetic_auto/nested.rs b/tests/rustdoc/synthetic_auto/nested.rs index 423bf115ab1..e4aead71bf2 100644 --- a/tests/rustdoc/synthetic_auto/nested.rs +++ b/tests/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ where } // @has nested/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Send for Foo<T>where T: Copy' // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl<T> Sync for Foo<T>where T: Sync' pub struct Foo<T> { inner_field: Inner<T>, diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc/synthetic_auto/no-redundancy.rs index 59f33623322..ea57d7388b8 100644 --- a/tests/rustdoc/synthetic_auto/no-redundancy.rs +++ b/tests/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,7 +9,7 @@ where } // @has no_redundancy/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> Send for Outer<T>where T: Send + Copy" pub struct Outer<T> { inner_field: Inner<T>, diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc/synthetic_auto/project.rs index 558ff2add40..7c9412ae962 100644 --- a/tests/rustdoc/synthetic_auto/project.rs +++ b/tests/rustdoc/synthetic_auto/project.rs @@ -23,10 +23,10 @@ where } // @has project/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \ // 'c: 'static," pub struct Foo<'c, K: 'c> { diff --git a/tests/rustdoc/synthetic_auto/self-referential.rs b/tests/rustdoc/synthetic_auto/self-referential.rs index c6ae96de776..145a2b7e00c 100644 --- a/tests/rustdoc/synthetic_auto/self-referential.rs +++ b/tests/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> { // @has self_referential/struct.WriteAndThen.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<P1> Send for WriteAndThen<P1>where <P1 as Pattern>::Value: Send" pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value) where P1: Pattern; diff --git a/tests/rustdoc/synthetic_auto/static-region.rs b/tests/rustdoc/synthetic_auto/static-region.rs index 1a76cb919c2..9dc6211ec20 100644 --- a/tests/rustdoc/synthetic_auto/static-region.rs +++ b/tests/rustdoc/synthetic_auto/static-region.rs @@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> { } // @has static_region/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send" pub struct Owned<T> where T: OwnedTrait<'static> { marker: <T as OwnedTrait<'static>>::Reader, diff --git a/tests/rustdoc/typedef.rs b/tests/rustdoc/typedef.rs index d5dfa948489..63e2973c759 100644 --- a/tests/rustdoc/typedef.rs +++ b/tests/rustdoc/typedef.rs @@ -9,8 +9,8 @@ impl MyStruct { } // @has typedef/type.MyAlias.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyAlias' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias' // @hasraw - 'Alias docstring' // @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias' // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods' diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 3ac0c6872a8..644a0058244 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -13,7 +13,7 @@ pub fn charlie<C>() where C: MyTrait {} pub struct Delta<D>(D); -// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<D> Delta<D>where D: MyTrait" impl<D> Delta<D> where D: MyTrait { pub fn delta() {} @@ -43,7 +43,7 @@ pub trait TraitWhere { { todo!() } } -// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<E> MyTrait for Echo<E>where E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl<E> MyTrait for Echo<E>where E: MyTrait" @@ -51,7 +51,7 @@ impl<E> MyTrait for Echo<E>where E: MyTrait {} pub enum Foxtrot<F> { Foxtrot1(F) } -// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/enum.Foxtrot.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<F> MyTrait for Foxtrot<F>where F: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl<F> MyTrait for Foxtrot<F>where F: MyTrait" diff --git a/tests/rustdoc/whitespace-after-where-clause.enum.html b/tests/rustdoc/whitespace-after-where-clause.enum.html index 20bde549a03..eeb22878f3c 100644 --- a/tests/rustdoc/whitespace-after-where-clause.enum.html +++ b/tests/rustdoc/whitespace-after-where-clause.enum.html @@ -1,4 +1,4 @@ <div class="item-decl"><pre class="rust"><code>pub enum Cow<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{ - Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B), + Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>), Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), }</code></pre></div> \ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.enum2.html b/tests/rustdoc/whitespace-after-where-clause.enum2.html index d9fc0c22309..c8037c2a8df 100644 --- a/tests/rustdoc/whitespace-after-where-clause.enum2.html +++ b/tests/rustdoc/whitespace-after-where-clause.enum2.html @@ -1,4 +1,4 @@ <div class="item-decl"><pre class="rust"><code>pub enum Cow2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { - Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B), + Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>), Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), }</code></pre></div> \ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.struct.html b/tests/rustdoc/whitespace-after-where-clause.struct.html index f375265d7c1..5892270b2f9 100644 --- a/tests/rustdoc/whitespace-after-where-clause.struct.html +++ b/tests/rustdoc/whitespace-after-where-clause.struct.html @@ -1,4 +1,4 @@ <div class="item-decl"><pre class="rust"><code>pub struct Struct<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{ - pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B, + pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>, pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, }</code></pre></div> \ No newline at end of file diff --git a/tests/rustdoc/whitespace-after-where-clause.struct2.html b/tests/rustdoc/whitespace-after-where-clause.struct2.html index 1c59962eb1c..d3952b0c566 100644 --- a/tests/rustdoc/whitespace-after-where-clause.struct2.html +++ b/tests/rustdoc/whitespace-after-where-clause.struct2.html @@ -1,4 +1,4 @@ <div class="item-decl"><pre class="rust"><code>pub struct Struct2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { - pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B, + pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>, pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, }</code></pre></div> \ No newline at end of file diff --git a/tests/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/tests/ui-fulldeps/auxiliary/issue-40001-plugin.rs index c05443488c3..3f6caecaa5a 100644 --- a/tests/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/tests/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -16,6 +16,7 @@ use rustc_hir as hir; use rustc_hir::intravisit; use rustc_hir::Node; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map; #[no_mangle] @@ -40,8 +41,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingAllowedAttrPass { _: &'tcx hir::FnDecl, _: &'tcx hir::Body, span: source_map::Span, - id: hir::HirId, + def_id: LocalDefId, ) { + let id = cx.tcx.hir().local_def_id_to_hir_id(def_id); let item = match cx.tcx.hir().get(id) { Node::Item(item) => item, _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).def_id), diff --git a/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr b/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr index 4299688221a..47897dc003a 100644 --- a/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr +++ b/tests/ui-fulldeps/dropck-tarena-cycle-checked.stderr @@ -1,6 +1,8 @@ error[E0597]: `arena` does not live long enough --> $DIR/dropck-tarena-cycle-checked.rs:116:7 | +LL | let arena = TypedArena::default(); + | ----- binding `arena` declared here LL | f(&arena); | ^^^^^^ borrowed value does not live long enough LL | } diff --git a/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr b/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr index ccffee9cdbd..493d74b0bde 100644 --- a/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr +++ b/tests/ui-fulldeps/dropck-tarena-unsound-drop.stderr @@ -1,6 +1,8 @@ error[E0597]: `arena` does not live long enough --> $DIR/dropck-tarena-unsound-drop.rs:41:7 | +LL | let arena: TypedArena<C> = TypedArena::default(); + | ----- binding `arena` declared here LL | f(&arena); | ^^^^^^ borrowed value does not live long enough LL | } diff --git a/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl b/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl new file mode 100644 index 00000000000..0cd8229b230 --- /dev/null +++ b/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl @@ -0,0 +1 @@ +missing_message_ref = {message} diff --git a/tests/ui-fulldeps/fluent-messages/test.rs b/tests/ui-fulldeps/fluent-messages/test.rs index 4e8147e2b76..74303e97dba 100644 --- a/tests/ui-fulldeps/fluent-messages/test.rs +++ b/tests/ui-fulldeps/fluent-messages/test.rs @@ -96,3 +96,12 @@ mod missing_crate_name { use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, test_crate_foo, with_hyphens}; } + +mod missing_message_ref { + use super::fluent_messages; + + fluent_messages! { + missing => "./missing-message-ref.ftl" +//~^ ERROR referenced message `message` does not exist + } +} diff --git a/tests/ui-fulldeps/fluent-messages/test.stderr b/tests/ui-fulldeps/fluent-messages/test.stderr index d1cd4fe26da..2631b0a6232 100644 --- a/tests/ui-fulldeps/fluent-messages/test.stderr +++ b/tests/ui-fulldeps/fluent-messages/test.stderr @@ -93,6 +93,14 @@ LL | test_crate => "./missing-crate-name.ftl", | = help: replace any '-'s with '_'s -error: aborting due to 10 previous errors +error: referenced message `message` does not exist (in message `missing_message_ref`) + --> $DIR/test.rs:104:20 + | +LL | missing => "./missing-message-ref.ftl" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: you may have meant to use a variable reference (`{$message}`) + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs index 3f7429a5fcc..bf655510a5a 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -31,6 +31,7 @@ fn main() { TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Generator(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::GeneratorWitnessMIR(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Alias(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 1f49d6b6464..9f8c0bea0ee 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -121,59 +121,65 @@ LL | TyKind::GeneratorWitness(..) => (), error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:34:9 | -LL | TyKind::Never => (), +LL | TyKind::GeneratorWitnessMIR(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:35:9 | -LL | TyKind::Tuple(..) => (), +LL | TyKind::Never => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:36:9 | -LL | TyKind::Alias(..) => (), +LL | TyKind::Tuple(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:37:9 | -LL | TyKind::Param(..) => (), +LL | TyKind::Alias(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:38:9 | -LL | TyKind::Bound(..) => (), +LL | TyKind::Param(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:39:9 | -LL | TyKind::Placeholder(..) => (), +LL | TyKind::Bound(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:40:9 | -LL | TyKind::Infer(..) => (), +LL | TyKind::Placeholder(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:41:9 | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using `ty::<kind>` directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:42:9 + | LL | TyKind::Error(_) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` - --> $DIR/ty_tykind_usage.rs:46:12 + --> $DIR/ty_tykind_usage.rs:47:12 | LL | if let TyKind::Int(int_ty) = kind {} | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:48:24 + --> $DIR/ty_tykind_usage.rs:49:24 | LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} | ^^^^^^^^^^ @@ -181,7 +187,7 @@ LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:50:37 + --> $DIR/ty_tykind_usage.rs:51:37 | LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { | ^^^^^^^^^^^ @@ -189,7 +195,7 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:50:53 + --> $DIR/ty_tykind_usage.rs:51:53 | LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { | ^^^^^^^^^^^ @@ -197,12 +203,12 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { = help: try using `Ty` instead error: usage of `ty::TyKind::<kind>` - --> $DIR/ty_tykind_usage.rs:53:9 + --> $DIR/ty_tykind_usage.rs:54:9 | LL | IrTyKind::Bool | --------^^^^^^ | | | help: try using `ty::<kind>` directly: `ty` -error: aborting due to 32 previous errors +error: aborting due to 33 previous errors diff --git a/tests/ui/asm/type-check-4.stderr b/tests/ui/asm/type-check-4.stderr index c97cd171b1e..b5ecb3e1b56 100644 --- a/tests/ui/asm/type-check-4.stderr +++ b/tests/ui/asm/type-check-4.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `a` because it is borrowed --> $DIR/type-check-4.rs:14:9 | LL | let p = &a; - | -- borrow of `a` occurs here + | -- `a` is borrowed here LL | asm!("{}", out(reg) a); - | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ `a` is assigned to here but it was already borrowed LL | LL | println!("{}", p); | - borrow later used here @@ -13,7 +13,7 @@ error[E0503]: cannot use `a` because it was mutably borrowed --> $DIR/type-check-4.rs:22:28 | LL | let p = &mut a; - | ------ borrow of `a` occurs here + | ------ `a` is borrowed here LL | asm!("{}", in(reg) a); | ^ use of borrowed `a` LL | diff --git a/tests/ui/associated-types/associated-types-outlives.stderr b/tests/ui/associated-types/associated-types-outlives.stderr index 840e33b4b8a..2fe3f2d4a02 100644 --- a/tests/ui/associated-types/associated-types-outlives.stderr +++ b/tests/ui/associated-types/associated-types-outlives.stderr @@ -1,6 +1,9 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/associated-types-outlives.rs:22:14 | +LL | F: for<'a> FnOnce(<T as Foo<'a>>::Bar)>(x: T, f: F) { + | - binding `x` declared here +... LL | 's: loop { y = denormalise(&x); break } | -- borrow of `x` occurs here LL | drop(x); diff --git a/tests/ui/associated-types/defaults-in-other-trait-items.rs b/tests/ui/associated-types/defaults-in-other-trait-items.rs index 505751969b6..f263809552f 100644 --- a/tests/ui/associated-types/defaults-in-other-trait-items.rs +++ b/tests/ui/associated-types/defaults-in-other-trait-items.rs @@ -44,4 +44,18 @@ impl AssocConst for () { const C: Self::Ty = 0u8; } +pub trait Trait { + type Res = isize; //~ NOTE associated type defaults can't be assumed inside the trait defining them + + fn infer_me_correctly() -> Self::Res { + //~^ NOTE expected `<Self as Trait>::Res` because of return type + + // {integer} == isize + 2 + //~^ ERROR mismatched types + //~| NOTE expected associated type, found integer + //~| NOTE expected associated type `<Self as Trait>::Res` + } +} + fn main() {} diff --git a/tests/ui/associated-types/defaults-in-other-trait-items.stderr b/tests/ui/associated-types/defaults-in-other-trait-items.stderr index 71d421926e7..bdcfadd3955 100644 --- a/tests/ui/associated-types/defaults-in-other-trait-items.stderr +++ b/tests/ui/associated-types/defaults-in-other-trait-items.stderr @@ -24,6 +24,21 @@ LL | const C: Self::Ty = 0u8; = note: expected associated type `<Self as AssocConst>::Ty` found type `u8` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/defaults-in-other-trait-items.rs:54:9 + | +LL | type Res = isize; + | ----------------- associated type defaults can't be assumed inside the trait defining them +LL | +LL | fn infer_me_correctly() -> Self::Res { + | --------- expected `<Self as Trait>::Res` because of return type +... +LL | 2 + | ^ expected associated type, found integer + | + = note: expected associated type `<Self as Trait>::Res` + found type `{integer}` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-types/issue-26681.stderr b/tests/ui/associated-types/issue-26681.stderr index 74411008c9d..977620d9052 100644 --- a/tests/ui/associated-types/issue-26681.stderr +++ b/tests/ui/associated-types/issue-26681.stderr @@ -1,13 +1,13 @@ error[E0308]: mismatched types --> $DIR/issue-26681.rs:17:39 | +LL | type Fv: Foo = u8; + | ------------------ associated type defaults can't be assumed inside the trait defining them LL | const C: <Self::Fv as Foo>::Bar = 6665; | ^^^^ expected associated type, found integer | = note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar` found type `{integer}` - = help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to previous error diff --git a/tests/ui/async-await/async-await-let-else.drop_tracking.stderr b/tests/ui/async-await/async-await-let-else.drop_tracking.stderr new file mode 100644 index 00000000000..fb83ca90a37 --- /dev/null +++ b/tests/ui/async-await/async-await-let-else.drop_tracking.stderr @@ -0,0 +1,106 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:48:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:11:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error[E0277]: `Rc<()>` cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:50:13 + | +LL | async fn foo2(x: Option<bool>) { + | - within this `impl Future<Output = ()>` +... +LL | is_send(foo2(Some(true))); + | ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: required because it's used within this `async fn` body + --> $DIR/async-await-let-else.rs:27:29 + | +LL | async fn bar2<T>(_: T) -> ! { + | _____________________________^ +LL | | panic!() +LL | | } + | |_^ + = note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()` +note: required because it's used within this `async fn` body + --> $DIR/async-await-let-else.rs:21:32 + | +LL | async fn foo2(x: Option<bool>) { + | ________________________________^ +LL | | let Some(_) = x else { +LL | | bar2(Rc::new(())).await +LL | | }; +LL | | } + | |_^ +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:52:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:33:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ - `Rc::new(())` is later dropped here + | | | + | | await occurs here, with `Rc::new(())` maybe used later + | has type `Rc<()>` which is not `Send` +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:54:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:41:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +... +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-await-let-else.drop_tracking_mir.stderr b/tests/ui/async-await/async-await-let-else.drop_tracking_mir.stderr new file mode 100644 index 00000000000..c284bbfb1cc --- /dev/null +++ b/tests/ui/async-await/async-await-let-else.drop_tracking_mir.stderr @@ -0,0 +1,100 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:48:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:11:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error[E0277]: `Rc<()>` cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:50:13 + | +LL | async fn foo2(x: Option<bool>) { + | - within this `impl Future<Output = ()>` +... +LL | is_send(foo2(Some(true))); + | ------- ^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: required because it's used within this `async fn` body + --> $DIR/async-await-let-else.rs:27:29 + | +LL | async fn bar2<T>(_: T) -> ! { + | _____________________________^ +LL | | panic!() +LL | | } + | |_^ + = note: required because it captures the following types: `impl Future<Output = !>` +note: required because it's used within this `async fn` body + --> $DIR/async-await-let-else.rs:21:32 + | +LL | async fn foo2(x: Option<bool>) { + | ________________________________^ +LL | | let Some(_) = x else { +LL | | bar2(Rc::new(())).await +LL | | }; +LL | | } + | |_^ +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:52:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:33:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:54:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:41:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-await-let-else.no_drop_tracking.stderr b/tests/ui/async-await/async-await-let-else.no_drop_tracking.stderr new file mode 100644 index 00000000000..d3c5e80a30d --- /dev/null +++ b/tests/ui/async-await/async-await-let-else.no_drop_tracking.stderr @@ -0,0 +1,90 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:48:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:11:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:50:13 + | +LL | is_send(foo2(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:23:26 + | +LL | bar2(Rc::new(())).await + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +LL | }; + | - `Rc::new(())` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:52:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:33:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ - `Rc::new(())` is later dropped here + | | | + | | await occurs here, with `Rc::new(())` maybe used later + | has type `Rc<()>` which is not `Send` +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:54:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:41:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +... +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:19:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/async-await/async-await-let-else.rs b/tests/ui/async-await/async-await-let-else.rs index 3fb2142b9e5..113d576b5e7 100644 --- a/tests/ui/async-await/async-await-let-else.rs +++ b/tests/ui/async-await/async-await-let-else.rs @@ -1,7 +1,7 @@ // edition:2021 -// revisions: drop-tracking no-drop-tracking -// [drop-tracking] compile-flags: -Zdrop-tracking=yes -// [no-drop-tracking] compile-flags: -Zdrop-tracking=no +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir use std::rc::Rc; diff --git a/tests/ui/async-await/async-error-span.stderr b/tests/ui/async-await/async-error-span.drop_tracking.stderr index 7d4447b6d55..c6257cb324d 100644 --- a/tests/ui/async-await/async-error-span.stderr +++ b/tests/ui/async-await/async-error-span.drop_tracking.stderr @@ -1,5 +1,5 @@ error[E0277]: `()` is not a future - --> $DIR/async-error-span.rs:7:20 + --> $DIR/async-error-span.rs:10:20 | LL | fn get_future() -> impl Future<Output = ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future @@ -8,13 +8,13 @@ LL | fn get_future() -> impl Future<Output = ()> { = note: () must be a future or must implement `IntoFuture` to be awaited error[E0698]: type inside `async fn` body must be known in this context - --> $DIR/async-error-span.rs:13:9 + --> $DIR/async-error-span.rs:16:9 | LL | let a; | ^ cannot infer type | note: the type is part of the `async fn` body because of this `await` - --> $DIR/async-error-span.rs:14:17 + --> $DIR/async-error-span.rs:19:17 | LL | get_future().await; | ^^^^^^ diff --git a/tests/ui/async-await/async-error-span.drop_tracking_mir.stderr b/tests/ui/async-await/async-error-span.drop_tracking_mir.stderr new file mode 100644 index 00000000000..2f29ee6cdb0 --- /dev/null +++ b/tests/ui/async-await/async-error-span.drop_tracking_mir.stderr @@ -0,0 +1,24 @@ +error[E0277]: `()` is not a future + --> $DIR/async-error-span.rs:10:20 + | +LL | fn get_future() -> impl Future<Output = ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + +error[E0282]: type annotations needed + --> $DIR/async-error-span.rs:16:9 + | +LL | let a; + | ^ + | +help: consider giving `a` an explicit type + | +LL | let a: /* Type */; + | ++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0282. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-error-span.no_drop_tracking.stderr b/tests/ui/async-await/async-error-span.no_drop_tracking.stderr new file mode 100644 index 00000000000..c6257cb324d --- /dev/null +++ b/tests/ui/async-await/async-error-span.no_drop_tracking.stderr @@ -0,0 +1,25 @@ +error[E0277]: `()` is not a future + --> $DIR/async-error-span.rs:10:20 + | +LL | fn get_future() -> impl Future<Output = ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future + | + = help: the trait `Future` is not implemented for `()` + = note: () must be a future or must implement `IntoFuture` to be awaited + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/async-error-span.rs:16:9 + | +LL | let a; + | ^ cannot infer type + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/async-error-span.rs:19:17 + | +LL | get_future().await; + | ^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0698. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-error-span.rs b/tests/ui/async-await/async-error-span.rs index 86d459bf084..c9ecf359e3d 100644 --- a/tests/ui/async-await/async-error-span.rs +++ b/tests/ui/async-await/async-error-span.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 // Regression test for issue #62382. @@ -10,7 +13,9 @@ fn get_future() -> impl Future<Output = ()> { } async fn foo() { - let a; //~ ERROR type inside `async fn` body must be known in this context + let a; + //[no_drop_tracking,drop_tracking]~^ ERROR type inside `async fn` body must be known in this context + //[drop_tracking_mir]~^^ ERROR type annotations needed get_future().await; } diff --git a/tests/ui/async-await/async-fn-nonsend.drop_tracking.stderr b/tests/ui/async-await/async-fn-nonsend.drop_tracking.stderr new file mode 100644 index 00000000000..0f0dc335e7f --- /dev/null +++ b/tests/ui/async-await/async-fn-nonsend.drop_tracking.stderr @@ -0,0 +1,49 @@ +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:72:17 + | +LL | assert_send(non_send_temporary_in_match()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:36:25 + | +LL | match Some(non_send()) { + | ---------------- has type `Option<impl Debug>` which is not `Send` +LL | Some(_) => fut().await, + | ^^^^^^ await occurs here, with `Some(non_send())` maybe used later +... +LL | } + | - `Some(non_send())` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:74:17 + | +LL | assert_send(non_sync_with_method_call()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:49:14 + | +LL | let f: &mut std::fmt::Formatter = &mut get_formatter(); + | --------------- has type `Formatter<'_>` which is not `Send` +... +LL | fut().await; + | ^^^^^^ await occurs here, with `get_formatter()` maybe used later +LL | } +LL | } + | - `get_formatter()` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/async-fn-nonsend.drop_tracking_mir.stderr b/tests/ui/async-await/async-fn-nonsend.drop_tracking_mir.stderr new file mode 100644 index 00000000000..57a01280145 --- /dev/null +++ b/tests/ui/async-await/async-fn-nonsend.drop_tracking_mir.stderr @@ -0,0 +1,43 @@ +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:72:17 + | +LL | assert_send(non_send_temporary_in_match()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:36:25 + | +LL | match Some(non_send()) { + | ---------------- has type `Option<impl Debug>` which is not `Send` +LL | Some(_) => fut().await, + | ^^^^^^ await occurs here, with `Some(non_send())` maybe used later +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:74:17 + | +LL | assert_send(non_sync_with_method_call()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:49:14 + | +LL | let f: &mut std::fmt::Formatter = &mut get_formatter(); + | --------------- has type `Formatter<'_>` which is not `Send` +... +LL | fut().await; + | ^^^^^^ await occurs here, with `get_formatter()` maybe used later +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/async-await/async-fn-nonsend.no_drop_tracking.stderr b/tests/ui/async-await/async-fn-nonsend.no_drop_tracking.stderr new file mode 100644 index 00000000000..5cec21d890e --- /dev/null +++ b/tests/ui/async-await/async-fn-nonsend.no_drop_tracking.stderr @@ -0,0 +1,120 @@ +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:70:17 + | +LL | assert_send(local_dropped_before_await()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:27:10 + | +LL | let x = non_send(); + | - has type `impl Debug` which is not `Send` +LL | drop(x); +LL | fut().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:72:17 + | +LL | assert_send(non_send_temporary_in_match()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:36:25 + | +LL | match Some(non_send()) { + | ---------- has type `impl Debug` which is not `Send` +LL | Some(_) => fut().await, + | ^^^^^^ await occurs here, with `non_send()` maybe used later +... +LL | } + | - `non_send()` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:74:17 + | +LL | assert_send(non_sync_with_method_call()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:49:14 + | +LL | let f: &mut std::fmt::Formatter = &mut get_formatter(); + | --------------- has type `Formatter<'_>` which is not `Send` +... +LL | fut().await; + | ^^^^^^ await occurs here, with `get_formatter()` maybe used later +LL | } +LL | } + | - `get_formatter()` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:76:17 + | +LL | assert_send(non_sync_with_method_call_panic()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call_panic` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:56:14 + | +LL | let f: &mut std::fmt::Formatter = panic!(); + | - has type `&mut Formatter<'_>` which is not `Send` +LL | if non_sync().fmt(f).unwrap() == () { +LL | fut().await; + | ^^^^^^ await occurs here, with `f` maybe used later +LL | } +LL | } + | - `f` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: future cannot be sent between threads safely + --> $DIR/async-fn-nonsend.rs:78:17 + | +LL | assert_send(non_sync_with_method_call_infinite_loop()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call_infinite_loop` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` +note: future is not `Send` as this value is used across an await + --> $DIR/async-fn-nonsend.rs:63:14 + | +LL | let f: &mut std::fmt::Formatter = loop {}; + | - has type `&mut Formatter<'_>` which is not `Send` +LL | if non_sync().fmt(f).unwrap() == () { +LL | fut().await; + | ^^^^^^ await occurs here, with `f` maybe used later +LL | } +LL | } + | - `f` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/async-fn-nonsend.rs:67:24 + | +LL | fn assert_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/async-await/async-fn-nonsend.rs b/tests/ui/async-await/async-fn-nonsend.rs index d7f8d7ac546..ed440bd0182 100644 --- a/tests/ui/async-await/async-fn-nonsend.rs +++ b/tests/ui/async-await/async-fn-nonsend.rs @@ -1,5 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 -// compile-flags: --crate-type lib -Zdrop-tracking +// compile-flags: --crate-type lib use std::{cell::RefCell, fmt::Debug, rc::Rc}; @@ -65,10 +68,13 @@ fn assert_send(_: impl Send) {} pub fn pass_assert() { assert_send(local_dropped_before_await()); + //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely assert_send(non_send_temporary_in_match()); //~^ ERROR future cannot be sent between threads safely assert_send(non_sync_with_method_call()); //~^ ERROR future cannot be sent between threads safely assert_send(non_sync_with_method_call_panic()); + //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely assert_send(non_sync_with_method_call_infinite_loop()); + //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely } diff --git a/tests/ui/async-await/async-fn-nonsend.stderr b/tests/ui/async-await/async-fn-nonsend.stderr index a7b872fe444..0f0dc335e7f 100644 --- a/tests/ui/async-await/async-fn-nonsend.stderr +++ b/tests/ui/async-await/async-fn-nonsend.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:68:17 + --> $DIR/async-fn-nonsend.rs:72:17 | LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await - --> $DIR/async-fn-nonsend.rs:33:25 + --> $DIR/async-fn-nonsend.rs:36:25 | LL | match Some(non_send()) { | ---------------- has type `Option<impl Debug>` which is not `Send` @@ -16,20 +16,20 @@ LL | Some(_) => fut().await, LL | } | - `Some(non_send())` is later dropped here note: required by a bound in `assert_send` - --> $DIR/async-fn-nonsend.rs:64:24 + --> $DIR/async-fn-nonsend.rs:67:24 | LL | fn assert_send(_: impl Send) {} | ^^^^ required by this bound in `assert_send` error: future cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:70:17 + --> $DIR/async-fn-nonsend.rs:74:17 | LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write` note: future is not `Send` as this value is used across an await - --> $DIR/async-fn-nonsend.rs:46:14 + --> $DIR/async-fn-nonsend.rs:49:14 | LL | let f: &mut std::fmt::Formatter = &mut get_formatter(); | --------------- has type `Formatter<'_>` which is not `Send` @@ -40,7 +40,7 @@ LL | } LL | } | - `get_formatter()` is later dropped here note: required by a bound in `assert_send` - --> $DIR/async-fn-nonsend.rs:64:24 + --> $DIR/async-fn-nonsend.rs:67:24 | LL | fn assert_send(_: impl Send) {} | ^^^^ required by this bound in `assert_send` diff --git a/tests/ui/async-await/default-struct-update.rs b/tests/ui/async-await/default-struct-update.rs index 64fb6280dd7..daee8469a14 100644 --- a/tests/ui/async-await/default-struct-update.rs +++ b/tests/ui/async-await/default-struct-update.rs @@ -1,6 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // build-pass // edition:2018 -// compile-flags: -Zdrop-tracking=y fn main() { let _ = foo(); diff --git a/tests/ui/async-await/drop-and-assign.rs b/tests/ui/async-await/drop-and-assign.rs index fa3f3303677..e520dfbdcce 100644 --- a/tests/ui/async-await/drop-and-assign.rs +++ b/tests/ui/async-await/drop-and-assign.rs @@ -1,5 +1,7 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2021 -// compile-flags: -Zdrop-tracking // build-pass struct A; diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking.stderr index d95483c8119..e2bba812d05 100644 --- a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/drop-track-field-assign-nonsend.rs:43:17 + --> $DIR/drop-track-field-assign-nonsend.rs:45:17 | LL | assert_send(agent.handle()); | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` note: future is not `Send` as this value is used across an await - --> $DIR/drop-track-field-assign-nonsend.rs:21:38 + --> $DIR/drop-track-field-assign-nonsend.rs:23:38 | LL | let mut info = self.info_result.clone(); | -------- has type `InfoResult` which is not `Send` @@ -16,7 +16,7 @@ LL | let _ = send_element(element).await; LL | } | - `mut info` is later dropped here note: required by a bound in `assert_send` - --> $DIR/drop-track-field-assign-nonsend.rs:38:19 + --> $DIR/drop-track-field-assign-nonsend.rs:40:19 | LL | fn assert_send<T: Send>(_: T) {} | ^^^^ required by this bound in `assert_send` diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking_mir.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking_mir.stderr new file mode 100644 index 00000000000..b89d8680407 --- /dev/null +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.drop_tracking_mir.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/drop-track-field-assign-nonsend.rs:45:17 + | +LL | assert_send(agent.handle()); + | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` +note: future is not `Send` as this value is used across an await + --> $DIR/drop-track-field-assign-nonsend.rs:23:38 + | +LL | let mut info = self.info_result.clone(); + | -------- has type `InfoResult` which is not `Send` +... +LL | let _ = send_element(element).await; + | ^^^^^^ await occurs here, with `mut info` maybe used later +note: required by a bound in `assert_send` + --> $DIR/drop-track-field-assign-nonsend.rs:40:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.no_drop_tracking.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.no_drop_tracking.stderr new file mode 100644 index 00000000000..e2bba812d05 --- /dev/null +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.no_drop_tracking.stderr @@ -0,0 +1,25 @@ +error: future cannot be sent between threads safely + --> $DIR/drop-track-field-assign-nonsend.rs:45:17 + | +LL | assert_send(agent.handle()); + | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` +note: future is not `Send` as this value is used across an await + --> $DIR/drop-track-field-assign-nonsend.rs:23:38 + | +LL | let mut info = self.info_result.clone(); + | -------- has type `InfoResult` which is not `Send` +... +LL | let _ = send_element(element).await; + | ^^^^^^ await occurs here, with `mut info` maybe used later +LL | } + | - `mut info` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/drop-track-field-assign-nonsend.rs:40:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.rs b/tests/ui/async-await/drop-track-field-assign-nonsend.rs index b6c0fda1521..3e22280008f 100644 --- a/tests/ui/async-await/drop-track-field-assign-nonsend.rs +++ b/tests/ui/async-await/drop-track-field-assign-nonsend.rs @@ -1,6 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // Derived from an ICE found in tokio-xmpp during a crater run. // edition:2021 -// compile-flags: -Zdrop-tracking #![allow(dead_code)] diff --git a/tests/ui/async-await/drop-track-field-assign.rs b/tests/ui/async-await/drop-track-field-assign.rs index 3a393cd164b..dd0e3f11ccc 100644 --- a/tests/ui/async-await/drop-track-field-assign.rs +++ b/tests/ui/async-await/drop-track-field-assign.rs @@ -1,6 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // Derived from an ICE found in tokio-xmpp during a crater run. // edition:2021 -// compile-flags: -Zdrop-tracking // build-pass #![allow(dead_code)] diff --git a/tests/ui/async-await/field-assign-nonsend.drop_tracking.stderr b/tests/ui/async-await/field-assign-nonsend.drop_tracking.stderr new file mode 100644 index 00000000000..ac461a671a8 --- /dev/null +++ b/tests/ui/async-await/field-assign-nonsend.drop_tracking.stderr @@ -0,0 +1,25 @@ +error: future cannot be sent between threads safely + --> $DIR/field-assign-nonsend.rs:45:17 + | +LL | assert_send(agent.handle()); + | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` +note: future is not `Send` as this value is used across an await + --> $DIR/field-assign-nonsend.rs:23:38 + | +LL | let mut info = self.info_result.clone(); + | -------- has type `InfoResult` which is not `Send` +... +LL | let _ = send_element(element).await; + | ^^^^^^ await occurs here, with `mut info` maybe used later +LL | } + | - `mut info` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/field-assign-nonsend.rs:40:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/field-assign-nonsend.drop_tracking_mir.stderr b/tests/ui/async-await/field-assign-nonsend.drop_tracking_mir.stderr new file mode 100644 index 00000000000..8c9d14d624c --- /dev/null +++ b/tests/ui/async-await/field-assign-nonsend.drop_tracking_mir.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/field-assign-nonsend.rs:45:17 + | +LL | assert_send(agent.handle()); + | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` +note: future is not `Send` as this value is used across an await + --> $DIR/field-assign-nonsend.rs:23:38 + | +LL | let mut info = self.info_result.clone(); + | -------- has type `InfoResult` which is not `Send` +... +LL | let _ = send_element(element).await; + | ^^^^^^ await occurs here, with `mut info` maybe used later +note: required by a bound in `assert_send` + --> $DIR/field-assign-nonsend.rs:40:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/field-assign-nonsend.no_drop_tracking.stderr b/tests/ui/async-await/field-assign-nonsend.no_drop_tracking.stderr new file mode 100644 index 00000000000..ac461a671a8 --- /dev/null +++ b/tests/ui/async-await/field-assign-nonsend.no_drop_tracking.stderr @@ -0,0 +1,25 @@ +error: future cannot be sent between threads safely + --> $DIR/field-assign-nonsend.rs:45:17 + | +LL | assert_send(agent.handle()); + | ^^^^^^^^^^^^^^ future returned by `handle` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>` +note: future is not `Send` as this value is used across an await + --> $DIR/field-assign-nonsend.rs:23:38 + | +LL | let mut info = self.info_result.clone(); + | -------- has type `InfoResult` which is not `Send` +... +LL | let _ = send_element(element).await; + | ^^^^^^ await occurs here, with `mut info` maybe used later +LL | } + | - `mut info` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/field-assign-nonsend.rs:40:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/field-assign-nonsend.rs b/tests/ui/async-await/field-assign-nonsend.rs new file mode 100644 index 00000000000..3e22280008f --- /dev/null +++ b/tests/ui/async-await/field-assign-nonsend.rs @@ -0,0 +1,47 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// Derived from an ICE found in tokio-xmpp during a crater run. +// edition:2021 + +#![allow(dead_code)] + +#[derive(Clone)] +struct InfoResult { + node: Option<std::rc::Rc<String>> +} + +struct Agent { + info_result: InfoResult +} + +impl Agent { + async fn handle(&mut self) { + let mut info = self.info_result.clone(); + info.node = None; + let element = parse_info(info); + let _ = send_element(element).await; + } +} + +struct Element { +} + +async fn send_element(_: Element) {} + +fn parse(_: &[u8]) -> Result<(), ()> { + Ok(()) +} + +fn parse_info(_: InfoResult) -> Element { + Element { } +} + +fn assert_send<T: Send>(_: T) {} + +fn main() { + let agent = Agent { info_result: InfoResult { node: None } }; + // FIXME: It would be nice for this to work. See #94067. + assert_send(agent.handle()); + //~^ cannot be sent between threads safely +} diff --git a/tests/ui/async-await/field-assign.rs b/tests/ui/async-await/field-assign.rs new file mode 100644 index 00000000000..dd0e3f11ccc --- /dev/null +++ b/tests/ui/async-await/field-assign.rs @@ -0,0 +1,46 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// Derived from an ICE found in tokio-xmpp during a crater run. +// edition:2021 +// build-pass + +#![allow(dead_code)] + +#[derive(Clone)] +struct InfoResult { + node: Option<String> +} + +struct Agent { + info_result: InfoResult +} + +impl Agent { + async fn handle(&mut self) { + let mut info = self.info_result.clone(); + info.node = Some("bar".into()); + let element = parse_info(info); + let _ = send_element(element).await; + } +} + +struct Element { +} + +async fn send_element(_: Element) {} + +fn parse(_: &[u8]) -> Result<(), ()> { + Ok(()) +} + +fn parse_info(_: InfoResult) -> Element { + Element { } +} + +fn main() { + let mut agent = Agent { + info_result: InfoResult { node: None } + }; + let _ = agent.handle(); +} diff --git a/tests/ui/async-await/issue-64130-1-sync.drop_tracking.stderr b/tests/ui/async-await/issue-64130-1-sync.drop_tracking.stderr new file mode 100644 index 00000000000..c4c7f26c7c7 --- /dev/null +++ b/tests/ui/async-await/issue-64130-1-sync.drop_tracking.stderr @@ -0,0 +1,25 @@ +error: future cannot be shared between threads safely + --> $DIR/issue-64130-1-sync.rs:25:13 + | +LL | is_sync(bar()); + | ^^^^^ future returned by `bar` is not `Sync` + | + = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` +note: future is not `Sync` as this value is used across an await + --> $DIR/issue-64130-1-sync.rs:18:10 + | +LL | let x = Foo; + | - has type `Foo` which is not `Sync` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | drop(x); +LL | } + | - `x` is later dropped here +note: required by a bound in `is_sync` + --> $DIR/issue-64130-1-sync.rs:14:15 + | +LL | fn is_sync<T: Sync>(t: T) { } + | ^^^^ required by this bound in `is_sync` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-64130-1-sync.drop_tracking_mir.stderr b/tests/ui/async-await/issue-64130-1-sync.drop_tracking_mir.stderr new file mode 100644 index 00000000000..6f43b568a7a --- /dev/null +++ b/tests/ui/async-await/issue-64130-1-sync.drop_tracking_mir.stderr @@ -0,0 +1,22 @@ +error: future cannot be shared between threads safely + --> $DIR/issue-64130-1-sync.rs:25:13 + | +LL | is_sync(bar()); + | ^^^^^ future returned by `bar` is not `Sync` + | + = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` +note: future is not `Sync` as this value is used across an await + --> $DIR/issue-64130-1-sync.rs:18:10 + | +LL | let x = Foo; + | - has type `Foo` which is not `Sync` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +note: required by a bound in `is_sync` + --> $DIR/issue-64130-1-sync.rs:14:15 + | +LL | fn is_sync<T: Sync>(t: T) { } + | ^^^^ required by this bound in `is_sync` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-64130-1-sync.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-1-sync.no_drop_tracking.stderr new file mode 100644 index 00000000000..c4c7f26c7c7 --- /dev/null +++ b/tests/ui/async-await/issue-64130-1-sync.no_drop_tracking.stderr @@ -0,0 +1,25 @@ +error: future cannot be shared between threads safely + --> $DIR/issue-64130-1-sync.rs:25:13 + | +LL | is_sync(bar()); + | ^^^^^ future returned by `bar` is not `Sync` + | + = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` +note: future is not `Sync` as this value is used across an await + --> $DIR/issue-64130-1-sync.rs:18:10 + | +LL | let x = Foo; + | - has type `Foo` which is not `Sync` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | drop(x); +LL | } + | - `x` is later dropped here +note: required by a bound in `is_sync` + --> $DIR/issue-64130-1-sync.rs:14:15 + | +LL | fn is_sync<T: Sync>(t: T) { } + | ^^^^ required by this bound in `is_sync` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-64130-1-sync.rs b/tests/ui/async-await/issue-64130-1-sync.rs index 1714cec5221..44646e0e5f2 100644 --- a/tests/ui/async-await/issue-64130-1-sync.rs +++ b/tests/ui/async-await/issue-64130-1-sync.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(negative_impls)] // edition:2018 @@ -13,6 +16,7 @@ fn is_sync<T: Sync>(t: T) { } async fn bar() { let x = Foo; baz().await; + drop(x); } async fn baz() { } diff --git a/tests/ui/async-await/issue-64130-1-sync.stderr b/tests/ui/async-await/issue-64130-1-sync.stderr index e205de4738f..8d5169a6302 100644 --- a/tests/ui/async-await/issue-64130-1-sync.stderr +++ b/tests/ui/async-await/issue-64130-1-sync.stderr @@ -1,12 +1,12 @@ error: future cannot be shared between threads safely - --> $DIR/issue-64130-1-sync.rs:21:13 + --> $DIR/issue-64130-1-sync.rs:24:13 | LL | is_sync(bar()); | ^^^^^ future returned by `bar` is not `Sync` | = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` note: future is not `Sync` as this value is used across an await - --> $DIR/issue-64130-1-sync.rs:15:10 + --> $DIR/issue-64130-1-sync.rs:18:10 | LL | let x = Foo; | - has type `Foo` which is not `Sync` @@ -15,7 +15,7 @@ LL | baz().await; LL | } | - `x` is later dropped here note: required by a bound in `is_sync` - --> $DIR/issue-64130-1-sync.rs:11:15 + --> $DIR/issue-64130-1-sync.rs:14:15 | LL | fn is_sync<T: Sync>(t: T) { } | ^^^^ required by this bound in `is_sync` diff --git a/tests/ui/async-await/issue-64130-2-send.drop_tracking.stderr b/tests/ui/async-await/issue-64130-2-send.drop_tracking.stderr new file mode 100644 index 00000000000..b6a73c2a5cb --- /dev/null +++ b/tests/ui/async-await/issue-64130-2-send.drop_tracking.stderr @@ -0,0 +1,28 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-2-send.rs:24:13 + | +LL | is_send(bar()); + | ^^^^^ future returned by `bar` is not `Send` + | + = note: the trait bound `Unique<Foo>: Send` is not satisfied +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-2-send.rs:18:10 + | +LL | let x = Box::new(Foo); + | - has type `Box<Foo>` which is not `Send` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_send` + --> $DIR/issue-64130-2-send.rs:14:15 + | +LL | fn is_send<T: Send>(t: T) { } + | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&bar()); + | + + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-64130-2-send.drop_tracking_mir.stderr b/tests/ui/async-await/issue-64130-2-send.drop_tracking_mir.stderr new file mode 100644 index 00000000000..560560f6036 --- /dev/null +++ b/tests/ui/async-await/issue-64130-2-send.drop_tracking_mir.stderr @@ -0,0 +1,26 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-2-send.rs:24:13 + | +LL | is_send(bar()); + | ^^^^^ future returned by `bar` is not `Send` + | + = note: the trait bound `Unique<Foo>: Send` is not satisfied +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-2-send.rs:18:10 + | +LL | let x = Box::new(Foo); + | - has type `Box<Foo>` which is not `Send` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +note: required by a bound in `is_send` + --> $DIR/issue-64130-2-send.rs:14:15 + | +LL | fn is_send<T: Send>(t: T) { } + | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&bar()); + | + + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-64130-2-send.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-2-send.no_drop_tracking.stderr new file mode 100644 index 00000000000..b6a73c2a5cb --- /dev/null +++ b/tests/ui/async-await/issue-64130-2-send.no_drop_tracking.stderr @@ -0,0 +1,28 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-64130-2-send.rs:24:13 + | +LL | is_send(bar()); + | ^^^^^ future returned by `bar` is not `Send` + | + = note: the trait bound `Unique<Foo>: Send` is not satisfied +note: future is not `Send` as this value is used across an await + --> $DIR/issue-64130-2-send.rs:18:10 + | +LL | let x = Box::new(Foo); + | - has type `Box<Foo>` which is not `Send` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_send` + --> $DIR/issue-64130-2-send.rs:14:15 + | +LL | fn is_send<T: Send>(t: T) { } + | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&bar()); + | + + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-64130-2-send.rs b/tests/ui/async-await/issue-64130-2-send.rs index 7a6e5952cb9..d6d855bac07 100644 --- a/tests/ui/async-await/issue-64130-2-send.rs +++ b/tests/ui/async-await/issue-64130-2-send.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(negative_impls)] // edition:2018 @@ -11,7 +14,7 @@ impl !Send for Foo {} fn is_send<T: Send>(t: T) { } async fn bar() { - let x = Foo; + let x = Box::new(Foo); baz().await; } diff --git a/tests/ui/async-await/issue-64130-2-send.stderr b/tests/ui/async-await/issue-64130-2-send.stderr index 2225000e2e5..f6505cad69e 100644 --- a/tests/ui/async-await/issue-64130-2-send.stderr +++ b/tests/ui/async-await/issue-64130-2-send.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-64130-2-send.rs:21:13 + --> $DIR/issue-64130-2-send.rs:24:13 | LL | is_send(bar()); | ^^^^^ future returned by `bar` is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-2-send.rs:15:10 + --> $DIR/issue-64130-2-send.rs:18:10 | LL | let x = Foo; | - has type `Foo` which is not `Send` @@ -15,7 +15,7 @@ LL | baz().await; LL | } | - `x` is later dropped here note: required by a bound in `is_send` - --> $DIR/issue-64130-2-send.rs:11:15 + --> $DIR/issue-64130-2-send.rs:14:15 | LL | fn is_send<T: Send>(t: T) { } | ^^^^ required by this bound in `is_send` diff --git a/tests/ui/async-await/issue-64130-3-other.drop_tracking.stderr b/tests/ui/async-await/issue-64130-3-other.drop_tracking.stderr new file mode 100644 index 00000000000..d65aae8cc3f --- /dev/null +++ b/tests/ui/async-await/issue-64130-3-other.drop_tracking.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>` + --> $DIR/issue-64130-3-other.rs:27:12 + | +LL | async fn bar() { + | - within this `impl Future<Output = ()>` +... +LL | is_qux(bar()); + | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` + | +note: future does not implement `Qux` as this value is used across an await + --> $DIR/issue-64130-3-other.rs:21:10 + | +LL | let x = Box::new(Foo); + | - has type `Box<Foo>` which does not implement `Qux` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_qux` + --> $DIR/issue-64130-3-other.rs:17:14 + | +LL | fn is_qux<T: Qux>(t: T) {} + | ^^^ required by this bound in `is_qux` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/issue-64130-3-other.drop_tracking_mir.stderr b/tests/ui/async-await/issue-64130-3-other.drop_tracking_mir.stderr new file mode 100644 index 00000000000..8fed69d9d88 --- /dev/null +++ b/tests/ui/async-await/issue-64130-3-other.drop_tracking_mir.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>` + --> $DIR/issue-64130-3-other.rs:27:12 + | +LL | async fn bar() { + | - within this `impl Future<Output = ()>` +... +LL | is_qux(bar()); + | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` + | +note: future does not implement `Qux` as this value is used across an await + --> $DIR/issue-64130-3-other.rs:21:10 + | +LL | let x = Box::new(Foo); + | - has type `Box<Foo>` which does not implement `Qux` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +note: required by a bound in `is_qux` + --> $DIR/issue-64130-3-other.rs:17:14 + | +LL | fn is_qux<T: Qux>(t: T) {} + | ^^^ required by this bound in `is_qux` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/issue-64130-3-other.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-3-other.no_drop_tracking.stderr new file mode 100644 index 00000000000..d65aae8cc3f --- /dev/null +++ b/tests/ui/async-await/issue-64130-3-other.no_drop_tracking.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>` + --> $DIR/issue-64130-3-other.rs:27:12 + | +LL | async fn bar() { + | - within this `impl Future<Output = ()>` +... +LL | is_qux(bar()); + | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` + | +note: future does not implement `Qux` as this value is used across an await + --> $DIR/issue-64130-3-other.rs:21:10 + | +LL | let x = Box::new(Foo); + | - has type `Box<Foo>` which does not implement `Qux` +LL | baz().await; + | ^^^^^^ await occurs here, with `x` maybe used later +LL | } + | - `x` is later dropped here +note: required by a bound in `is_qux` + --> $DIR/issue-64130-3-other.rs:17:14 + | +LL | fn is_qux<T: Qux>(t: T) {} + | ^^^ required by this bound in `is_qux` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/issue-64130-3-other.rs b/tests/ui/async-await/issue-64130-3-other.rs index 630fb2c41cd..92d3b7c81fb 100644 --- a/tests/ui/async-await/issue-64130-3-other.rs +++ b/tests/ui/async-await/issue-64130-3-other.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(auto_traits)] #![feature(negative_impls)] // edition:2018 @@ -14,7 +17,7 @@ impl !Qux for Foo {} fn is_qux<T: Qux>(t: T) {} async fn bar() { - let x = Foo; + let x = Box::new(Foo); baz().await; } diff --git a/tests/ui/async-await/issue-64130-3-other.stderr b/tests/ui/async-await/issue-64130-3-other.stderr index 17867a6a3f6..cb36a3811b2 100644 --- a/tests/ui/async-await/issue-64130-3-other.stderr +++ b/tests/ui/async-await/issue-64130-3-other.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future<Output = ()>` - --> $DIR/issue-64130-3-other.rs:24:12 + --> $DIR/issue-64130-3-other.rs:27:12 | LL | async fn bar() { | - within this `impl Future<Output = ()>` @@ -8,7 +8,7 @@ LL | is_qux(bar()); | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` | note: future does not implement `Qux` as this value is used across an await - --> $DIR/issue-64130-3-other.rs:18:10 + --> $DIR/issue-64130-3-other.rs:21:10 | LL | let x = Foo; | - has type `Foo` which does not implement `Qux` @@ -17,7 +17,7 @@ LL | baz().await; LL | } | - `x` is later dropped here note: required by a bound in `is_qux` - --> $DIR/issue-64130-3-other.rs:14:14 + --> $DIR/issue-64130-3-other.rs:17:14 | LL | fn is_qux<T: Qux>(t: T) {} | ^^^ required by this bound in `is_qux` diff --git a/tests/ui/async-await/issue-64130-4-async-move.drop-tracking.stderr b/tests/ui/async-await/issue-64130-4-async-move.drop-tracking.stderr index f609e36362c..884619f4dd6 100644 --- a/tests/ui/async-await/issue-64130-4-async-move.drop-tracking.stderr +++ b/tests/ui/async-await/issue-64130-4-async-move.drop-tracking.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-64130-4-async-move.rs:19:17 + --> $DIR/issue-64130-4-async-move.rs:20:17 | LL | pub fn foo() -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-4-async-move.rs:25:31 + --> $DIR/issue-64130-4-async-move.rs:27:31 | LL | match client.status() { | ------ has type `&Client` which is not `Send` @@ -17,7 +17,7 @@ LL | let _x = get().await; LL | } | - `client` is later dropped here help: consider moving this into a `let` binding to create a shorter lived borrow - --> $DIR/issue-64130-4-async-move.rs:23:15 + --> $DIR/issue-64130-4-async-move.rs:25:15 | LL | match client.status() { | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/issue-64130-4-async-move.no_drop_tracking.stderr b/tests/ui/async-await/issue-64130-4-async-move.no_drop_tracking.stderr index f609e36362c..0bc7cb2f2ac 100644 --- a/tests/ui/async-await/issue-64130-4-async-move.no_drop_tracking.stderr +++ b/tests/ui/async-await/issue-64130-4-async-move.no_drop_tracking.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-64130-4-async-move.rs:19:17 + --> $DIR/issue-64130-4-async-move.rs:21:17 | LL | pub fn foo() -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` note: future is not `Send` as this value is used across an await - --> $DIR/issue-64130-4-async-move.rs:25:31 + --> $DIR/issue-64130-4-async-move.rs:27:31 | LL | match client.status() { | ------ has type `&Client` which is not `Send` @@ -17,7 +17,7 @@ LL | let _x = get().await; LL | } | - `client` is later dropped here help: consider moving this into a `let` binding to create a shorter lived borrow - --> $DIR/issue-64130-4-async-move.rs:23:15 + --> $DIR/issue-64130-4-async-move.rs:25:15 | LL | match client.status() { | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/issue-64130-4-async-move.rs b/tests/ui/async-await/issue-64130-4-async-move.rs index a38428fc00f..bcb297aaa02 100644 --- a/tests/ui/async-await/issue-64130-4-async-move.rs +++ b/tests/ui/async-await/issue-64130-4-async-move.rs @@ -1,8 +1,10 @@ // edition:2018 -// revisions: no_drop_tracking drop_tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// [drop_tracking_mir] check-pass // [drop_tracking] check-pass -// [drop_tracking] compile-flags: -Zdrop-tracking=yes -// [no_drop_tracking] compile-flags: -Zdrop-tracking=no + use std::any::Any; use std::future::Future; diff --git a/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking.stderr b/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking.stderr new file mode 100644 index 00000000000..fc8bcc8ae79 --- /dev/null +++ b/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking.stderr @@ -0,0 +1,30 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-67252-unnamed-future.rs:21:11 + | +LL | spawn(async { + | ___________^ +LL | | let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` +LL | | AFuture.await; +LL | | drop(a); +LL | | }); + | |_____^ future created by async block is not `Send` + | + = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:21:11: 25:6]`, the trait `Send` is not implemented for `*mut ()` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-67252-unnamed-future.rs:23:16 + | +LL | let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` + | - has type `*mut ()` which is not `Send` +LL | AFuture.await; + | ^^^^^^ await occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `spawn` + --> $DIR/issue-67252-unnamed-future.rs:9:13 + | +LL | fn spawn<T: Send>(_: T) {} + | ^^^^ required by this bound in `spawn` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking_mir.stderr b/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking_mir.stderr new file mode 100644 index 00000000000..a3ef7add116 --- /dev/null +++ b/tests/ui/async-await/issue-67252-unnamed-future.drop_tracking_mir.stderr @@ -0,0 +1,22 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-67252-unnamed-future.rs:21:5 + | +LL | spawn(async { + | ^^^^^ future created by async block is not `Send` + | + = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:21:11: 25:6]`, the trait `Send` is not implemented for `*mut ()` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-67252-unnamed-future.rs:23:16 + | +LL | let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` + | - has type `*mut ()` which is not `Send` +LL | AFuture.await; + | ^^^^^^ await occurs here, with `a` maybe used later +note: required by a bound in `spawn` + --> $DIR/issue-67252-unnamed-future.rs:9:13 + | +LL | fn spawn<T: Send>(_: T) {} + | ^^^^ required by this bound in `spawn` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-67252-unnamed-future.no_drop_tracking.stderr b/tests/ui/async-await/issue-67252-unnamed-future.no_drop_tracking.stderr new file mode 100644 index 00000000000..fc8bcc8ae79 --- /dev/null +++ b/tests/ui/async-await/issue-67252-unnamed-future.no_drop_tracking.stderr @@ -0,0 +1,30 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-67252-unnamed-future.rs:21:11 + | +LL | spawn(async { + | ___________^ +LL | | let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` +LL | | AFuture.await; +LL | | drop(a); +LL | | }); + | |_____^ future created by async block is not `Send` + | + = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:21:11: 25:6]`, the trait `Send` is not implemented for `*mut ()` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-67252-unnamed-future.rs:23:16 + | +LL | let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` + | - has type `*mut ()` which is not `Send` +LL | AFuture.await; + | ^^^^^^ await occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `spawn` + --> $DIR/issue-67252-unnamed-future.rs:9:13 + | +LL | fn spawn<T: Send>(_: T) {} + | ^^^^ required by this bound in `spawn` + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-67252-unnamed-future.rs b/tests/ui/async-await/issue-67252-unnamed-future.rs index 1a7ff613341..bb9ad77cef3 100644 --- a/tests/ui/async-await/issue-67252-unnamed-future.rs +++ b/tests/ui/async-await/issue-67252-unnamed-future.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 use std::future::Future; use std::pin::Pin; @@ -16,8 +19,9 @@ impl Future for AFuture{ async fn foo() { spawn(async { //~ ERROR future cannot be sent between threads safely - let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` + let a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` AFuture.await; + drop(a); }); } diff --git a/tests/ui/async-await/issue-67252-unnamed-future.stderr b/tests/ui/async-await/issue-67252-unnamed-future.stderr deleted file mode 100644 index fcba4410ba9..00000000000 --- a/tests/ui/async-await/issue-67252-unnamed-future.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: future cannot be sent between threads safely - --> $DIR/issue-67252-unnamed-future.rs:18:11 - | -LL | spawn(async { - | ___________^ -LL | | let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` -LL | | AFuture.await; -LL | | }); - | |_____^ future created by async block is not `Send` - | - = help: within `[async block@$DIR/issue-67252-unnamed-future.rs:18:11: 21:6]`, the trait `Send` is not implemented for `*mut ()` -note: future is not `Send` as this value is used across an await - --> $DIR/issue-67252-unnamed-future.rs:20:16 - | -LL | let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` - | -- has type `*mut ()` which is not `Send` -LL | AFuture.await; - | ^^^^^^ await occurs here, with `_a` maybe used later -LL | }); - | - `_a` is later dropped here -note: required by a bound in `spawn` - --> $DIR/issue-67252-unnamed-future.rs:6:13 - | -LL | fn spawn<T: Send>(_: T) {} - | ^^^^ required by this bound in `spawn` - -error: aborting due to previous error - diff --git a/tests/ui/async-await/issue-68112.drop_tracking.stderr b/tests/ui/async-await/issue-68112.drop_tracking.stderr index f2802698fd5..bd648de3067 100644 --- a/tests/ui/async-await/issue-68112.drop_tracking.stderr +++ b/tests/ui/async-await/issue-68112.drop_tracking.stderr @@ -5,6 +5,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:34:17 | @@ -23,6 +24,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:43:17 | @@ -43,6 +45,7 @@ LL | require_send(send_fut); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this `async fn` body --> $DIR/issue-68112.rs:50:31 diff --git a/tests/ui/async-await/issue-68112.drop_tracking_mir.stderr b/tests/ui/async-await/issue-68112.drop_tracking_mir.stderr new file mode 100644 index 00000000000..7a9242cbaf5 --- /dev/null +++ b/tests/ui/async-await/issue-68112.drop_tracking_mir.stderr @@ -0,0 +1,80 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:37:5 + | +LL | require_send(send_fut); + | ^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/issue-68112.rs:34:17 + | +LL | let _ = non_send_fut.await; + | ^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send` +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:14:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:46:5 + | +LL | require_send(send_fut); + | ^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/issue-68112.rs:43:17 + | +LL | let _ = make_non_send_future1().await; + | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future<Output = Arc<RefCell<i32>>>`, which is not `Send` +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:14:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error[E0277]: `RefCell<i32>` cannot be shared between threads safely + --> $DIR/issue-68112.rs:65:5 + | +LL | require_send(send_fut); + | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead + = note: required for `Arc<RefCell<i32>>` to implement `Send` +note: required because it's used within this `async fn` body + --> $DIR/issue-68112.rs:50:31 + | +LL | async fn ready2<T>(t: T) -> T { + | _______________________________^ +LL | | t +LL | | } + | |_^ +note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>` + --> $DIR/issue-68112.rs:53:31 + | +LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `impl Future<Output = Arc<RefCell<i32>>>`, `Ready<i32>` +note: required because it's used within this `async` block + --> $DIR/issue-68112.rs:60:20 + | +LL | let send_fut = async { + | ____________________^ +LL | | let non_send_fut = make_non_send_future2(); +LL | | let _ = non_send_fut.await; +LL | | ready(0).await; +LL | | }; + | |_____^ +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:14:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/issue-68112.no_drop_tracking.stderr b/tests/ui/async-await/issue-68112.no_drop_tracking.stderr index 38eb85b302f..35b7341f63a 100644 --- a/tests/ui/async-await/issue-68112.no_drop_tracking.stderr +++ b/tests/ui/async-await/issue-68112.no_drop_tracking.stderr @@ -5,6 +5,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:34:17 | @@ -23,6 +24,7 @@ LL | require_send(send_fut); | ^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:43:17 | @@ -43,6 +45,7 @@ LL | require_send(send_fut); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this `async fn` body --> $DIR/issue-68112.rs:50:31 diff --git a/tests/ui/async-await/issue-68112.rs b/tests/ui/async-await/issue-68112.rs index 9c705137a10..19119ae0fc1 100644 --- a/tests/ui/async-await/issue-68112.rs +++ b/tests/ui/async-await/issue-68112.rs @@ -1,7 +1,7 @@ // edition:2018 -// revisions: no_drop_tracking drop_tracking -// [drop_tracking] compile-flags: -Zdrop-tracking=yes -// [no_drop_tracking] compile-flags: -Zdrop-tracking=no +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir use std::{ cell::RefCell, @@ -14,7 +14,7 @@ use std::{ fn require_send(_: impl Send) {} struct Ready<T>(Option<T>); -impl<T> Future for Ready<T> { +impl<T: Unpin> Future for Ready<T> { type Output = T; fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> { Poll::Ready(self.0.take().unwrap()) diff --git a/tests/ui/async-await/issue-70818.drop_tracking.stderr b/tests/ui/async-await/issue-70818.drop_tracking.stderr new file mode 100644 index 00000000000..ab0698c3ec2 --- /dev/null +++ b/tests/ui/async-await/issue-70818.drop_tracking.stderr @@ -0,0 +1,18 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:7:38 + | +LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> $DIR/issue-70818.rs:9:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` +help: consider restricting type parameter `U` + | +LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-70818.drop_tracking_mir.stderr b/tests/ui/async-await/issue-70818.drop_tracking_mir.stderr new file mode 100644 index 00000000000..ab0698c3ec2 --- /dev/null +++ b/tests/ui/async-await/issue-70818.drop_tracking_mir.stderr @@ -0,0 +1,18 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:7:38 + | +LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> $DIR/issue-70818.rs:9:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` +help: consider restricting type parameter `U` + | +LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-70818.no_drop_tracking.stderr b/tests/ui/async-await/issue-70818.no_drop_tracking.stderr new file mode 100644 index 00000000000..ab0698c3ec2 --- /dev/null +++ b/tests/ui/async-await/issue-70818.no_drop_tracking.stderr @@ -0,0 +1,18 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:7:38 + | +LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> $DIR/issue-70818.rs:9:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` +help: consider restricting type parameter `U` + | +LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs index 019c56eb2fa..2941de0f577 100644 --- a/tests/ui/async-await/issue-70818.rs +++ b/tests/ui/async-await/issue-70818.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 use std::future::Future; diff --git a/tests/ui/async-await/issue-70818.stderr b/tests/ui/async-await/issue-70818.stderr index 20109d4d116..ab0698c3ec2 100644 --- a/tests/ui/async-await/issue-70818.stderr +++ b/tests/ui/async-await/issue-70818.stderr @@ -1,11 +1,11 @@ error: future cannot be sent between threads safely - --> $DIR/issue-70818.rs:4:38 + --> $DIR/issue-70818.rs:7:38 | LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | note: captured value is not `Send` - --> $DIR/issue-70818.rs:6:18 + --> $DIR/issue-70818.rs:9:18 | LL | async { (ty, ty1) } | ^^^ has type `U` which is not `Send` diff --git a/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr new file mode 100644 index 00000000000..c636be15a58 --- /dev/null +++ b/tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr @@ -0,0 +1,34 @@ +error[E0277]: `Sender<i32>` cannot be shared between threads safely + --> $DIR/issue-70935-complex-spans.rs:13:45 + | +LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Sender<i32>` + = note: required for `&Sender<i32>` to implement `Send` +note: required because it's used within this closure + --> $DIR/issue-70935-complex-spans.rs:17:13 + | +LL | baz(|| async{ + | ^^ +note: required because it's used within this `async fn` body + --> $DIR/issue-70935-complex-spans.rs:10:67 + | +LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { + | ___________________________________________________________________^ +LL | | } + | |_^ + = note: required because it captures the following types: `impl Future<Output = ()>` +note: required because it's used within this `async` block + --> $DIR/issue-70935-complex-spans.rs:16:5 + | +LL | / async move { +LL | | baz(|| async{ +LL | | foo(tx.clone()); +LL | | }).await; +LL | | } + | |_____^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/issue-70935-complex-spans.rs b/tests/ui/async-await/issue-70935-complex-spans.rs index b6d17f93a66..78625bd393d 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.rs +++ b/tests/ui/async-await/issue-70935-complex-spans.rs @@ -1,7 +1,7 @@ // edition:2018 -// revisions: no_drop_tracking drop_tracking -// [no_drop_tracking]compile-flags:-Zdrop-tracking=no -// [drop_tracking]compile-flags:-Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // #70935: Check if we do not emit snippet // with newlines which lead complex diagnostics. @@ -12,7 +12,7 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { //[no_drop_tracking]~^ ERROR future cannot be sent between threads safely - //[drop_tracking]~^^ ERROR `Sender<i32>` cannot be shared between threads + //[drop_tracking,drop_tracking_mir]~^^ ERROR `Sender<i32>` cannot be shared between threads async move { baz(|| async{ foo(tx.clone()); diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking.stderr new file mode 100644 index 00000000000..6d19c3beb2f --- /dev/null +++ b/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking_mir.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking_mir.stderr new file mode 100644 index 00000000000..6d19c3beb2f --- /dev/null +++ b/tests/ui/async-await/issue-73741-type-err-drop-tracking.drop_tracking_mir.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.no_drop_tracking.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.no_drop_tracking.stderr new file mode 100644 index 00000000000..6d19c3beb2f --- /dev/null +++ b/tests/ui/async-await/issue-73741-type-err-drop-tracking.no_drop_tracking.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.rs b/tests/ui/async-await/issue-73741-type-err-drop-tracking.rs index c3423ad629f..1fa8d69143a 100644 --- a/tests/ui/async-await/issue-73741-type-err-drop-tracking.rs +++ b/tests/ui/async-await/issue-73741-type-err-drop-tracking.rs @@ -1,5 +1,8 @@ // edition:2018 -// compile-flags: -Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// // Regression test for issue #73741 // Ensures that we don't emit spurious errors when // a type error ocurrs in an `async fn` diff --git a/tests/ui/async-await/issue-73741-type-err-drop-tracking.stderr b/tests/ui/async-await/issue-73741-type-err-drop-tracking.stderr index d4e3b6c3bf4..6d19c3beb2f 100644 --- a/tests/ui/async-await/issue-73741-type-err-drop-tracking.stderr +++ b/tests/ui/async-await/issue-73741-type-err-drop-tracking.stderr @@ -1,5 +1,5 @@ error[E0070]: invalid left-hand side of assignment - --> $DIR/issue-73741-type-err-drop-tracking.rs:8:7 + --> $DIR/issue-73741-type-err-drop-tracking.rs:11:7 | LL | 1 = 2; | - ^ diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr index b96cab9f0f5..628ba1a4818 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -4,9 +4,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed LL | pub async fn async_fn(x: &mut i32) -> &i32 { | - let's call the lifetime of this reference `'1` LL | let y = &*x; - | --- borrow of `*x` occurs here + | --- `*x` is borrowed here LL | *x += 1; - | ^^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` @@ -14,9 +14,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9 | LL | let y = &*x; - | --- borrow of `*x` occurs here + | --- `*x` is borrowed here LL | *x += 1; - | ^^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` LL | })() @@ -28,9 +28,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed LL | (async move || -> &i32 { | - let's call the lifetime of this reference `'1` LL | let y = &*x; - | --- borrow of `*x` occurs here + | --- `*x` is borrowed here LL | *x += 1; - | ^^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` @@ -38,9 +38,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9 | LL | let y = &*x; - | --- borrow of `*x` occurs here + | --- `*x` is borrowed here LL | *x += 1; - | ^^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | y | - returning this value requires that `*x` is borrowed for `'1` LL | } diff --git a/tests/ui/async-await/issue-75785-confusing-named-region.stderr b/tests/ui/async-await/issue-75785-confusing-named-region.stderr index 3b731d9c60a..b69033a0eda 100644 --- a/tests/ui/async-await/issue-75785-confusing-named-region.stderr +++ b/tests/ui/async-await/issue-75785-confusing-named-region.stderr @@ -4,9 +4,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed LL | pub async fn async_fn(x: &mut i32) -> (&i32, &i32) { | - let's call the lifetime of this reference `'1` LL | let y = &*x; - | --- borrow of `*x` occurs here + | --- `*x` is borrowed here LL | *x += 1; - | ^^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^^ `*x` is assigned to here but it was already borrowed LL | (&32, y) | -------- returning this value requires that `*x` is borrowed for `'1` diff --git a/tests/ui/async-await/issue-86507.stderr b/tests/ui/async-await/issue-86507.drop_tracking.stderr index 8c2c06da25c..5c8b7ef1b71 100644 --- a/tests/ui/async-await/issue-86507.stderr +++ b/tests/ui/async-await/issue-86507.drop_tracking.stderr @@ -1,5 +1,5 @@ error: future cannot be sent between threads safely - --> $DIR/issue-86507.rs:17:13 + --> $DIR/issue-86507.rs:20:13 | LL | / Box::pin( LL | | async move { @@ -9,11 +9,11 @@ LL | | ) | |_____________^ future created by async block is not `Send` | note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> $DIR/issue-86507.rs:19:29 + --> $DIR/issue-86507.rs:22:29 | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `[async block@$DIR/issue-86507.rs:18:17: 20:18]` to the object type `dyn Future<Output = ()> + Send` + = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send` help: consider further restricting this bound | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr b/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr new file mode 100644 index 00000000000..5c8b7ef1b71 --- /dev/null +++ b/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-86507.rs:20:13 + | +LL | / Box::pin( +LL | | async move { +LL | | let x = x; +LL | | } +LL | | ) + | |_____________^ future created by async block is not `Send` + | +note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` + --> $DIR/issue-86507.rs:22:29 + | +LL | let x = x; + | ^ has type `&T` which is not `Send`, because `T` is not `Sync` + = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send` +help: consider further restricting this bound + | +LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-86507.no_drop_tracking.stderr b/tests/ui/async-await/issue-86507.no_drop_tracking.stderr new file mode 100644 index 00000000000..5c8b7ef1b71 --- /dev/null +++ b/tests/ui/async-await/issue-86507.no_drop_tracking.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-86507.rs:20:13 + | +LL | / Box::pin( +LL | | async move { +LL | | let x = x; +LL | | } +LL | | ) + | |_____________^ future created by async block is not `Send` + | +note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` + --> $DIR/issue-86507.rs:22:29 + | +LL | let x = x; + | ^ has type `&T` which is not `Send`, because `T` is not `Sync` + = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send` +help: consider further restricting this bound + | +LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) + | +++++++++++++++++++ + +error: aborting due to previous error + diff --git a/tests/ui/async-await/issue-86507.rs b/tests/ui/async-await/issue-86507.rs index 317f0317664..63c298dbe3d 100644 --- a/tests/ui/async-await/issue-86507.rs +++ b/tests/ui/async-await/issue-86507.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 use ::core::pin::Pin; diff --git a/tests/ui/async-await/issue-93648.rs b/tests/ui/async-await/issue-93648.rs index 4ce3ac1e874..ec2249ca592 100644 --- a/tests/ui/async-await/issue-93648.rs +++ b/tests/ui/async-await/issue-93648.rs @@ -1,6 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2021 // build-pass -// compile-flags: -Zdrop-tracking fn main() { let _ = async { diff --git a/tests/ui/async-await/issues/auxiliary/issue_67893.rs b/tests/ui/async-await/issues/auxiliary/issue_67893.rs index 387966a5064..d5394469806 100644 --- a/tests/ui/async-await/issues/auxiliary/issue_67893.rs +++ b/tests/ui/async-await/issues/auxiliary/issue_67893.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 use std::sync::{Arc, Mutex}; diff --git a/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.no_drop_tracking.stderr b/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.no_drop_tracking.stderr index 1033fa6cc8b..8745bdd973b 100644 --- a/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.no_drop_tracking.stderr +++ b/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.no_drop_tracking.stderr @@ -1,5 +1,5 @@ error: future cannot be sent between threads safely - --> $DIR/issue-65436-raw-ptr-not-send.rs:16:17 + --> $DIR/issue-65436-raw-ptr-not-send.rs:17:17 | LL | assert_send(async { | _________________^ @@ -8,9 +8,9 @@ LL | | bar(Foo(std::ptr::null())).await; LL | | }) | |_____^ future created by async block is not `Send` | - = help: within `[async block@$DIR/issue-65436-raw-ptr-not-send.rs:16:17: 19:6]`, the trait `Send` is not implemented for `*const u8` + = help: within `[async block@$DIR/issue-65436-raw-ptr-not-send.rs:17:17: 20:6]`, the trait `Send` is not implemented for `*const u8` note: future is not `Send` as this value is used across an await - --> $DIR/issue-65436-raw-ptr-not-send.rs:18:35 + --> $DIR/issue-65436-raw-ptr-not-send.rs:19:35 | LL | bar(Foo(std::ptr::null())).await; | ---------------- ^^^^^^- `std::ptr::null()` is later dropped here @@ -18,12 +18,12 @@ LL | bar(Foo(std::ptr::null())).await; | | await occurs here, with `std::ptr::null()` maybe used later | has type `*const u8` which is not `Send` help: consider moving this into a `let` binding to create a shorter lived borrow - --> $DIR/issue-65436-raw-ptr-not-send.rs:18:13 + --> $DIR/issue-65436-raw-ptr-not-send.rs:19:13 | LL | bar(Foo(std::ptr::null())).await; | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `assert_send` - --> $DIR/issue-65436-raw-ptr-not-send.rs:13:19 + --> $DIR/issue-65436-raw-ptr-not-send.rs:14:19 | LL | fn assert_send<T: Send>(_: T) {} | ^^^^ required by this bound in `assert_send` diff --git a/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs b/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs index 91edbc10dc0..d7ef929517c 100644 --- a/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs +++ b/tests/ui/async-await/issues/issue-65436-raw-ptr-not-send.rs @@ -1,8 +1,9 @@ // edition:2018 -// revisions: no_drop_tracking drop_tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // [drop_tracking] check-pass -// [drop_tracking] compile-flags: -Zdrop-tracking=yes -// [no_drop_tracking] compile-flags: -Zdrop-tracking=no +// [drop_tracking_mir] check-pass struct Foo(*const u8); diff --git a/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs b/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs index dda4a151dd2..c4f8f607d25 100644 --- a/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs +++ b/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs @@ -1,6 +1,10 @@ // build-pass // edition:2018 +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + static mut A: [i32; 5] = [1, 2, 3, 4, 5]; fn is_send_sync<T: Send + Sync>(_: T) {} diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr index 2ce68a78291..ce9424c8b25 100644 --- a/tests/ui/async-await/issues/issue-67893.stderr +++ b/tests/ui/async-await/issues/issue-67893.stderr @@ -6,7 +6,7 @@ LL | g(issue_67893::run()) | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` note: future is not `Send` as this value is used across an await - --> $DIR/auxiliary/issue_67893.rs:9:26 + --> $DIR/auxiliary/issue_67893.rs:12:26 | LL | f(*x.lock().unwrap()).await; | ----------------- ^^^^^^- `x.lock().unwrap()` is later dropped here diff --git a/tests/ui/async-await/multiple-lifetimes/ret-ref.stderr b/tests/ui/async-await/multiple-lifetimes/ret-ref.stderr index d86e84033b8..a599ac1d92f 100644 --- a/tests/ui/async-await/multiple-lifetimes/ret-ref.stderr +++ b/tests/ui/async-await/multiple-lifetimes/ret-ref.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `a` because it is borrowed --> $DIR/ret-ref.rs:16:5 | LL | let future = multiple_named_lifetimes(&a, &b); - | -- borrow of `a` occurs here + | -- `a` is borrowed here LL | a += 1; - | ^^^^^^ assignment to borrowed `a` occurs here + | ^^^^^^ `a` is assigned to here but it was already borrowed LL | b += 1; LL | let p = future.await; | ------ borrow later used here @@ -13,10 +13,10 @@ error[E0506]: cannot assign to `b` because it is borrowed --> $DIR/ret-ref.rs:17:5 | LL | let future = multiple_named_lifetimes(&a, &b); - | -- borrow of `b` occurs here + | -- `b` is borrowed here LL | a += 1; LL | b += 1; - | ^^^^^^ assignment to borrowed `b` occurs here + | ^^^^^^ `b` is assigned to here but it was already borrowed LL | let p = future.await; | ------ borrow later used here @@ -24,10 +24,10 @@ error[E0506]: cannot assign to `a` because it is borrowed --> $DIR/ret-ref.rs:28:5 | LL | let future = multiple_named_lifetimes(&a, &b); - | -- borrow of `a` occurs here + | -- `a` is borrowed here LL | let p = future.await; LL | a += 1; - | ^^^^^^ assignment to borrowed `a` occurs here + | ^^^^^^ `a` is assigned to here but it was already borrowed LL | b += 1; LL | drop(p); | - borrow later used here diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking.stderr new file mode 100644 index 00000000000..8a7317bb95a --- /dev/null +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking.stderr @@ -0,0 +1,21 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 + | +LL | async fn rec_1() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18 + | +LL | async fn rec_2() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking_mir.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking_mir.stderr new file mode 100644 index 00000000000..8a7317bb95a --- /dev/null +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.drop_tracking_mir.stderr @@ -0,0 +1,21 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 + | +LL | async fn rec_1() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18 + | +LL | async fn rec_2() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.no_drop_tracking.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.no_drop_tracking.stderr new file mode 100644 index 00000000000..8a7317bb95a --- /dev/null +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.no_drop_tracking.stderr @@ -0,0 +1,21 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 + | +LL | async fn rec_1() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18 + | +LL | async fn rec_2() { + | ^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs index bb2a61f03ce..a241f30e73e 100644 --- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.rs @@ -1,3 +1,7 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + // edition:2018 // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. diff --git a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr index f789ad2a05c..8a7317bb95a 100644 --- a/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr +++ b/tests/ui/async-await/mutually-recursive-async-impl-trait-type.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/mutually-recursive-async-impl-trait-type.rs:5:18 + --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 | LL | async fn rec_1() { | ^ recursive `async fn` @@ -8,7 +8,7 @@ LL | async fn rec_1() { = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/mutually-recursive-async-impl-trait-type.rs:9:18 + --> $DIR/mutually-recursive-async-impl-trait-type.rs:13:18 | LL | async fn rec_2() { | ^ recursive `async fn` diff --git a/tests/ui/async-await/non-trivial-drop.rs b/tests/ui/async-await/non-trivial-drop.rs index a3167215dc3..d4df9d439c5 100644 --- a/tests/ui/async-await/non-trivial-drop.rs +++ b/tests/ui/async-await/non-trivial-drop.rs @@ -1,6 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // build-pass // edition:2018 -// compile-flags: -Zdrop-tracking=y #![feature(generators)] diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking.stderr new file mode 100644 index 00000000000..7e63a8da552 --- /dev/null +++ b/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking.stderr @@ -0,0 +1,12 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/recursive-async-impl-trait-type.rs:8:40 + | +LL | async fn recursive_async_function() -> () { + | ^^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking_mir.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking_mir.stderr new file mode 100644 index 00000000000..7e63a8da552 --- /dev/null +++ b/tests/ui/async-await/recursive-async-impl-trait-type.drop_tracking_mir.stderr @@ -0,0 +1,12 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/recursive-async-impl-trait-type.rs:8:40 + | +LL | async fn recursive_async_function() -> () { + | ^^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.no_drop_tracking.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.no_drop_tracking.stderr new file mode 100644 index 00000000000..7e63a8da552 --- /dev/null +++ b/tests/ui/async-await/recursive-async-impl-trait-type.no_drop_tracking.stderr @@ -0,0 +1,12 @@ +error[E0733]: recursion in an `async fn` requires boxing + --> $DIR/recursive-async-impl-trait-type.rs:8:40 + | +LL | async fn recursive_async_function() -> () { + | ^^ recursive `async fn` + | + = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future` + = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.rs b/tests/ui/async-await/recursive-async-impl-trait-type.rs index edc4cb8ac5d..60b34d3a174 100644 --- a/tests/ui/async-await/recursive-async-impl-trait-type.rs +++ b/tests/ui/async-await/recursive-async-impl-trait-type.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. diff --git a/tests/ui/async-await/recursive-async-impl-trait-type.stderr b/tests/ui/async-await/recursive-async-impl-trait-type.stderr index 63f64f44557..7e63a8da552 100644 --- a/tests/ui/async-await/recursive-async-impl-trait-type.stderr +++ b/tests/ui/async-await/recursive-async-impl-trait-type.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/recursive-async-impl-trait-type.rs:5:40 + --> $DIR/recursive-async-impl-trait-type.rs:8:40 | LL | async fn recursive_async_function() -> () { | ^^ recursive `async fn` diff --git a/tests/ui/async-await/send-bound-async-closure.rs b/tests/ui/async-await/send-bound-async-closure.rs new file mode 100644 index 00000000000..4e9e7309be0 --- /dev/null +++ b/tests/ui/async-await/send-bound-async-closure.rs @@ -0,0 +1,37 @@ +// edition: 2021 +// check-pass + +// This test verifies that we do not create a query cycle when typechecking has several inference +// variables that point to the same generator interior type. + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +type ChannelTask = Pin<Box<dyn Future<Output = ()> + Send>>; + +pub fn register_message_type() -> ChannelTask { + Box::pin(async move { + let f = |__cx: &mut Context<'_>| Poll::<()>::Pending; + PollFn { f }.await + }) +} + +struct PollFn<F> { + f: F, +} + +impl<F> Unpin for PollFn<F> {} + +impl<T, F> Future for PollFn<F> +where + F: FnMut(&mut Context<'_>) -> Poll<T>, +{ + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { + (&mut self.f)(cx) + } +} + +fn main() {} diff --git a/tests/ui/async-await/unresolved_type_param.drop_tracking.stderr b/tests/ui/async-await/unresolved_type_param.drop_tracking.stderr new file mode 100644 index 00000000000..912e2b34c05 --- /dev/null +++ b/tests/ui/async-await/unresolved_type_param.drop_tracking.stderr @@ -0,0 +1,39 @@ +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0698`. diff --git a/tests/ui/async-await/unresolved_type_param.drop_tracking_mir.stderr b/tests/ui/async-await/unresolved_type_param.drop_tracking_mir.stderr new file mode 100644 index 00000000000..95c79946831 --- /dev/null +++ b/tests/ui/async-await/unresolved_type_param.drop_tracking_mir.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type of the type parameter `T` declared on the function `bar` + | +help: consider specifying the generic argument + | +LL | bar::<T>().await; + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/async-await/unresolved_type_param.no_drop_tracking.stderr b/tests/ui/async-await/unresolved_type_param.no_drop_tracking.stderr new file mode 100644 index 00000000000..16d618caa57 --- /dev/null +++ b/tests/ui/async-await/unresolved_type_param.no_drop_tracking.stderr @@ -0,0 +1,63 @@ +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/unresolved_type_param.rs:12:5 + | +LL | bar().await; + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/unresolved_type_param.rs:12:10 + | +LL | bar().await; + | ^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0698`. diff --git a/tests/ui/async-await/unresolved_type_param.rs b/tests/ui/async-await/unresolved_type_param.rs index 6d6d8061491..ca0a92b9434 100644 --- a/tests/ui/async-await/unresolved_type_param.rs +++ b/tests/ui/async-await/unresolved_type_param.rs @@ -1,24 +1,36 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // Provoke an unresolved type error (T). // Error message should pinpoint the type parameter T as needing to be bound // (rather than give a general error message) // edition:2018 -// compile-flags: -Zdrop-tracking async fn bar<T>() -> () {} async fn foo() { bar().await; - //~^ ERROR type inside `async fn` body must be known in this context - //~| ERROR type inside `async fn` body must be known in this context - //~| ERROR type inside `async fn` body must be known in this context - //~| NOTE cannot infer type for type parameter `T` - //~| NOTE cannot infer type for type parameter `T` - //~| NOTE cannot infer type for type parameter `T` - //~| NOTE the type is part of the `async fn` body because of this `await` - //~| NOTE the type is part of the `async fn` body because of this `await` - //~| NOTE the type is part of the `async fn` body because of this `await` - //~| NOTE in this expansion of desugaring of `await` - //~| NOTE in this expansion of desugaring of `await` - //~| NOTE in this expansion of desugaring of `await` + //[drop_tracking_mir]~^ ERROR type annotations needed + //[drop_tracking_mir]~| NOTE cannot infer type of the type parameter `T` + //[no_drop_tracking,drop_tracking]~^^^ ERROR type inside `async fn` body must be known in this context + //[no_drop_tracking,drop_tracking]~| ERROR type inside `async fn` body must be known in this context + //[no_drop_tracking,drop_tracking]~| ERROR type inside `async fn` body must be known in this context + //[no_drop_tracking,drop_tracking]~| NOTE cannot infer type for type parameter `T` + //[no_drop_tracking,drop_tracking]~| NOTE cannot infer type for type parameter `T` + //[no_drop_tracking,drop_tracking]~| NOTE cannot infer type for type parameter `T` + //[no_drop_tracking,drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await` + //[no_drop_tracking,drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await` + //[no_drop_tracking,drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await` + //[no_drop_tracking,drop_tracking]~| NOTE in this expansion of desugaring of `await` + //[no_drop_tracking,drop_tracking]~| NOTE in this expansion of desugaring of `await` + //[no_drop_tracking,drop_tracking]~| NOTE in this expansion of desugaring of `await` + //[no_drop_tracking]~^^^^^^^^^^^^^^^ ERROR type inside `async fn` body must be known in this context + //[no_drop_tracking]~| ERROR type inside `async fn` body must be known in this context + //[no_drop_tracking]~| NOTE cannot infer type for type parameter `T` + //[no_drop_tracking]~| NOTE cannot infer type for type parameter `T` + //[no_drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await` + //[no_drop_tracking]~| NOTE the type is part of the `async fn` body because of this `await` + //[no_drop_tracking]~| NOTE in this expansion of desugaring of `await` + //[no_drop_tracking]~| NOTE in this expansion of desugaring of `await` } fn main() {} diff --git a/tests/ui/async-await/unresolved_type_param.stderr b/tests/ui/async-await/unresolved_type_param.stderr index 7236c681f34..64a31b5fc32 100644 --- a/tests/ui/async-await/unresolved_type_param.stderr +++ b/tests/ui/async-await/unresolved_type_param.stderr @@ -1,35 +1,35 @@ error[E0698]: type inside `async fn` body must be known in this context - --> $DIR/unresolved_type_param.rs:10:5 + --> $DIR/unresolved_type_param.rs:13:5 | LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:10:10 + --> $DIR/unresolved_type_param.rs:13:10 | LL | bar().await; | ^^^^^^ error[E0698]: type inside `async fn` body must be known in this context - --> $DIR/unresolved_type_param.rs:10:5 + --> $DIR/unresolved_type_param.rs:13:5 | LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:10:10 + --> $DIR/unresolved_type_param.rs:13:10 | LL | bar().await; | ^^^^^^ error[E0698]: type inside `async fn` body must be known in this context - --> $DIR/unresolved_type_param.rs:10:5 + --> $DIR/unresolved_type_param.rs:13:5 | LL | bar().await; | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` - --> $DIR/unresolved_type_param.rs:10:10 + --> $DIR/unresolved_type_param.rs:13:10 | LL | bar().await; | ^^^^^^ diff --git a/tests/ui/attributes/key-value-expansion.stderr b/tests/ui/attributes/key-value-expansion.stderr index 1b776322aaa..aaa8b169583 100644 --- a/tests/ui/attributes/key-value-expansion.stderr +++ b/tests/ui/attributes/key-value-expansion.stderr @@ -15,12 +15,7 @@ LL | bug!(); | = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unexpected expression: `{ - let res = - ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], - &[::core::fmt::ArgumentV1::new_display(&"u8")])); - res - }.as_str()` +error: unexpected expression: `{ let res = ::alloc::fmt::format(format_args!("{0}", "u8")); res }.as_str()` --> $DIR/key-value-expansion.rs:48:23 | LL | doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} diff --git a/tests/ui/augmented-assignments.rs b/tests/ui/augmented-assignments.rs index 20c7fb3a983..bd2435a78bf 100644 --- a/tests/ui/augmented-assignments.rs +++ b/tests/ui/augmented-assignments.rs @@ -9,7 +9,7 @@ impl AddAssign for Int { } fn main() { - let mut x = Int(1); + let mut x = Int(1); //~ NOTE binding `x` declared here x //~^ NOTE borrow of `x` occurs here += diff --git a/tests/ui/augmented-assignments.stderr b/tests/ui/augmented-assignments.stderr index 2910c910d55..d1096aea279 100644 --- a/tests/ui/augmented-assignments.stderr +++ b/tests/ui/augmented-assignments.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/augmented-assignments.rs:16:5 | +LL | let mut x = Int(1); + | ----- binding `x` declared here LL | x | - borrow of `x` occurs here ... diff --git a/tests/ui/binop/binop-move-semantics.stderr b/tests/ui/binop/binop-move-semantics.stderr index dae267da05d..8645169b98a 100644 --- a/tests/ui/binop/binop-move-semantics.stderr +++ b/tests/ui/binop/binop-move-semantics.stderr @@ -41,6 +41,8 @@ LL | fn move_then_borrow<T: Add<Output=()> + Clone + Copy>(x: T) { error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/binop-move-semantics.rs:21:5 | +LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) { + | - binding `x` declared here LL | let m = &x; | -- borrow of `x` occurs here ... @@ -53,6 +55,9 @@ LL | use_mut(n); use_imm(m); error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/binop-move-semantics.rs:23:5 | +LL | fn move_borrowed<T: Add<Output=()>>(x: T, mut y: T) { + | ----- binding `y` declared here +LL | let m = &x; LL | let n = &mut y; | ------ borrow of `y` occurs here ... diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 50eee1049db..5835f06753b 100644 --- a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -4,8 +4,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref foo @ [.., ref mut bar] => (), | -------^^^^^^^^-----------^ | | | - | | mutable borrow, by `bar`, occurs here - | immutable borrow, by `foo`, occurs here + | | value is mutably borrowed by `bar` here + | value is borrowed by `foo` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9 @@ -13,8 +13,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref foo @ Some(box ref mut s) => (), | -------^^^^^^^^^^^^---------^ | | | - | | mutable borrow, by `s`, occurs here - | immutable borrow, by `foo`, occurs here + | | value is mutably borrowed by `s` here + | value is borrowed by `foo` here error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:18:5 diff --git a/tests/ui/borrowck/borrow-tuple-fields.stderr b/tests/ui/borrowck/borrow-tuple-fields.stderr index befa751a600..d7d3efe492c 100644 --- a/tests/ui/borrowck/borrow-tuple-fields.stderr +++ b/tests/ui/borrowck/borrow-tuple-fields.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrow-tuple-fields.rs:12:13 | +LL | let x: (Box<_>, _) = (Box::new(1), 2); + | - binding `x` declared here LL | let r = &x.0; | ---- borrow of `x.0` occurs here LL | let y = x; @@ -32,6 +34,8 @@ LL | a.use_ref(); error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrow-tuple-fields.rs:28:13 | +LL | let x = Foo(Box::new(1), 2); + | - binding `x` declared here LL | let r = &x.0; | ---- borrow of `x.0` occurs here LL | let y = x; diff --git a/tests/ui/borrowck/borrowck-anon-fields-variant.stderr b/tests/ui/borrowck/borrowck-anon-fields-variant.stderr index 98f6f00a7d4..c1d668f74ef 100644 --- a/tests/ui/borrowck/borrowck-anon-fields-variant.stderr +++ b/tests/ui/borrowck/borrowck-anon-fields-variant.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `y` because it was mutably borrowed --> $DIR/borrowck-anon-fields-variant.rs:16:19 | LL | Foo::Y(ref mut a, _) => a, - | --------- borrow of `y.0` occurs here + | --------- `y.0` is borrowed here ... LL | let b = match y { | ^ use of borrowed `y.0` @@ -14,7 +14,7 @@ error[E0503]: cannot use `y` because it was mutably borrowed --> $DIR/borrowck-anon-fields-variant.rs:34:19 | LL | Foo::Y(ref mut a, _) => a, - | --------- borrow of `y.0` occurs here + | --------- `y.0` is borrowed here ... LL | let b = match y { | ^ use of borrowed `y.0` diff --git a/tests/ui/borrowck/borrowck-assign-comp.stderr b/tests/ui/borrowck/borrowck-assign-comp.stderr index 2b7cef7b325..d35f2331a76 100644 --- a/tests/ui/borrowck/borrowck-assign-comp.stderr +++ b/tests/ui/borrowck/borrowck-assign-comp.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `p.x` because it is borrowed --> $DIR/borrowck-assign-comp.rs:10:5 | LL | let q = &p; - | -- borrow of `p.x` occurs here + | -- `p.x` is borrowed here ... LL | p.x = 5; - | ^^^^^^^ assignment to borrowed `p.x` occurs here + | ^^^^^^^ `p.x` is assigned to here but it was already borrowed LL | q.x; | --- borrow later used here @@ -13,9 +13,9 @@ error[E0506]: cannot assign to `p` because it is borrowed --> $DIR/borrowck-assign-comp.rs:20:5 | LL | let q = &p.y; - | ---- borrow of `p` occurs here + | ---- `p` is borrowed here LL | p = Point {x: 5, y: 7}; - | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ `p` is assigned to here but it was already borrowed LL | p.x; // silence warning LL | *q; // stretch loan | -- borrow later used here @@ -24,9 +24,9 @@ error[E0506]: cannot assign to `p.y` because it is borrowed --> $DIR/borrowck-assign-comp.rs:31:5 | LL | let q = &p.y; - | ---- borrow of `p.y` occurs here + | ---- `p.y` is borrowed here LL | p.y = 5; - | ^^^^^^^ assignment to borrowed `p.y` occurs here + | ^^^^^^^ `p.y` is assigned to here but it was already borrowed LL | *q; | -- borrow later used here diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr index 0b21d113f74..8c0a8efcc18 100644 --- a/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `*y.pointer` because it was mutably borrowed --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 | LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `y` occurs here + | ------ `y` is borrowed here LL | *y.pointer += 1; | ^^^^^^^^^^^^^^^ use of borrowed `y` ... @@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*y.pointer` because it is borrowed --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 | LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `*y.pointer` occurs here + | ------ `*y.pointer` is borrowed here LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here + | ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed ... LL | *z.pointer += 1; | --------------- borrow later used here diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr index 371bcf2b69c..e582ec605de 100644 --- a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr +++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr @@ -1,6 +1,9 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/borrowck-bad-nested-calls-move.rs:25:9 | +LL | let mut a: Box<_> = Box::new(1); + | ----- binding `a` declared here +... LL | add( | --- borrow later used by call LL | &*a, @@ -11,6 +14,8 @@ LL | a); error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/borrowck-bad-nested-calls-move.rs:32:9 | +LL | let mut a: Box<_> = Box::new(1); + | ----- binding `a` declared here LL | add( | --- borrow later used by call LL | &*a, diff --git a/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr index fadcd11a592..8a7870e0c44 100644 --- a/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr +++ b/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr @@ -49,9 +49,9 @@ error[E0506]: cannot assign to `x` because it is borrowed LL | let c2 = || x * 5; | -- - borrow occurs due to use in closure | | - | borrow of `x` occurs here + | `x` is borrowed here LL | x = 5; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | LL | drop(c2); | -- borrow later used here @@ -62,9 +62,9 @@ error[E0506]: cannot assign to `x` because it is borrowed LL | let c1 = || get(&x); | -- - borrow occurs due to use in closure | | - | borrow of `x` occurs here + | `x` is borrowed here LL | x = 5; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | LL | drop(c1); | -- borrow later used here @@ -75,9 +75,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed LL | let c1 = || get(&*x); | -- -- borrow occurs due to use in closure | | - | borrow of `*x` occurs here + | `*x` is borrowed here LL | *x = 5; - | ^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^ `*x` is assigned to here but it was already borrowed LL | LL | drop(c1); | -- borrow later used here @@ -88,9 +88,9 @@ error[E0506]: cannot assign to `*x.f` because it is borrowed LL | let c1 = || get(&*x.f); | -- ---- borrow occurs due to use in closure | | - | borrow of `*x.f` occurs here + | `*x.f` is borrowed here LL | *x.f = 5; - | ^^^^^^^^ assignment to borrowed `*x.f` occurs here + | ^^^^^^^^ `*x.f` is assigned to here but it was already borrowed LL | LL | drop(c1); | -- borrow later used here diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.stderr b/tests/ui/borrowck/borrowck-describe-lvalue.stderr index 2c1b9c10d46..cb29c9fdac3 100644 --- a/tests/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/tests/ui/borrowck/borrowck-describe-lvalue.stderr @@ -45,7 +45,7 @@ error[E0503]: cannot use `f.x` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:37:9 | LL | let x = f.x(); - | ----- borrow of `f` occurs here + | ----- `f` is borrowed here LL | f.x; | ^^^ use of borrowed `f` LL | drop(x); @@ -55,7 +55,7 @@ error[E0503]: cannot use `g.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:44:9 | LL | let x = g.x(); - | ----- borrow of `g` occurs here + | ----- `g` is borrowed here LL | g.0; | ^^^ use of borrowed `g` LL | drop(x); @@ -65,7 +65,7 @@ error[E0503]: cannot use `h.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:51:9 | LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here + | -------- `h.0` is borrowed here LL | h.0; | ^^^ use of borrowed `h.0` LL | drop(x); @@ -75,7 +75,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:59:20 | LL | let x = e.x(); - | ----- borrow of `e` occurs here + | ----- `e` is borrowed here LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` @@ -87,7 +87,7 @@ error[E0503]: cannot use `u.a` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:67:9 | LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here + | -------- `u.a` is borrowed here LL | u.a; | ^^^ use of borrowed `u.a` LL | drop(x); @@ -97,7 +97,7 @@ error[E0503]: cannot use `f.x` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:74:9 | LL | let x = f.x(); - | ----- borrow of `*f` occurs here + | ----- `*f` is borrowed here LL | f.x; | ^^^ use of borrowed `*f` LL | drop(x); @@ -107,7 +107,7 @@ error[E0503]: cannot use `g.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:81:9 | LL | let x = g.x(); - | ----- borrow of `*g` occurs here + | ----- `*g` is borrowed here LL | g.0; | ^^^ use of borrowed `*g` LL | drop(x); @@ -117,7 +117,7 @@ error[E0503]: cannot use `h.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:88:9 | LL | let x = &mut h.0; - | -------- borrow of `h.0` occurs here + | -------- `h.0` is borrowed here LL | h.0; | ^^^ use of borrowed `h.0` LL | drop(x); @@ -127,7 +127,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:96:20 | LL | let x = e.x(); - | ----- borrow of `*e` occurs here + | ----- `*e` is borrowed here LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` @@ -139,7 +139,7 @@ error[E0503]: cannot use `u.a` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:105:9 | LL | let x = &mut u.a; - | -------- borrow of `u.a` occurs here + | -------- `u.a` is borrowed here LL | u.a; | ^^^ use of borrowed `u.a` LL | drop(x); @@ -149,7 +149,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:113:15 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here LL | match v { LL | &[x, _, .., _, _] => println!("{}", x), | ^ use of borrowed `v` @@ -161,7 +161,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:118:18 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here ... LL | &[_, x, .., _, _] => println!("{}", x), | ^ use of borrowed `v` @@ -173,7 +173,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:123:25 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here ... LL | &[_, _, .., x, _] => println!("{}", x), | ^ use of borrowed `v` @@ -185,7 +185,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:128:28 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here ... LL | &[_, _, .., _, x] => println!("{}", x), | ^ use of borrowed `v` @@ -197,7 +197,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:139:15 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here LL | match v { LL | &[x @ ..] => println!("{:?}", x), | ^ use of borrowed `v` @@ -209,7 +209,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:144:18 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here ... LL | &[_, x @ ..] => println!("{:?}", x), | ^ use of borrowed `v` @@ -221,7 +221,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:149:15 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here ... LL | &[x @ .., _] => println!("{:?}", x), | ^ use of borrowed `v` @@ -233,7 +233,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:154:18 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here ... LL | &[_, x @ .., _] => println!("{:?}", x), | ^ use of borrowed `v` @@ -245,7 +245,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:166:15 | LL | let x = &mut e; - | ------ borrow of `e` occurs here + | ------ `e` is borrowed here LL | match e { | ^ use of borrowed `e` ... @@ -304,7 +304,7 @@ error[E0503]: cannot use `*v` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:232:9 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here LL | v[0].y; | ^^^^ use of borrowed `v` ... @@ -315,7 +315,7 @@ error[E0503]: cannot use `v[_].y` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:232:9 | LL | let x = &mut v; - | ------ borrow of `v` occurs here + | ------ `v` is borrowed here LL | v[0].y; | ^^^^^^ use of borrowed `v` ... diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.stderr b/tests/ui/borrowck/borrowck-field-sensitivity.stderr index e009f5913ed..11812847dd1 100644 --- a/tests/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/tests/ui/borrowck/borrowck-field-sensitivity.stderr @@ -41,6 +41,8 @@ LL | let p = &x.b; error[E0505]: cannot move out of `x.b` because it is borrowed --> $DIR/borrowck-field-sensitivity.rs:34:10 | +LL | let x = A { a: 1, b: Box::new(2) }; + | - binding `x` declared here LL | let p = &x.b; | ---- borrow of `x.b` occurs here LL | drop(x.b); @@ -51,6 +53,8 @@ LL | drop(**p); error[E0505]: cannot move out of `x.b` because it is borrowed --> $DIR/borrowck-field-sensitivity.rs:41:14 | +LL | let x = A { a: 1, b: Box::new(2) }; + | - binding `x` declared here LL | let p = &x.b; | ---- borrow of `x.b` occurs here LL | let _y = A { a: 3, .. x }; diff --git a/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr index a66db05ccc5..1a20ec85fc0 100644 --- a/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr +++ b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `_a` because it is borrowed --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:6:9 | LL | let b = &mut _a; - | ------- borrow of `_a` occurs here + | ------- `_a` is borrowed here ... LL | _a = 4; - | ^^^^^^ assignment to borrowed `_a` occurs here + | ^^^^^^ `_a` is assigned to here but it was already borrowed ... LL | drop(b); | - borrow later used here diff --git a/tests/ui/borrowck/borrowck-issue-14498.stderr b/tests/ui/borrowck/borrowck-issue-14498.stderr index 42a55b7a854..374c5ee3ed2 100644 --- a/tests/ui/borrowck/borrowck-issue-14498.stderr +++ b/tests/ui/borrowck/borrowck-issue-14498.stderr @@ -13,10 +13,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed --> $DIR/borrowck-issue-14498.rs:25:5 | LL | let p = &y; - | -- borrow of `**y` occurs here + | -- `**y` is borrowed here LL | let q = &***p; LL | **y = 2; - | ^^^^^^^ assignment to borrowed `**y` occurs here + | ^^^^^^^ `**y` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -24,10 +24,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed --> $DIR/borrowck-issue-14498.rs:35:5 | LL | let p = &y; - | -- borrow of `**y` occurs here + | -- `**y` is borrowed here LL | let q = &***p; LL | **y = 2; - | ^^^^^^^ assignment to borrowed `**y` occurs here + | ^^^^^^^ `**y` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -35,10 +35,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed --> $DIR/borrowck-issue-14498.rs:45:5 | LL | let p = &y; - | -- borrow of `**y` occurs here + | -- `**y` is borrowed here LL | let q = &***p; LL | **y = 2; - | ^^^^^^^ assignment to borrowed `**y` occurs here + | ^^^^^^^ `**y` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -46,10 +46,10 @@ error[E0506]: cannot assign to `**y` because it is borrowed --> $DIR/borrowck-issue-14498.rs:55:5 | LL | let p = &y; - | -- borrow of `**y` occurs here + | -- `**y` is borrowed here LL | let q = &***p; LL | **y = 2; - | ^^^^^^^ assignment to borrowed `**y` occurs here + | ^^^^^^^ `**y` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -57,10 +57,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed --> $DIR/borrowck-issue-14498.rs:65:5 | LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here + | ---- `**y.a` is borrowed here LL | let q = &***p; LL | **y.a = 2; - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here + | ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -68,10 +68,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed --> $DIR/borrowck-issue-14498.rs:75:5 | LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here + | ---- `**y.a` is borrowed here LL | let q = &***p; LL | **y.a = 2; - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here + | ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -79,10 +79,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed --> $DIR/borrowck-issue-14498.rs:85:5 | LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here + | ---- `**y.a` is borrowed here LL | let q = &***p; LL | **y.a = 2; - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here + | ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here @@ -90,10 +90,10 @@ error[E0506]: cannot assign to `**y.a` because it is borrowed --> $DIR/borrowck-issue-14498.rs:95:5 | LL | let p = &y.a; - | ---- borrow of `**y.a` occurs here + | ---- `**y.a` is borrowed here LL | let q = &***p; LL | **y.a = 2; - | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here + | ^^^^^^^^^ `**y.a` is assigned to here but it was already borrowed LL | drop(p); | - borrow later used here diff --git a/tests/ui/borrowck/borrowck-lend-flow-match.stderr b/tests/ui/borrowck/borrowck-lend-flow-match.stderr index 66f1cd9bd56..6cdce7bee88 100644 --- a/tests/ui/borrowck/borrowck-lend-flow-match.stderr +++ b/tests/ui/borrowck/borrowck-lend-flow-match.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/borrowck-lend-flow-match.rs:12:13 | LL | Some(ref r) => { - | ----- borrow of `x` occurs here + | ----- `x` is borrowed here LL | x = Some(1); - | ^^^^^^^^^^^ assignment to borrowed `x` occurs here + | ^^^^^^^^^^^ `x` is assigned to here but it was already borrowed LL | drop(r); | - borrow later used here diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr index 3548da35b61..6eabfff9054 100644 --- a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr +++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move-cc.rs:14:19 | +LL | let v: Box<_> = Box::new(3); + | - binding `v` declared here LL | let w = &v; | -- borrow of `v` occurs here LL | thread::spawn(move|| { @@ -15,6 +17,8 @@ LL | w.use_ref(); error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 | +LL | let v: Box<_> = Box::new(3); + | - binding `v` declared here LL | let w = &v; | -- borrow of `v` occurs here LL | thread::spawn(move|| { diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr index b5c6b101f76..38e06fa0187 100644 --- a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr +++ b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move.rs:11:10 | +LL | let v = Box::new(3); + | - binding `v` declared here LL | let w = &v; | -- borrow of `v` occurs here LL | take(v); diff --git a/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr index 6994c837dfc..311369a260d 100644 --- a/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr +++ b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr @@ -2,12 +2,12 @@ error[E0506]: cannot assign to `*s` because it is borrowed --> $DIR/borrowck-loan-of-static-data-issue-27616.rs:16:5 | LL | let alias: &'static mut String = s; - | ------------------- - borrow of `*s` occurs here + | ------------------- - `*s` is borrowed here | | | type annotation requires that `*s` is borrowed for `'static` ... LL | *s = String::new(); - | ^^ assignment to borrowed `*s` occurs here + | ^^ `*s` is assigned to here but it was already borrowed error: aborting due to previous error diff --git a/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr index 24cc4933ef1..f1640d3b777 100644 --- a/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr +++ b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `p` because it was mutably borrowed --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:38:5 | LL | let q = &mut p; - | ------ borrow of `p` occurs here + | ------ `p` is borrowed here LL | LL | p + 3; | ^ use of borrowed `p` diff --git a/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr index 6ea6951ad96..0fdb1dabbc5 100644 --- a/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr +++ b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr @@ -1,6 +1,8 @@ error[E0597]: `z.1` does not live long enough --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:3:15 | +LL | let mut z = (0, 0); + | ----- binding `z` declared here LL | *x = Some(&mut z.1); | ----------^^^^^^^^- | | | diff --git a/tests/ui/borrowck/borrowck-match-already-borrowed.stderr b/tests/ui/borrowck/borrowck-match-already-borrowed.stderr index 39047be9de6..e5c0ec960a4 100644 --- a/tests/ui/borrowck/borrowck-match-already-borrowed.stderr +++ b/tests/ui/borrowck/borrowck-match-already-borrowed.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `foo` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:9:19 | LL | let p = &mut foo; - | -------- borrow of `foo` occurs here + | -------- `foo` is borrowed here LL | let _ = match foo { | ^^^ use of borrowed `foo` ... @@ -13,7 +13,7 @@ error[E0503]: cannot use `foo.0` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:12:16 | LL | let p = &mut foo; - | -------- borrow of `foo` occurs here + | -------- `foo` is borrowed here ... LL | Foo::A(x) => x | ^ use of borrowed `foo` @@ -25,7 +25,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:22:9 | LL | let r = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | let _ = match x { LL | x => x + 1, | ^ use of borrowed `x` @@ -37,7 +37,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:23:9 | LL | let r = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here ... LL | y => y + 2, | ^ use of borrowed `x` diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr index 8ddc48b2a99..6eaa1fa3169 100644 --- a/tests/ui/borrowck/borrowck-move-by-capture.stderr +++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr @@ -10,7 +10,7 @@ LL | let _h = to_fn_once(move || -> isize { *bar }); | | | | | variable moved due to use in closure | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait - | move out of `bar` occurs here + | `bar` is moved here error: aborting due to previous error diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr index f833abcc02a..bd94f1a4299 100644 --- a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr +++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `*a` because it is borrowed --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:13 | +LL | let a: Box<Box<_>> = Box::new(Box::new(2)); + | - binding `a` declared here LL | let b = &a; | -- borrow of `a` occurs here LL | diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr index d5ff0c501c4..cdad20c52bf 100644 --- a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr +++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `t0` because it is borrowed --> $DIR/borrowck-move-mut-base-ptr.rs:10:14 | +LL | fn foo(t0: &mut isize) { + | -- binding `t0` declared here LL | let p: &isize = &*t0; // Freezes `*t0` | ---- borrow of `*t0` occurs here LL | let t1 = t0; diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr index 8c9083fcf13..341146bd18f 100644 --- a/tests/ui/borrowck/borrowck-move-subcomponent.stderr +++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `a.x` because it is borrowed --> $DIR/borrowck-move-subcomponent.rs:15:14 | +LL | let a : S = S { x : Box::new(1) }; + | - binding `a` declared here LL | let pb = &a; | -- borrow of `a` occurs here LL | let S { x: ax } = a; diff --git a/tests/ui/borrowck/borrowck-multiple-captures.stderr b/tests/ui/borrowck/borrowck-multiple-captures.stderr index f94cbc30db4..70abe7b346e 100644 --- a/tests/ui/borrowck/borrowck-multiple-captures.stderr +++ b/tests/ui/borrowck/borrowck-multiple-captures.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `x1` because it is borrowed --> $DIR/borrowck-multiple-captures.rs:12:19 | +LL | let x1: Box<_> = Box::new(1); + | -- binding `x1` declared here LL | let p1 = &x1; | --- borrow of `x1` occurs here ... @@ -16,6 +18,8 @@ LL | borrow(&*p1); error[E0505]: cannot move out of `x2` because it is borrowed --> $DIR/borrowck-multiple-captures.rs:12:19 | +LL | let x2: Box<_> = Box::new(2); + | -- binding `x2` declared here LL | let p2 = &x2; | --- borrow of `x2` occurs here LL | thread::spawn(move|| { @@ -77,6 +81,8 @@ LL | drop(x); error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrowck-multiple-captures.rs:38:19 | +LL | let x: Box<_> = Box::new(1); + | - binding `x` declared here LL | let p = &x; | -- borrow of `x` occurs here LL | thread::spawn(move|| { diff --git a/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr index 5d52e491918..7f42becd21c 100644 --- a/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `v` because it is borrowed --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:31:5 | LL | let i = &v[0].f; - | - borrow of `v` occurs here + | - `v` is borrowed here LL | v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `v` is assigned to here but it was already borrowed LL | LL | read(*i); | -- borrow later used here diff --git a/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr index 087f2ac799e..fb7af50bcb5 100644 --- a/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr @@ -42,9 +42,9 @@ error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5 | LL | let p = &f.foo[&s]; - | ----- borrow of `f.foo` occurs here + | ----- `f.foo` is borrowed here LL | f.foo = g; - | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here + | ^^^^^^^^^ `f.foo` is assigned to here but it was already borrowed LL | p.use_ref(); | ----------- borrow later used here @@ -52,9 +52,9 @@ error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5 | LL | let p = &f.foo[&s]; - | ----- borrow of `*f` occurs here + | ----- `*f` is borrowed here LL | *f = g; - | ^^^^^^ assignment to borrowed `*f` occurs here + | ^^^^^^ `*f` is assigned to here but it was already borrowed LL | p.use_ref(); | ----------- borrow later used here @@ -62,9 +62,9 @@ error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5 | LL | let p = &mut f.foo[&s]; - | ----- borrow of `f.foo` occurs here + | ----- `f.foo` is borrowed here LL | f.foo = g; - | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here + | ^^^^^^^^^ `f.foo` is assigned to here but it was already borrowed LL | p.use_mut(); | ----------- borrow later used here @@ -72,9 +72,9 @@ error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5 | LL | let p = &mut f.foo[&s]; - | ----- borrow of `*f` occurs here + | ----- `*f` is borrowed here LL | *f = g; - | ^^^^^^ assignment to borrowed `*f` occurs here + | ^^^^^^ `*f` is assigned to here but it was already borrowed LL | p.use_mut(); | ----------- borrow later used here diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr index fb0e274c291..7f8cc74a715 100644 --- a/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr +++ b/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/borrowck-overloaded-index-move-index.rs:50:22 | +LL | let mut s = "hello".to_string(); + | ----- binding `s` declared here LL | let rs = &mut s; | ------ borrow of `s` occurs here LL | @@ -13,6 +15,8 @@ LL | use_mut(rs); error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 | +LL | let mut s = "hello".to_string(); + | ----- binding `s` declared here LL | let rs = &mut s; | ------ borrow of `s` occurs here ... diff --git a/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr b/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr index 9e65ccf5a19..b86a8693881 100644 --- a/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr +++ b/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/borrowck-pat-reassign-binding.rs:10:11 | LL | Some(ref i) => { - | ----- borrow of `x` occurs here + | ----- `x` is borrowed here LL | // But on this branch, `i` is an outstanding borrow LL | x = Some(*i+1); - | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here + | ^^^^^^^^^^^^^^ `x` is assigned to here but it was already borrowed LL | drop(i); | - borrow later used here diff --git a/tests/ui/borrowck/borrowck-unary-move.stderr b/tests/ui/borrowck/borrowck-unary-move.stderr index aab225ed4a4..f3b962059f5 100644 --- a/tests/ui/borrowck/borrowck-unary-move.stderr +++ b/tests/ui/borrowck/borrowck-unary-move.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrowck-unary-move.rs:3:10 | +LL | fn foo(x: Box<isize>) -> isize { + | - binding `x` declared here LL | let y = &*x; | --- borrow of `*x` occurs here LL | free(x); diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.stderr b/tests/ui/borrowck/borrowck-union-borrow-nested.stderr index 4bd7d54cffe..a87a14e7cab 100644 --- a/tests/ui/borrowck/borrowck-union-borrow-nested.stderr +++ b/tests/ui/borrowck/borrowck-union-borrow-nested.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `u.c` because it was mutably borrowed --> $DIR/borrowck-union-borrow-nested.rs:24:21 | LL | let ra = &mut u.s.a; - | ---------- borrow of `u.s.a` occurs here + | ---------- `u.s.a` is borrowed here LL | let b = u.c; | ^^^ use of borrowed `u.s.a` LL | ra.use_mut(); diff --git a/tests/ui/borrowck/borrowck-union-borrow.stderr b/tests/ui/borrowck/borrowck-union-borrow.stderr index 090c7b6b51a..11a28f6744b 100644 --- a/tests/ui/borrowck/borrowck-union-borrow.stderr +++ b/tests/ui/borrowck/borrowck-union-borrow.stderr @@ -12,9 +12,9 @@ error[E0506]: cannot assign to `u.a` because it is borrowed --> $DIR/borrowck-union-borrow.rs:28:13 | LL | let ra = &u.a; - | ---- borrow of `u.a` occurs here + | ---- `u.a` is borrowed here LL | u.a = 1; - | ^^^^^^^ assignment to borrowed `u.a` occurs here + | ^^^^^^^ `u.a` is assigned to here but it was already borrowed LL | drop(ra); | -- borrow later used here @@ -34,9 +34,9 @@ error[E0506]: cannot assign to `u.b` because it is borrowed --> $DIR/borrowck-union-borrow.rs:49:13 | LL | let ra = &u.a; - | ---- borrow of `u.b` occurs here + | ---- `u.b` is borrowed here LL | u.b = 1; - | ^^^^^^^ assignment to borrowed `u.b` occurs here + | ^^^^^^^ `u.b` is assigned to here but it was already borrowed LL | drop(ra); | -- borrow later used here @@ -54,7 +54,7 @@ error[E0503]: cannot use `u.a` because it was mutably borrowed --> $DIR/borrowck-union-borrow.rs:60:21 | LL | let ra = &mut u.a; - | -------- borrow of `u.a` occurs here + | -------- `u.a` is borrowed here LL | let a = u.a; | ^^^ use of borrowed `u.a` LL | drop(ra); @@ -74,9 +74,9 @@ error[E0506]: cannot assign to `u.a` because it is borrowed --> $DIR/borrowck-union-borrow.rs:70:13 | LL | let rma = &mut u.a; - | -------- borrow of `u.a` occurs here + | -------- `u.a` is borrowed here LL | u.a = 1; - | ^^^^^^^ assignment to borrowed `u.a` occurs here + | ^^^^^^^ `u.a` is assigned to here but it was already borrowed LL | drop(rma); | --- borrow later used here @@ -96,7 +96,7 @@ error[E0503]: cannot use `u.b` because it was mutably borrowed --> $DIR/borrowck-union-borrow.rs:81:21 | LL | let ra = &mut u.a; - | -------- borrow of `u.a` occurs here + | -------- `u.a` is borrowed here LL | let b = u.b; | ^^^ use of borrowed `u.a` LL | @@ -119,9 +119,9 @@ error[E0506]: cannot assign to `u.b` because it is borrowed --> $DIR/borrowck-union-borrow.rs:92:13 | LL | let rma = &mut u.a; - | -------- borrow of `u.b` occurs here + | -------- `u.b` is borrowed here LL | u.b = 1; - | ^^^^^^^ assignment to borrowed `u.b` occurs here + | ^^^^^^^ `u.b` is assigned to here but it was already borrowed LL | drop(rma); | --- borrow later used here diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow.stderr b/tests/ui/borrowck/borrowck-use-mut-borrow.stderr index 91d69c51e81..4d300ae3c52 100644 --- a/tests/ui/borrowck/borrowck-use-mut-borrow.stderr +++ b/tests/ui/borrowck/borrowck-use-mut-borrow.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:11:10 | LL | let p = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | drop(x); | ^ use of borrowed `x` LL | *p = 2; @@ -12,7 +12,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:18:10 | LL | let p = &mut x.a; - | -------- borrow of `x.a` occurs here + | -------- `x.a` is borrowed here LL | drop(x); | ^ use of borrowed `x.a` LL | *p = 3; @@ -22,7 +22,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:25:10 | LL | let p = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | drop(x.a); | ^^^ use of borrowed `x` LL | p.a = 3; @@ -32,7 +32,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:32:10 | LL | let p = &mut x.a; - | -------- borrow of `x.a` occurs here + | -------- `x.a` is borrowed here LL | drop(x.a); | ^^^ use of borrowed `x.a` LL | *p = 3; @@ -42,7 +42,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:39:13 | LL | let p = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | let y = A { b: 3, .. x }; | ^^^^^^^^^^^^^^^^ use of borrowed `x` LL | drop(y); @@ -53,7 +53,7 @@ error[E0503]: cannot use `x.a` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:47:13 | LL | let p = &mut x.a; - | -------- borrow of `x.a` occurs here + | -------- `x.a` is borrowed here LL | let y = A { b: 3, .. x }; | ^^^^^^^^^^^^^^^^ use of borrowed `x.a` LL | drop(y); @@ -64,7 +64,7 @@ error[E0503]: cannot use `*x` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:55:10 | LL | let p = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | drop(*x); | ^^ use of borrowed `x` LL | **p = 2; @@ -74,7 +74,7 @@ error[E0503]: cannot use `*x.b` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:62:10 | LL | let p = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | drop(*x.b); | ^^^^ use of borrowed `x` LL | p.a = 3; @@ -84,7 +84,7 @@ error[E0503]: cannot use `*x.b` because it was mutably borrowed --> $DIR/borrowck-use-mut-borrow.rs:69:10 | LL | let p = &mut x.b; - | -------- borrow of `x.b` occurs here + | -------- `x.b` is borrowed here LL | drop(*x.b); | ^^^^ use of borrowed `x.b` LL | **p = 3; diff --git a/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr index 0ac7df944d7..494d8c351a1 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr +++ b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5 | LL | [1, 2, ref tail @ ..] => tail, - | -------- borrow of `a[_]` occurs here + | -------- `a[_]` is borrowed here ... LL | a[2] = 0; - | ^^^^^^^^ assignment to borrowed `a[_]` occurs here + | ^^^^^^^^ `a[_]` is assigned to here but it was already borrowed LL | println!("t[0]: {}", t[0]); | ---- borrow later used here diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs index 0e9284a2cad..1bda7a49713 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -5,9 +5,9 @@ fn a() { let mut vec = [Box::new(1), Box::new(2), Box::new(3)]; match vec { [box ref _a, _, _] => { - //~^ NOTE borrow of `vec[_]` occurs here + //~^ NOTE `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign - //~^ NOTE assignment to borrowed `vec[_]` occurs here + //~^ NOTE `vec[_]` is assigned to here _a.use_ref(); //~^ NOTE borrow later used here } @@ -19,9 +19,9 @@ fn b() { let vec: &mut [Box<isize>] = &mut vec; match vec { &mut [ref _b @ ..] => { - //~^ borrow of `vec[_]` occurs here + //~^ `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign - //~^ NOTE assignment to borrowed `vec[_]` occurs here + //~^ NOTE `vec[_]` is assigned to here _b.use_ref(); //~^ NOTE borrow later used here } diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 0dc5e64e4ff..70b9e4f4433 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:9:13 | LL | [box ref _a, _, _] => { - | ------ borrow of `vec[_]` occurs here + | ------ `vec[_]` is borrowed here LL | LL | vec[0] = Box::new(4); - | ^^^^^^ assignment to borrowed `vec[_]` occurs here + | ^^^^^^ `vec[_]` is assigned to here but it was already borrowed LL | LL | _a.use_ref(); | ------------ borrow later used here @@ -14,10 +14,10 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 | LL | &mut [ref _b @ ..] => { - | ------ borrow of `vec[_]` occurs here + | ------ `vec[_]` is borrowed here LL | LL | vec[0] = Box::new(4); - | ^^^^^^ assignment to borrowed `vec[_]` occurs here + | ^^^^^^ `vec[_]` is assigned to here but it was already borrowed LL | LL | _b.use_ref(); | ------------ borrow later used here diff --git a/tests/ui/borrowck/issue-25793.stderr b/tests/ui/borrowck/issue-25793.stderr index da3412f112d..27dab53e48f 100644 --- a/tests/ui/borrowck/issue-25793.stderr +++ b/tests/ui/borrowck/issue-25793.stderr @@ -5,7 +5,7 @@ LL | $this.width.unwrap() | ^^^^^^^^^^^ use of borrowed `*self` ... LL | let r = &mut *self; - | ---------- borrow of `*self` occurs here + | ---------- `*self` is borrowed here LL | r.get_size(width!(self)) | -------- ------------ in this macro invocation | | diff --git a/tests/ui/borrowck/issue-52713-bug.stderr b/tests/ui/borrowck/issue-52713-bug.stderr index 4abb6fb2c71..3f7715645e6 100644 --- a/tests/ui/borrowck/issue-52713-bug.stderr +++ b/tests/ui/borrowck/issue-52713-bug.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/issue-52713-bug.rs:12:5 | LL | let y = &x; - | -- borrow of `x` occurs here + | -- `x` is borrowed here ... LL | x += 1; - | ^^^^^^ assignment to borrowed `x` occurs here + | ^^^^^^ `x` is assigned to here but it was already borrowed LL | println!("{}", y); | - borrow later used here diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr index 57803247ba8..0870b423769 100644 --- a/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr +++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr @@ -4,10 +4,10 @@ error[E0506]: cannot assign to `greeting` because it is borrowed LL | let res = (|| (|| &greeting)())(); | -- -------- borrow occurs due to use in closure | | - | borrow of `greeting` occurs here + | `greeting` is borrowed here LL | LL | greeting = "DEALLOCATED".to_string(); - | ^^^^^^^^ assignment to borrowed `greeting` occurs here + | ^^^^^^^^ `greeting` is assigned to here but it was already borrowed ... LL | println!("thread result: {:?}", res); | --- borrow later used here diff --git a/tests/ui/borrowck/issue-81365-1.stderr b/tests/ui/borrowck/issue-81365-1.stderr index d79394834dc..0d803b0427a 100644 --- a/tests/ui/borrowck/issue-81365-1.stderr +++ b/tests/ui/borrowck/issue-81365-1.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-1.rs:21:9 | LL | let first = &self.target_field; - | ---- borrow of `self.container_field` occurs here + | ---- `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-10.stderr b/tests/ui/borrowck/issue-81365-10.stderr index 27123ef2be1..d0986e9f922 100644 --- a/tests/ui/borrowck/issue-81365-10.stderr +++ b/tests/ui/borrowck/issue-81365-10.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-10.rs:21:9 | LL | let first = &self.deref().target_field; - | ------------ borrow of `self.container_field` occurs here + | ------------ `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here diff --git a/tests/ui/borrowck/issue-81365-11.stderr b/tests/ui/borrowck/issue-81365-11.stderr index 0770c136632..5f7e86f11dc 100644 --- a/tests/ui/borrowck/issue-81365-11.stderr +++ b/tests/ui/borrowck/issue-81365-11.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-11.rs:27:9 | LL | let first = &mut self.target_field; - | ---- borrow of `self.container_field` occurs here + | ---- `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here diff --git a/tests/ui/borrowck/issue-81365-2.stderr b/tests/ui/borrowck/issue-81365-2.stderr index 764eaaa7cc7..d9aeaf15f20 100644 --- a/tests/ui/borrowck/issue-81365-2.stderr +++ b/tests/ui/borrowck/issue-81365-2.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container.container_field` because it is bo --> $DIR/issue-81365-2.rs:25:9 | LL | let first = &self.container.target_field; - | -------------- borrow of `self.container.container_field` occurs here + | -------------- `self.container.container_field` is borrowed here LL | self.container.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-3.stderr b/tests/ui/borrowck/issue-81365-3.stderr index 9447174fd21..0c0d1994baf 100644 --- a/tests/ui/borrowck/issue-81365-3.stderr +++ b/tests/ui/borrowck/issue-81365-3.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container.container_field` because it is bo --> $DIR/issue-81365-3.rs:32:9 | LL | let first = &self.target_field; - | ---- borrow of `self.container.container_field` occurs here + | ---- `self.container.container_field` is borrowed here LL | self.container.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-4.stderr b/tests/ui/borrowck/issue-81365-4.stderr index 0ab3fa92706..98093daa945 100644 --- a/tests/ui/borrowck/issue-81365-4.stderr +++ b/tests/ui/borrowck/issue-81365-4.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.outer_field` because it is borrowed --> $DIR/issue-81365-4.rs:33:9 | LL | let first = &self.target_field; - | ---- borrow of `self.outer_field` occurs here + | ---- `self.outer_field` is borrowed here LL | self.outer_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^ `self.outer_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-5.stderr b/tests/ui/borrowck/issue-81365-5.stderr index 20ff229ffe7..c00e48288ba 100644 --- a/tests/ui/borrowck/issue-81365-5.stderr +++ b/tests/ui/borrowck/issue-81365-5.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-5.rs:28:9 | LL | let first = self.get(); - | ---------- borrow of `self.container_field` occurs here + | ---------- `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-6.stderr b/tests/ui/borrowck/issue-81365-6.stderr index 575aed73b46..e61dc95ecc8 100644 --- a/tests/ui/borrowck/issue-81365-6.stderr +++ b/tests/ui/borrowck/issue-81365-6.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-6.rs:18:9 | LL | let first = &self[0]; - | ---- borrow of `self.container_field` occurs here + | ---- `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-7.stderr b/tests/ui/borrowck/issue-81365-7.stderr index 52d2d9e75a9..0565127e387 100644 --- a/tests/ui/borrowck/issue-81365-7.stderr +++ b/tests/ui/borrowck/issue-81365-7.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `c.container_field` because it is borrowed --> $DIR/issue-81365-7.rs:20:5 | LL | let first = &c.target_field; - | - borrow of `c.container_field` occurs here + | - `c.container_field` is borrowed here LL | c.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^ `c.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-8.stderr b/tests/ui/borrowck/issue-81365-8.stderr index fd83e10a295..0ca732ff2ae 100644 --- a/tests/ui/borrowck/issue-81365-8.stderr +++ b/tests/ui/borrowck/issue-81365-8.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-8.rs:21:9 | LL | let first = &(*self).target_field; - | ------- borrow of `self.container_field` occurs here + | ------- `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here | diff --git a/tests/ui/borrowck/issue-81365-9.stderr b/tests/ui/borrowck/issue-81365-9.stderr index c7d48214fd4..4d305268a0b 100644 --- a/tests/ui/borrowck/issue-81365-9.stderr +++ b/tests/ui/borrowck/issue-81365-9.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `self.container_field` because it is borrowed --> $DIR/issue-81365-9.rs:21:9 | LL | let first = &Deref::deref(self).target_field; - | ---- borrow of `self.container_field` occurs here + | ---- `self.container_field` is borrowed here LL | self.container_field = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.container_field` is assigned to here but it was already borrowed LL | first; | ----- borrow later used here diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr index a57ceb84739..1356c80493c 100644 --- a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr +++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `i` because it was mutably borrowed --> $DIR/two-phase-allow-access-during-reservation.rs:26:19 | LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) - | ------ borrow of `i` occurs here + | ------ `i` is borrowed here LL | LL | /*2*/ let j = i; // OK: `i` is only reserved here | ^ use of borrowed `i` @@ -14,7 +14,7 @@ error[E0503]: cannot use `i` because it was mutably borrowed --> $DIR/two-phase-allow-access-during-reservation.rs:31:19 | LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) - | ------ borrow of `i` occurs here + | ------ `i` is borrowed here ... LL | /*4*/ let k = i; | ^ use of borrowed `i` diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr index 5a240d90011..e75094d4f13 100644 --- a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr +++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `self.cx` because it was mutably borrowed --> $DIR/two-phase-surprise-no-conflict.rs:21:23 | LL | let _mut_borrow = &mut *self; - | ---------- borrow of `*self` occurs here + | ---------- `*self` is borrowed here LL | let _access = self.cx; | ^^^^^^^ use of borrowed `*self` LL | diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr index e8a6ad0995a..5140b58934a 100644 --- a/tests/ui/box/leak-alloc.stderr +++ b/tests/ui/box/leak-alloc.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `alloc` because it is borrowed --> $DIR/leak-alloc.rs:26:10 | +LL | let alloc = Alloc {}; + | ----- binding `alloc` declared here LL | let boxed = Box::new_in(10, alloc.by_ref()); | -------------- borrow of `alloc` occurs here LL | let theref = Box::leak(boxed); diff --git a/tests/ui/btreemap/btreemap_dropck.stderr b/tests/ui/btreemap/btreemap_dropck.stderr index e953e7ae82b..d405e465aae 100644 --- a/tests/ui/btreemap/btreemap_dropck.stderr +++ b/tests/ui/btreemap/btreemap_dropck.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/btreemap_dropck.rs:15:10 | +LL | let s = String::from("Hello World!"); + | - binding `s` declared here LL | let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]); | -- borrow of `s` occurs here LL | drop(s); diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index 6f8e53298ac..c9d90d73dea 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -107,7 +107,9 @@ error[E0597]: `ap1` does not live long enough --> $DIR/variadic-ffi-4.rs:28:11 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | - let's call the lifetime of this reference `'3` + | - ------- binding `ap1` declared here + | | + | let's call the lifetime of this reference `'3` LL | ap0 = &mut ap1; | ------^^^^^^^^ | | | diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr index 4f41060dc98..9e5200ef34b 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `arr` because it was mutably borrowed --> $DIR/arrays.rs:14:5 | LL | let mut c = || { - | -- borrow of `arr` occurs here + | -- `arr` is borrowed here LL | arr[0] += 10; | --- borrow occurs due to use of `arr` in closure ... @@ -16,7 +16,7 @@ error[E0503]: cannot use `arr[_]` because it was mutably borrowed --> $DIR/arrays.rs:14:5 | LL | let mut c = || { - | -- borrow of `arr` occurs here + | -- `arr` is borrowed here LL | arr[0] += 10; | --- borrow occurs due to use of `arr` in closure ... @@ -30,12 +30,12 @@ error[E0506]: cannot assign to `arr[_]` because it is borrowed --> $DIR/arrays.rs:29:5 | LL | let c = || { - | -- borrow of `arr[_]` occurs here + | -- `arr[_]` is borrowed here LL | println!("{:#?}", &arr[3..4]); | --- borrow occurs due to use in closure ... LL | arr[1] += 10; - | ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here + | ^^^^^^^^^^^^ `arr[_]` is assigned to here but it was already borrowed LL | LL | c(); | - borrow later used here @@ -44,12 +44,12 @@ error[E0506]: cannot assign to `arr[_]` because it is borrowed --> $DIR/arrays.rs:43:5 | LL | let c = || { - | -- borrow of `arr[_]` occurs here + | -- `arr[_]` is borrowed here LL | println!("{}", arr[3]); | --- borrow occurs due to use in closure ... LL | arr[1] += 10; - | ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here + | ^^^^^^^^^^^^ `arr[_]` is assigned to here but it was already borrowed LL | LL | c(); | - borrow later used here @@ -58,7 +58,7 @@ error[E0503]: cannot use `arr` because it was mutably borrowed --> $DIR/arrays.rs:57:20 | LL | let mut c = || { - | -- borrow of `arr` occurs here + | -- `arr` is borrowed here LL | arr[1] += 10; | --- borrow occurs due to use of `arr` in closure ... diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr index f8b17875235..2e3259e6405 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -2,12 +2,12 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed --> $DIR/box.rs:21:5 | LL | let mut c = || { - | -- borrow of `e.0.0.m.x` occurs here + | -- `e.0.0.m.x` is borrowed here LL | e.0.0.m.x = format!("not-x"); | --------- borrow occurs due to use in closure ... LL | e.0.0.m.x = format!("not-x"); - | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here + | ^^^^^^^^^ `e.0.0.m.x` is assigned to here but it was already borrowed LL | LL | c(); | - borrow later used here @@ -32,12 +32,12 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed --> $DIR/box.rs:55:5 | LL | let c = || { - | -- borrow of `e.0.0.m.x` occurs here + | -- `e.0.0.m.x` is borrowed here LL | println!("{}", e.0.0.m.x); | --------- borrow occurs due to use in closure ... LL | e.0.0.m.x = format!("not-x"); - | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here + | ^^^^^^^^^ `e.0.0.m.x` is assigned to here but it was already borrowed LL | LL | c(); | - borrow later used here diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs index 46b54846e32..695337ea82c 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/union.rs @@ -11,7 +11,7 @@ union A { fn main() { let mut a = A { y: 1 }; let mut c = || { - //~^ borrow of `a.y` occurs here + //~^ `a.y` is borrowed here let _ = unsafe { &a.y }; let _ = &mut a; //~^ borrow occurs due to use in closure @@ -19,7 +19,7 @@ fn main() { }; a.y = 1; //~^ cannot assign to `a.y` because it is borrowed [E0506] - //~| assignment to borrowed `a.y` occurs here + //~| `a.y` is assigned to here c(); //~^ borrow later used here } diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/union.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/union.stderr index 7c34e2336c8..17834e61236 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/union.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/union.stderr @@ -2,13 +2,13 @@ error[E0506]: cannot assign to `a.y` because it is borrowed --> $DIR/union.rs:20:5 | LL | let mut c = || { - | -- borrow of `a.y` occurs here + | -- `a.y` is borrowed here ... LL | let _ = &mut a; | - borrow occurs due to use in closure ... LL | a.y = 1; - | ^^^^^^^ assignment to borrowed `a.y` occurs here + | ^^^^^^^ `a.y` is assigned to here but it was already borrowed ... LL | c(); | - borrow later used here diff --git a/tests/ui/coercion/coerce-overloaded-autoderef-fail.stderr b/tests/ui/coercion/coerce-overloaded-autoderef-fail.stderr index d067c3b3a18..d412b8b08b7 100644 --- a/tests/ui/coercion/coerce-overloaded-autoderef-fail.stderr +++ b/tests/ui/coercion/coerce-overloaded-autoderef-fail.stderr @@ -13,10 +13,10 @@ error[E0506]: cannot assign to `**x` because it is borrowed --> $DIR/coerce-overloaded-autoderef-fail.rs:17:5 | LL | let y = borrow(x); - | - borrow of `**x` occurs here + | - `**x` is borrowed here LL | let z = borrow(x); LL | **x += 1; - | ^^^^^^^^ assignment to borrowed `**x` occurs here + | ^^^^^^^^ `**x` is assigned to here but it was already borrowed LL | LL | drop((y, z)); | - borrow later used here diff --git a/tests/ui/const-generics/bad-const-generic-exprs.rs b/tests/ui/const-generics/bad-const-generic-exprs.rs index ca91643edf7..423752ca25e 100644 --- a/tests/ui/const-generics/bad-const-generic-exprs.rs +++ b/tests/ui/const-generics/bad-const-generic-exprs.rs @@ -13,10 +13,34 @@ fn main() { let _: Wow<A.0>; //~^ ERROR expected one of //~| HELP expressions must be enclosed in braces to be used as const generic arguments - - // FIXME(compiler-errors): This one is still unsatisfying, - // and probably a case I could see someone typing by accident.. + let _: Wow<[]>; + //~^ ERROR expected type + //~| HELP expressions must be enclosed in braces to be used as const generic arguments let _: Wow<[12]>; - //~^ ERROR expected type, found - //~| ERROR type provided when a constant was expected + //~^ ERROR expected type + //~| ERROR invalid const generic expression + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + let _: Wow<[0, 1, 3]>; + //~^ ERROR expected type + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + let _: Wow<[0xff; 8]>; + //~^ ERROR expected type + //~| ERROR invalid const generic expression + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + let _: Wow<[1, 2]>; // Regression test for issue #81698. + //~^ ERROR expected type + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + let _: Wow<&0>; + //~^ ERROR expected type + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + let _: Wow<("", 0)>; + //~^ ERROR expected type + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + let _: Wow<(1 + 2) * 3>; + //~^ ERROR expected type + //~| HELP expressions must be enclosed in braces to be used as const generic arguments + // FIXME(fmease): This one is pretty bad. + let _: Wow<!0>; + //~^ ERROR expected one of + //~| HELP you might have meant to end the type parameters here } diff --git a/tests/ui/const-generics/bad-const-generic-exprs.stderr b/tests/ui/const-generics/bad-const-generic-exprs.stderr index 24668b08b8a..17a63a96fe4 100644 --- a/tests/ui/const-generics/bad-const-generic-exprs.stderr +++ b/tests/ui/const-generics/bad-const-generic-exprs.stderr @@ -42,18 +42,118 @@ help: expressions must be enclosed in braces to be used as const generic argumen LL | let _: Wow<{ A.0 }>; | + + +error: expected type, found `]` + --> $DIR/bad-const-generic-exprs.rs:16:17 + | +LL | let _: Wow<[]>; + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ [] }>; + | + + + error: expected type, found `12` --> $DIR/bad-const-generic-exprs.rs:19:17 | LL | let _: Wow<[12]>; | ^^ expected type -error[E0747]: type provided when a constant was expected +error: invalid const generic expression --> $DIR/bad-const-generic-exprs.rs:19:16 | LL | let _: Wow<[12]>; | ^^^^ + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ [12] }>; + | + + + +error: expected type, found `0` + --> $DIR/bad-const-generic-exprs.rs:23:17 + | +LL | let _: Wow<[0, 1, 3]>; + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ [0, 1, 3] }>; + | + + + +error: expected type, found `0xff` + --> $DIR/bad-const-generic-exprs.rs:26:17 + | +LL | let _: Wow<[0xff; 8]>; + | ^^^^ expected type + +error: invalid const generic expression + --> $DIR/bad-const-generic-exprs.rs:26:16 + | +LL | let _: Wow<[0xff; 8]>; + | ^^^^^^^^^ + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ [0xff; 8] }>; + | + + + +error: expected type, found `1` + --> $DIR/bad-const-generic-exprs.rs:30:17 + | +LL | let _: Wow<[1, 2]>; // Regression test for issue #81698. + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ [1, 2] }>; // Regression test for issue #81698. + | + + + +error: expected type, found `0` + --> $DIR/bad-const-generic-exprs.rs:33:17 + | +LL | let _: Wow<&0>; + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ &0 }>; + | + + + +error: expected type, found `""` + --> $DIR/bad-const-generic-exprs.rs:36:17 + | +LL | let _: Wow<("", 0)>; + | ^^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ ("", 0) }>; + | + + + +error: expected type, found `1` + --> $DIR/bad-const-generic-exprs.rs:39:17 + | +LL | let _: Wow<(1 + 2) * 3>; + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | let _: Wow<{ (1 + 2) * 3 }>; + | + + + +error: expected one of `,` or `>`, found `0` + --> $DIR/bad-const-generic-exprs.rs:43:17 + | +LL | let _: Wow<!0>; + | - ^ expected one of `,` or `>` + | | + | while parsing the type for `_` + | +help: you might have meant to end the type parameters here + | +LL | let _: Wow<!>0>; + | + -error: aborting due to 6 previous errors +error: aborting due to 15 previous errors -For more information about this error, try `rustc --explain E0747`. diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr index 9f73b91aabe..cc629fd920f 100644 --- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr +++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr @@ -8,7 +8,7 @@ LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> { | in this macro invocation ... LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type + | ^ expected type | = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -22,26 +22,21 @@ LL | Example::<gimme_a_const!(marker)> | in this macro invocation ... LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type + | ^ expected type | = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected type, found `{` --> $DIR/macro-fail.rs:4:10 | -LL | () => {{ - | __________^ -LL | | -LL | | const X: usize = 1337; -LL | | X -LL | | }} - | |___^ expected type +LL | () => {{ + | ^ expected type ... -LL | let _fail = Example::<external_macro!()>; - | ----------------- - | | - | this macro call doesn't expand to a type - | in this macro invocation +LL | let _fail = Example::<external_macro!()>; + | ----------------- + | | + | this macro call doesn't expand to a type + | in this macro invocation | = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/consts/const-eval/infinite_loop.stderr b/tests/ui/consts/const-eval/infinite_loop.stderr index 8b58cb279f3..f30bfaf3f95 100644 --- a/tests/ui/consts/const-eval/infinite_loop.stderr +++ b/tests/ui/consts/const-eval/infinite_loop.stderr @@ -1,8 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/infinite_loop.rs:6:15 + --> $DIR/infinite_loop.rs:6:9 | -LL | while n != 0 { - | ^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) +LL | / while n != 0 { +LL | | +LL | | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; +LL | | } + | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`) error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/issue-52475.rs b/tests/ui/consts/const-eval/issue-52475.rs index ce65407bbab..307c1a66834 100644 --- a/tests/ui/consts/const-eval/issue-52475.rs +++ b/tests/ui/consts/const-eval/issue-52475.rs @@ -2,8 +2,8 @@ fn main() { let _ = [(); { let mut x = &0; let mut n = 0; - while n < 5 { - n = (n + 1) % 5; //~ ERROR evaluation of constant value failed + while n < 5 { //~ ERROR evaluation of constant value failed [E0080] + n = (n + 1) % 5; x = &0; // Materialize a new AllocId } 0 diff --git a/tests/ui/consts/const-eval/issue-52475.stderr b/tests/ui/consts/const-eval/issue-52475.stderr index 8536ff02c6d..3aa6bd277dd 100644 --- a/tests/ui/consts/const-eval/issue-52475.stderr +++ b/tests/ui/consts/const-eval/issue-52475.stderr @@ -1,8 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/issue-52475.rs:6:17 + --> $DIR/issue-52475.rs:5:9 | -LL | n = (n + 1) % 5; - | ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) +LL | / while n < 5 { +LL | | n = (n + 1) % 5; +LL | | x = &0; // Materialize a new AllocId +LL | | } + | |_________^ exceeded interpreter step limit (see `#[const_eval_limit]`) error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs new file mode 100644 index 00000000000..c59596238e1 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.rs @@ -0,0 +1,36 @@ +// check-fail +// compile-flags: -Z tiny-const-eval-limit + +const fn foo() {} + +const fn call_foo() -> u32 { + foo(); + foo(); + foo(); + foo(); + foo(); + + foo(); + foo(); + foo(); + foo(); + foo(); + + foo(); + foo(); + foo(); + foo(); + foo(); + + foo(); + foo(); + foo(); + foo(); //~ ERROR evaluation of constant value failed [E0080] + 0 +} + +const X: u32 = call_foo(); + +fn main() { + println!("{X}"); +} diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr new file mode 100644 index 00000000000..ed70975af34 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-fn-call.stderr @@ -0,0 +1,20 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ctfe-fn-call.rs:28:5 + | +LL | foo(); + | ^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + | +note: inside `call_foo` + --> $DIR/ctfe-fn-call.rs:28:5 + | +LL | foo(); + | ^^^^^ +note: inside `X` + --> $DIR/ctfe-fn-call.rs:32:16 + | +LL | const X: u32 = call_foo(); + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs new file mode 100644 index 00000000000..c10b8d83791 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.rs @@ -0,0 +1,19 @@ +// check-fail +// compile-flags: -Z tiny-const-eval-limit + +const fn labelled_loop(n: u32) -> u32 { + let mut i = 0; + 'mylabel: loop { //~ ERROR evaluation of constant value failed [E0080] + if i > n { + break 'mylabel + } + i += 1; + } + 0 +} + +const X: u32 = labelled_loop(19); + +fn main() { + println!("{X}"); +} diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr new file mode 100644 index 00000000000..d9404edd5b1 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-labelled-loop.stderr @@ -0,0 +1,30 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ctfe-labelled-loop.rs:6:5 + | +LL | / 'mylabel: loop { +LL | | if i > n { +LL | | break 'mylabel +LL | | } +LL | | i += 1; +LL | | } + | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`) + | +note: inside `labelled_loop` + --> $DIR/ctfe-labelled-loop.rs:6:5 + | +LL | / 'mylabel: loop { +LL | | if i > n { +LL | | break 'mylabel +LL | | } +LL | | i += 1; +LL | | } + | |_____^ +note: inside `X` + --> $DIR/ctfe-labelled-loop.rs:15:16 + | +LL | const X: u32 = labelled_loop(19); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs new file mode 100644 index 00000000000..80ff835f3e8 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.rs @@ -0,0 +1,16 @@ +// check-fail +// compile-flags: -Z tiny-const-eval-limit + +const fn recurse(n: u32) -> u32 { + if n == 0 { + n + } else { + recurse(n - 1) //~ ERROR evaluation of constant value failed [E0080] + } +} + +const X: u32 = recurse(19); + +fn main() { + println!("{X}"); +} diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr new file mode 100644 index 00000000000..ed9a3111942 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-recursion.stderr @@ -0,0 +1,25 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ctfe-recursion.rs:8:9 + | +LL | recurse(n - 1) + | ^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + | +note: inside `recurse` + --> $DIR/ctfe-recursion.rs:8:9 + | +LL | recurse(n - 1) + | ^^^^^^^^^^^^^^ +note: [... 18 additional calls inside `recurse` ...] + --> $DIR/ctfe-recursion.rs:8:9 + | +LL | recurse(n - 1) + | ^^^^^^^^^^^^^^ +note: inside `X` + --> $DIR/ctfe-recursion.rs:12:16 + | +LL | const X: u32 = recurse(19); + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs new file mode 100644 index 00000000000..ca0eec93c5d --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs @@ -0,0 +1,15 @@ +// check-fail +// compile-flags: -Z tiny-const-eval-limit +const fn simple_loop(n: u32) -> u32 { + let mut index = 0; + while index < n { //~ ERROR evaluation of constant value failed [E0080] + index = index + 1; + } + 0 +} + +const X: u32 = simple_loop(19); + +fn main() { + println!("{X}"); +} diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr new file mode 100644 index 00000000000..83ff275de70 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.stderr @@ -0,0 +1,24 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ctfe-simple-loop.rs:5:5 + | +LL | / while index < n { +LL | | index = index + 1; +LL | | } + | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`) + | +note: inside `simple_loop` + --> $DIR/ctfe-simple-loop.rs:5:5 + | +LL | / while index < n { +LL | | index = index + 1; +LL | | } + | |_____^ +note: inside `X` + --> $DIR/ctfe-simple-loop.rs:11:16 + | +LL | const X: u32 = simple_loop(19); + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs b/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs new file mode 100644 index 00000000000..0b0f361809f --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/dominators-edge-case.rs @@ -0,0 +1,19 @@ +// check-pass +// +// Exercising an edge case which was found during Stage 2 compilation. +// Compilation would fail for this code when running the `CtfeLimit` +// MirPass (specifically when looking up the dominators). +#![crate_type="lib"] + +const DUMMY: Expr = Expr::Path(ExprPath { + attrs: Vec::new(), + path: Vec::new(), +}); + +pub enum Expr { + Path(ExprPath), +} +pub struct ExprPath { + pub attrs: Vec<()>, + pub path: Vec<()>, +} diff --git a/tests/ui/consts/const_limit/const_eval_limit_reached.stderr b/tests/ui/consts/const_limit/const_eval_limit_reached.stderr index 850aebdfb2a..a8e8ae9bb08 100644 --- a/tests/ui/consts/const_limit/const_eval_limit_reached.stderr +++ b/tests/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -1,8 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_eval_limit_reached.rs:6:11 + --> $DIR/const_eval_limit_reached.rs:6:5 | -LL | while x != 1000 { - | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) +LL | / while x != 1000 { +LL | | +LL | | x += 1; +LL | | } + | |_____^ exceeded interpreter step limit (see `#[const_eval_limit]`) error: aborting due to previous error diff --git a/tests/ui/consts/promote_const_let.stderr b/tests/ui/consts/promote_const_let.stderr index 975a235a649..6e0349a4773 100644 --- a/tests/ui/consts/promote_const_let.stderr +++ b/tests/ui/consts/promote_const_let.stderr @@ -4,6 +4,7 @@ error[E0597]: `y` does not live long enough LL | let x: &'static u32 = { | ------------ type annotation requires that `y` is borrowed for `'static` LL | let y = 42; + | - binding `y` declared here LL | &y | ^^ borrowed value does not live long enough LL | }; diff --git a/tests/ui/derives/deriving-with-repr-packed-2.rs b/tests/ui/derives/deriving-with-repr-packed-2.rs new file mode 100644 index 00000000000..cbd7432fce4 --- /dev/null +++ b/tests/ui/derives/deriving-with-repr-packed-2.rs @@ -0,0 +1,22 @@ +#![deny(unaligned_references)] + +// Check that deriving certain builtin traits on certain packed structs cause +// errors. To avoid potentially misaligned references, field copies must be +// used, which involves adding `T: Copy` bounds. + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +#[repr(packed)] +pub struct Foo<T>(T, T, T); + +struct NonCopy; + +fn main() { + // This one is fine because `u32` impls `Copy`. + let x: Foo<u32> = Foo(1, 2, 3); + _ = x.clone(); + + // This one is an error because `NonCopy` doesn't impl `Copy`. + let x: Foo<NonCopy> = Foo(NonCopy, NonCopy, NonCopy); + _ = x.clone(); + //~^ ERROR the method `clone` exists for struct `Foo<NonCopy>`, but its trait bounds were not satisfied +} diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr new file mode 100644 index 00000000000..83540739ee3 --- /dev/null +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -0,0 +1,33 @@ +error[E0599]: the method `clone` exists for struct `Foo<NonCopy>`, but its trait bounds were not satisfied + --> $DIR/deriving-with-repr-packed-2.rs:20:11 + | +LL | pub struct Foo<T>(T, T, T); + | ----------------- + | | + | method `clone` not found for this struct + | doesn't satisfy `Foo<NonCopy>: Clone` +LL | +LL | struct NonCopy; + | -------------- + | | + | doesn't satisfy `NonCopy: Clone` + | doesn't satisfy `NonCopy: Copy` +... +LL | _ = x.clone(); + | ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `NonCopy: Clone` + `NonCopy: Copy` + --> $DIR/deriving-with-repr-packed-2.rs:7:16 + | +LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] + | ^^^^^ unsatisfied trait bound introduced in this `derive` macro +help: consider annotating `NonCopy` with `#[derive(Clone, Copy)]` + | +LL | #[derive(Clone, Copy)] + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs index 3884e397764..eddf41f5553 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -1,45 +1,38 @@ #![deny(unaligned_references)] // Check that deriving certain builtin traits on certain packed structs cause -// errors. This happens when the derived trait would need to use a potentially -// misaligned reference. But there are two cases that are allowed: -// - If all the fields within the struct meet the required alignment: 1 for -// `repr(packed)`, or `N` for `repr(packed(N))`. -// - If `Default` is the only trait derived, because it doesn't involve any -// references. +// errors. To avoid potentially misaligned references, field copies must be +// used, which involves adding `T: Copy` bounds. #[derive(Copy, Clone, Default, PartialEq, Eq)] -//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters -//~| hard error -//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters -//~| hard error #[repr(packed)] pub struct Foo<T>(T, T, T); +// This one is fine because the fields all impl `Copy`. #[derive(Default, Hash)] -//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` -//~| hard error #[repr(packed)] pub struct Bar(u32, u32, u32); -// This one is fine because the field alignment is 1. -#[derive(Default, Hash)] -#[repr(packed)] -pub struct Bar2(u8, i8, bool); - -// This one is fine because the field alignment is 2, matching `packed(2)`. -#[derive(Default, Hash)] -#[repr(packed(2))] -pub struct Bar3(u16, i16, bool); - // This one is fine because it's not packed. #[derive(Debug, Default)] struct Y(usize); +// This one has an error because `Y` doesn't impl `Copy`. +// Note: there is room for improvement in the error message. #[derive(Debug, Default)] -//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` -//~| hard error #[repr(packed)] struct X(Y); +//~^ ERROR cannot move out of `self` which is behind a shared reference + +// This is currently allowed, but will be phased out at some point. From +// `zerovec` within icu4x-0.9.0. +#[derive(Debug)] +#[repr(packed)] +struct FlexZeroSlice { + width: u8, + data: [u8], + //~^ WARNING byte slice in a packed struct that derives a built-in trait + //~^^ this was previously accepted +} fn main() {} diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 0ad800c3981..2cb2a696d97 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -1,111 +1,45 @@ -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-with-repr-packed.rs:33:5 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^ +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | data: [u8], + | ^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 - | -LL | #[derive(Default, Hash)] - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 +error[E0507]: cannot move out of `self` which is behind a shared reference + --> $DIR/deriving-with-repr-packed.rs:24:10 | LL | #[derive(Debug, Default)] - | ^^^^^ + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct X(Y); + | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0507`. Future incompatibility report: Future breakage diagnostic: -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 - | -LL | #[derive(Default, Hash)] - | ^^^^ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-with-repr-packed.rs:33:5 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 - | -LL | #[derive(Debug, Default)] - | ^^^^^ +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | data: [u8], + | ^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523> -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index ba7809413bd..51f9708d3cd 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -21,36 +21,88 @@ #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Empty; -// A basic struct. +// A basic struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Point { x: u32, y: u32, } -// A large struct. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +// A basic packed struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(packed)] +struct PackedPoint { + x: u32, + y: u32, +} + +// A large struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Big { b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32, } +// A struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +struct NonCopy(u32); + +// A packed struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +#[repr(packed)] +struct PackedNonCopy(u32); + +// A struct that impls `Copy` manually, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +struct ManualCopy(u32); +impl Copy for ManualCopy {} + +// A packed struct that impls `Copy` manually, which means it gets the +// non-simple `clone` implemention that clones the fields individually. +#[derive(Clone)] +#[repr(packed)] +struct PackedManualCopy(u32); +impl Copy for PackedManualCopy {} + // A struct with an unsized field. Some derives are not usable in this case. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Unsized([u32]); -// A packed tuple struct that impls `Copy`. -#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +// A packed struct with an unsized `[u8]` field. This is currently allowed, but +// causes a warning and will be phased out at some point. +#[derive(Debug, Hash)] #[repr(packed)] -struct PackedCopy(u32); +struct PackedUnsizedU8([u8]); +//~^ WARNING byte slice in a packed struct that derives a built-in trait +//~^^ WARNING byte slice in a packed struct that derives a built-in trait +//~^^^ this was previously accepted +//~^^^^ this was previously accepted -// A packed tuple struct that does not impl `Copy`. Note that the alignment of -// the field must be 1 for this code to be valid. Otherwise it triggers an -// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not -// derive Copy (error E0133)" at MIR building time. This is a weird case and -// it's possible that this struct is not supposed to work, but for now it does. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +trait Trait { + type A; +} + +// A generic struct involving an associated type. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Generic<T: Trait, U> { + t: T, + ta: T::A, + u: U, +} + +// A packed, generic tuple struct involving an associated type. Because it is +// packed, a `T: Copy` bound is added to all impls (and where clauses within +// them) except for `Default`. This is because we must access fields using +// copies (e.g. `&{self.0}`), instead of using direct references (e.g. +// `&self.0`) which may be misaligned in a packed struct. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(packed)] -struct PackedNonCopy(u8); +struct PackedGeneric<T: Trait, U>(T, T::A, U); // An empty enum. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -97,6 +149,13 @@ enum Fielded { Z(Option<i32>), } +// A generic enum. Note that `Default` cannot be derived for this enum. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum EnumGeneric<T, U> { + One(T), + Two(U), +} + // A union. Most builtin traits are not derivable for unions. #[derive(Clone, Copy)] pub union Union { diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.stderr new file mode 100644 index 00000000000..503f0cae73b --- /dev/null +++ b/tests/ui/deriving/deriving-all-codegen.stderr @@ -0,0 +1,63 @@ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted + +Future incompatibility report: Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457> + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index e6ee11a783b..b4874cef134 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -78,7 +78,8 @@ impl ::core::cmp::Ord for Empty { } } -// A basic struct. +// A basic struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. struct Point { x: u32, y: u32, @@ -161,7 +162,95 @@ impl ::core::cmp::Ord for Point { } } -// A large struct. +// A basic packed struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[repr(packed)] +struct PackedPoint { + x: u32, + y: u32, +} +#[automatically_derived] +impl ::core::clone::Clone for PackedPoint { + #[inline] + fn clone(&self) -> PackedPoint { + let _: ::core::clone::AssertParamIsClone<u32>; + *self + } +} +#[automatically_derived] +impl ::core::marker::Copy for PackedPoint { } +#[automatically_derived] +impl ::core::fmt::Debug for PackedPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_struct_field2_finish(f, "PackedPoint", + "x", &&{ self.x }, "y", &&{ self.y }) + } +} +#[automatically_derived] +impl ::core::default::Default for PackedPoint { + #[inline] + fn default() -> PackedPoint { + PackedPoint { + x: ::core::default::Default::default(), + y: ::core::default::Default::default(), + } + } +} +#[automatically_derived] +impl ::core::hash::Hash for PackedPoint { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&{ self.x }, state); + ::core::hash::Hash::hash(&{ self.y }, state) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for PackedPoint { } +#[automatically_derived] +impl ::core::cmp::PartialEq for PackedPoint { + #[inline] + fn eq(&self, other: &PackedPoint) -> bool { + { self.x } == { other.x } && { self.y } == { other.y } + } +} +#[automatically_derived] +impl ::core::marker::StructuralEq for PackedPoint { } +#[automatically_derived] +impl ::core::cmp::Eq for PackedPoint { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for PackedPoint { + #[inline] + fn partial_cmp(&self, other: &PackedPoint) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&{ self.x }, &{ other.x }) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + ::core::cmp::PartialOrd::partial_cmp(&{ self.y }, + &{ other.y }), + cmp => cmp, + } + } +} +#[automatically_derived] +impl ::core::cmp::Ord for PackedPoint { + #[inline] + fn cmp(&self, other: &PackedPoint) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&{ self.x }, &{ other.x }) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&{ self.y }, &{ other.y }), + cmp => cmp, + } + } +} + +// A large struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. struct Big { b1: u32, b2: u32, @@ -176,19 +265,13 @@ struct Big { impl ::core::clone::Clone for Big { #[inline] fn clone(&self) -> Big { - Big { - b1: ::core::clone::Clone::clone(&self.b1), - b2: ::core::clone::Clone::clone(&self.b2), - b3: ::core::clone::Clone::clone(&self.b3), - b4: ::core::clone::Clone::clone(&self.b4), - b5: ::core::clone::Clone::clone(&self.b5), - b6: ::core::clone::Clone::clone(&self.b6), - b7: ::core::clone::Clone::clone(&self.b7), - b8: ::core::clone::Clone::clone(&self.b8), - } + let _: ::core::clone::AssertParamIsClone<u32>; + *self } } #[automatically_derived] +impl ::core::marker::Copy for Big { } +#[automatically_derived] impl ::core::fmt::Debug for Big { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { let names: &'static _ = @@ -336,6 +419,54 @@ impl ::core::cmp::Ord for Big { } } +// A struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +struct NonCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for NonCopy { + #[inline] + fn clone(&self) -> NonCopy { + NonCopy(::core::clone::Clone::clone(&self.0)) + } +} + +// A packed struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[repr(packed)] +struct PackedNonCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for PackedNonCopy { + #[inline] + fn clone(&self) -> PackedNonCopy { + PackedNonCopy(::core::clone::Clone::clone(&{ self.0 })) + } +} + +// A struct that impls `Copy` manually, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +struct ManualCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for ManualCopy { + #[inline] + fn clone(&self) -> ManualCopy { + ManualCopy(::core::clone::Clone::clone(&self.0)) + } +} +impl Copy for ManualCopy {} + +// A packed struct that impls `Copy` manually, which means it gets the +// non-simple `clone` implemention that clones the fields individually. +#[repr(packed)] +struct PackedManualCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for PackedManualCopy { + #[inline] + fn clone(&self) -> PackedManualCopy { + PackedManualCopy(::core::clone::Clone::clone(&{ self.0 })) + } +} +impl Copy for PackedManualCopy {} + // A struct with an unsized field. Some derives are not usable in this case. struct Unsized([u32]); #[automatically_derived] @@ -385,138 +516,265 @@ impl ::core::cmp::Ord for Unsized { } } -// A packed tuple struct that impls `Copy`. +// A packed struct with an unsized `[u8]` field. This is currently allowed, but +// causes a warning and will be phased out at some point. #[repr(packed)] -struct PackedCopy(u32); +struct PackedUnsizedU8([u8]); #[automatically_derived] -impl ::core::clone::Clone for PackedCopy { +impl ::core::fmt::Debug for PackedUnsizedU8 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, + "PackedUnsizedU8", &&self.0) + } +} +#[automatically_derived] +impl ::core::hash::Hash for PackedUnsizedU8 { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.0, state) + } +} + +trait Trait { + type A; +} + +// A generic struct involving an associated type. +struct Generic<T: Trait, U> { + t: T, + ta: T::A, + u: U, +} +#[automatically_derived] +impl<T: ::core::clone::Clone + Trait, U: ::core::clone::Clone> + ::core::clone::Clone for Generic<T, U> where T::A: ::core::clone::Clone { #[inline] - fn clone(&self) -> PackedCopy { - let _: ::core::clone::AssertParamIsClone<u32>; - *self + fn clone(&self) -> Generic<T, U> { + Generic { + t: ::core::clone::Clone::clone(&self.t), + ta: ::core::clone::Clone::clone(&self.ta), + u: ::core::clone::Clone::clone(&self.u), + } } } #[automatically_derived] -impl ::core::marker::Copy for PackedCopy { } +impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy> + ::core::marker::Copy for Generic<T, U> where T::A: ::core::marker::Copy { +} #[automatically_derived] -impl ::core::fmt::Debug for PackedCopy { +impl<T: ::core::fmt::Debug + Trait, U: ::core::fmt::Debug> ::core::fmt::Debug + for Generic<T, U> where T::A: ::core::fmt::Debug { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy", - &&{ self.0 }) + ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t", + &&self.t, "ta", &&self.ta, "u", &&self.u) } } #[automatically_derived] -impl ::core::default::Default for PackedCopy { +impl<T: ::core::default::Default + Trait, U: ::core::default::Default> + ::core::default::Default for Generic<T, U> where + T::A: ::core::default::Default { #[inline] - fn default() -> PackedCopy { - PackedCopy(::core::default::Default::default()) + fn default() -> Generic<T, U> { + Generic { + t: ::core::default::Default::default(), + ta: ::core::default::Default::default(), + u: ::core::default::Default::default(), + } } } #[automatically_derived] -impl ::core::hash::Hash for PackedCopy { +impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash + for Generic<T, U> where T::A: ::core::hash::Hash { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&{ self.0 }, state) + ::core::hash::Hash::hash(&self.t, state); + ::core::hash::Hash::hash(&self.ta, state); + ::core::hash::Hash::hash(&self.u, state) } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for PackedCopy { } +impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { } #[automatically_derived] -impl ::core::cmp::PartialEq for PackedCopy { +impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq> + ::core::cmp::PartialEq for Generic<T, U> where + T::A: ::core::cmp::PartialEq { #[inline] - fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } } + fn eq(&self, other: &Generic<T, U>) -> bool { + self.t == other.t && self.ta == other.ta && self.u == other.u + } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedCopy { } +impl<T: Trait, U> ::core::marker::StructuralEq for Generic<T, U> { } #[automatically_derived] -impl ::core::cmp::Eq for PackedCopy { +impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for + Generic<T, U> where T::A: ::core::cmp::Eq { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { - let _: ::core::cmp::AssertParamIsEq<u32>; + let _: ::core::cmp::AssertParamIsEq<T>; + let _: ::core::cmp::AssertParamIsEq<T::A>; + let _: ::core::cmp::AssertParamIsEq<U>; } } #[automatically_derived] -impl ::core::cmp::PartialOrd for PackedCopy { +impl<T: ::core::cmp::PartialOrd + Trait, U: ::core::cmp::PartialOrd> + ::core::cmp::PartialOrd for Generic<T, U> where + T::A: ::core::cmp::PartialOrd { #[inline] - fn partial_cmp(&self, other: &PackedCopy) + fn partial_cmp(&self, other: &Generic<T, U>) -> ::core::option::Option<::core::cmp::Ordering> { - ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + match ::core::cmp::PartialOrd::partial_cmp(&self.t, &other.t) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&self.ta, + &other.ta) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => ::core::cmp::PartialOrd::partial_cmp(&self.u, &other.u), + cmp => cmp, + }, + cmp => cmp, + } } } #[automatically_derived] -impl ::core::cmp::Ord for PackedCopy { +impl<T: ::core::cmp::Ord + Trait, U: ::core::cmp::Ord> ::core::cmp::Ord for + Generic<T, U> where T::A: ::core::cmp::Ord { #[inline] - fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering { - ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) + fn cmp(&self, other: &Generic<T, U>) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&self.t, &other.t) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.ta, &other.ta) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&self.u, &other.u), + cmp => cmp, + }, + cmp => cmp, + } } } -// A packed tuple struct that does not impl `Copy`. Note that the alignment of -// the field must be 1 for this code to be valid. Otherwise it triggers an -// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not -// derive Copy (error E0133)" at MIR building time. This is a weird case and -// it's possible that this struct is not supposed to work, but for now it does. +// A packed, generic tuple struct involving an associated type. Because it is +// packed, a `T: Copy` bound is added to all impls (and where clauses within +// them) except for `Default`. This is because we must access fields using +// copies (e.g. `&{self.0}`), instead of using direct references (e.g. +// `&self.0`) which may be misaligned in a packed struct. #[repr(packed)] -struct PackedNonCopy(u8); +struct PackedGeneric<T: Trait, U>(T, T::A, U); #[automatically_derived] -impl ::core::clone::Clone for PackedNonCopy { +impl<T: ::core::clone::Clone + ::core::marker::Copy + Trait, + U: ::core::clone::Clone + ::core::marker::Copy> ::core::clone::Clone for + PackedGeneric<T, U> where T::A: ::core::clone::Clone + + ::core::marker::Copy { #[inline] - fn clone(&self) -> PackedNonCopy { - PackedNonCopy(::core::clone::Clone::clone(&self.0)) + fn clone(&self) -> PackedGeneric<T, U> { + PackedGeneric(::core::clone::Clone::clone(&{ self.0 }), + ::core::clone::Clone::clone(&{ self.1 }), + ::core::clone::Clone::clone(&{ self.2 })) } } #[automatically_derived] -impl ::core::fmt::Debug for PackedNonCopy { +impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy> + ::core::marker::Copy for PackedGeneric<T, U> where + T::A: ::core::marker::Copy { +} +#[automatically_derived] +impl<T: ::core::fmt::Debug + ::core::marker::Copy + Trait, + U: ::core::fmt::Debug + ::core::marker::Copy> ::core::fmt::Debug for + PackedGeneric<T, U> where T::A: ::core::fmt::Debug + ::core::marker::Copy + { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy", - &&self.0) + ::core::fmt::Formatter::debug_tuple_field3_finish(f, "PackedGeneric", + &&{ self.0 }, &&{ self.1 }, &&{ self.2 }) } } #[automatically_derived] -impl ::core::default::Default for PackedNonCopy { +impl<T: ::core::default::Default + Trait, U: ::core::default::Default> + ::core::default::Default for PackedGeneric<T, U> where + T::A: ::core::default::Default { #[inline] - fn default() -> PackedNonCopy { - PackedNonCopy(::core::default::Default::default()) + fn default() -> PackedGeneric<T, U> { + PackedGeneric(::core::default::Default::default(), + ::core::default::Default::default(), + ::core::default::Default::default()) } } #[automatically_derived] -impl ::core::hash::Hash for PackedNonCopy { +impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait, + U: ::core::hash::Hash + ::core::marker::Copy> ::core::hash::Hash for + PackedGeneric<T, U> where T::A: ::core::hash::Hash + ::core::marker::Copy + { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&self.0, state) + ::core::hash::Hash::hash(&{ self.0 }, state); + ::core::hash::Hash::hash(&{ self.1 }, state); + ::core::hash::Hash::hash(&{ self.2 }, state) } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for PackedNonCopy { } +impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U> + { +} #[automatically_derived] -impl ::core::cmp::PartialEq for PackedNonCopy { +impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait, + U: ::core::cmp::PartialEq + ::core::marker::Copy> ::core::cmp::PartialEq + for PackedGeneric<T, U> where T::A: ::core::cmp::PartialEq + + ::core::marker::Copy { #[inline] - fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 } + fn eq(&self, other: &PackedGeneric<T, U>) -> bool { + { self.0 } == { other.0 } && { self.1 } == { other.1 } && + { self.2 } == { other.2 } + } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedNonCopy { } +impl<T: Trait, U> ::core::marker::StructuralEq for PackedGeneric<T, U> { } #[automatically_derived] -impl ::core::cmp::Eq for PackedNonCopy { +impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq + + ::core::marker::Copy> ::core::cmp::Eq for PackedGeneric<T, U> where + T::A: ::core::cmp::Eq + ::core::marker::Copy { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { - let _: ::core::cmp::AssertParamIsEq<u8>; + let _: ::core::cmp::AssertParamIsEq<T>; + let _: ::core::cmp::AssertParamIsEq<T::A>; + let _: ::core::cmp::AssertParamIsEq<U>; } } #[automatically_derived] -impl ::core::cmp::PartialOrd for PackedNonCopy { +impl<T: ::core::cmp::PartialOrd + ::core::marker::Copy + Trait, + U: ::core::cmp::PartialOrd + ::core::marker::Copy> ::core::cmp::PartialOrd + for PackedGeneric<T, U> where T::A: ::core::cmp::PartialOrd + + ::core::marker::Copy { #[inline] - fn partial_cmp(&self, other: &PackedNonCopy) + fn partial_cmp(&self, other: &PackedGeneric<T, U>) -> ::core::option::Option<::core::cmp::Ordering> { - ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + match ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&{ self.1 }, + &{ other.1 }) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + ::core::cmp::PartialOrd::partial_cmp(&{ self.2 }, + &{ other.2 }), + cmp => cmp, + }, + cmp => cmp, + } } } #[automatically_derived] -impl ::core::cmp::Ord for PackedNonCopy { +impl<T: ::core::cmp::Ord + ::core::marker::Copy + Trait, U: ::core::cmp::Ord + + ::core::marker::Copy> ::core::cmp::Ord for PackedGeneric<T, U> where + T::A: ::core::cmp::Ord + ::core::marker::Copy { #[inline] - fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering { - ::core::cmp::Ord::cmp(&self.0, &other.0) + fn cmp(&self, other: &PackedGeneric<T, U>) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&{ self.1 }, &{ other.1 }) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&{ self.2 }, &{ other.2 }), + cmp => cmp, + }, + cmp => cmp, + } } } @@ -889,23 +1147,20 @@ impl ::core::cmp::PartialOrd for Mixed { -> ::core::option::Option<::core::cmp::Ordering> { let __self_tag = ::core::intrinsics::discriminant_value(self); let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) => - match (self, other) { - (Mixed::R(__self_0), Mixed::R(__arg1_0)) => - ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), - (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { - d1: __arg1_0, d2: __arg1_1 }) => - match ::core::cmp::PartialOrd::partial_cmp(__self_0, - __arg1_0) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1), - cmp => cmp, - }, - _ => - ::core::option::Option::Some(::core::cmp::Ordering::Equal), + match (self, other) { + (Mixed::R(__self_0), Mixed::R(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { + d1: __arg1_0, d2: __arg1_1 }) => + match ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1), + cmp => cmp, }, - cmp => cmp, + _ => + ::core::cmp::PartialOrd::partial_cmp(&__self_tag, + &__arg1_tag), } } } @@ -1019,35 +1274,152 @@ impl ::core::cmp::PartialOrd for Fielded { -> ::core::option::Option<::core::cmp::Ordering> { let __self_tag = ::core::intrinsics::discriminant_value(self); let __arg1_tag = ::core::intrinsics::discriminant_value(other); - match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match (self, other) { + (Fielded::X(__self_0), Fielded::X(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + _ => + ::core::cmp::PartialOrd::partial_cmp(&__self_tag, + &__arg1_tag), + } + } +} +#[automatically_derived] +impl ::core::cmp::Ord for Fielded { + #[inline] + fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + ::core::cmp::Ordering::Equal => match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => - ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + ::core::cmp::Ord::cmp(__self_0, __arg1_0), (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => - ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + ::core::cmp::Ord::cmp(__self_0, __arg1_0), (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => - ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + ::core::cmp::Ord::cmp(__self_0, __arg1_0), _ => unsafe { ::core::intrinsics::unreachable() } }, cmp => cmp, } } } + +// A generic enum. Note that `Default` cannot be derived for this enum. +enum EnumGeneric<T, U> { One(T), Two(U), } #[automatically_derived] -impl ::core::cmp::Ord for Fielded { +impl<T: ::core::clone::Clone, U: ::core::clone::Clone> ::core::clone::Clone + for EnumGeneric<T, U> { #[inline] - fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering { + fn clone(&self) -> EnumGeneric<T, U> { + match self { + EnumGeneric::One(__self_0) => + EnumGeneric::One(::core::clone::Clone::clone(__self_0)), + EnumGeneric::Two(__self_0) => + EnumGeneric::Two(::core::clone::Clone::clone(__self_0)), + } + } +} +#[automatically_derived] +impl<T: ::core::marker::Copy, U: ::core::marker::Copy> ::core::marker::Copy + for EnumGeneric<T, U> { +} +#[automatically_derived] +impl<T: ::core::fmt::Debug, U: ::core::fmt::Debug> ::core::fmt::Debug for + EnumGeneric<T, U> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + EnumGeneric::One(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "One", + &__self_0), + EnumGeneric::Two(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Two", + &__self_0), + } + } +} +#[automatically_derived] +impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for + EnumGeneric<T, U> { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let __self_tag = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_tag, state); + match self { + EnumGeneric::One(__self_0) => + ::core::hash::Hash::hash(__self_0, state), + EnumGeneric::Two(__self_0) => + ::core::hash::Hash::hash(__self_0, state), + } + } +} +#[automatically_derived] +impl<T, U> ::core::marker::StructuralPartialEq for EnumGeneric<T, U> { } +#[automatically_derived] +impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq> + ::core::cmp::PartialEq for EnumGeneric<T, U> { + #[inline] + fn eq(&self, other: &EnumGeneric<T, U>) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag == __arg1_tag && + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + *__self_0 == *__arg1_0, + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + *__self_0 == *__arg1_0, + _ => unsafe { ::core::intrinsics::unreachable() } + } + } +} +#[automatically_derived] +impl<T, U> ::core::marker::StructuralEq for EnumGeneric<T, U> { } +#[automatically_derived] +impl<T: ::core::cmp::Eq, U: ::core::cmp::Eq> ::core::cmp::Eq for + EnumGeneric<T, U> { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<T>; + let _: ::core::cmp::AssertParamIsEq<U>; + } +} +#[automatically_derived] +impl<T: ::core::cmp::PartialOrd, U: ::core::cmp::PartialOrd> + ::core::cmp::PartialOrd for EnumGeneric<T, U> { + #[inline] + fn partial_cmp(&self, other: &EnumGeneric<T, U>) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + _ => + ::core::cmp::PartialOrd::partial_cmp(&__self_tag, + &__arg1_tag), + } + } +} +#[automatically_derived] +impl<T: ::core::cmp::Ord, U: ::core::cmp::Ord> ::core::cmp::Ord for + EnumGeneric<T, U> { + #[inline] + fn cmp(&self, other: &EnumGeneric<T, U>) -> ::core::cmp::Ordering { let __self_tag = ::core::intrinsics::discriminant_value(self); let __arg1_tag = ::core::intrinsics::discriminant_value(other); match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { ::core::cmp::Ordering::Equal => match (self, other) { - (Fielded::X(__self_0), Fielded::X(__arg1_0)) => + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => ::core::cmp::Ord::cmp(__self_0, __arg1_0), - (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => - ::core::cmp::Ord::cmp(__self_0, __arg1_0), - (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => ::core::cmp::Ord::cmp(__self_0, __arg1_0), _ => unsafe { ::core::intrinsics::unreachable() } }, diff --git a/tests/ui/dropck/drop-with-active-borrows-1.stderr b/tests/ui/dropck/drop-with-active-borrows-1.stderr index 8d6a7f3721f..4585b22974c 100644 --- a/tests/ui/dropck/drop-with-active-borrows-1.stderr +++ b/tests/ui/dropck/drop-with-active-borrows-1.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/drop-with-active-borrows-1.rs:4:10 | +LL | let a = "".to_string(); + | - binding `a` declared here LL | let b: Vec<&str> = a.lines().collect(); | --------- borrow of `a` occurs here LL | drop(a); diff --git a/tests/ui/dropck/dropck-eyepatch-extern-crate.stderr b/tests/ui/dropck/dropck-eyepatch-extern-crate.stderr index 5d53405579d..23d57634e8f 100644 --- a/tests/ui/dropck/dropck-eyepatch-extern-crate.stderr +++ b/tests/ui/dropck/dropck-eyepatch-extern-crate.stderr @@ -1,6 +1,9 @@ error[E0597]: `c_shortest` does not live long enough --> $DIR/dropck-eyepatch-extern-crate.rs:46:23 | +LL | let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>); + | ---------- binding `c_shortest` declared here +... LL | dt = Dt("dt", &c_shortest); | ^^^^^^^^^^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `c_shortest` does not live long enough --> $DIR/dropck-eyepatch-extern-crate.rs:68:32 | +LL | let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + | ---------- binding `c_shortest` declared here +... LL | pt = Pt("pt", &c_long, &c_shortest); | ^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/dropck/dropck-eyepatch-reorder.stderr b/tests/ui/dropck/dropck-eyepatch-reorder.stderr index 5055cdd8b2b..a5d5136b5c5 100644 --- a/tests/ui/dropck/dropck-eyepatch-reorder.stderr +++ b/tests/ui/dropck/dropck-eyepatch-reorder.stderr @@ -1,6 +1,9 @@ error[E0597]: `c_shortest` does not live long enough --> $DIR/dropck-eyepatch-reorder.rs:64:23 | +LL | let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>); + | ---------- binding `c_shortest` declared here +... LL | dt = Dt("dt", &c_shortest); | ^^^^^^^^^^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `c_shortest` does not live long enough --> $DIR/dropck-eyepatch-reorder.rs:86:32 | +LL | let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + | ---------- binding `c_shortest` declared here +... LL | pt = Pt("pt", &c_long, &c_shortest); | ^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/dropck/dropck-eyepatch.stderr b/tests/ui/dropck/dropck-eyepatch.stderr index 21295e6c601..dc3f8c05e73 100644 --- a/tests/ui/dropck/dropck-eyepatch.stderr +++ b/tests/ui/dropck/dropck-eyepatch.stderr @@ -1,6 +1,9 @@ error[E0597]: `c_shortest` does not live long enough --> $DIR/dropck-eyepatch.rs:88:23 | +LL | let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>); + | ---------- binding `c_shortest` declared here +... LL | dt = Dt("dt", &c_shortest); | ^^^^^^^^^^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `c_shortest` does not live long enough --> $DIR/dropck-eyepatch.rs:110:32 | +LL | let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>); + | ---------- binding `c_shortest` declared here +... LL | pt = Pt("pt", &c_long, &c_shortest); | ^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/dropck/dropck-union.stderr b/tests/ui/dropck/dropck-union.stderr index 854e29385a8..7d48e9fdcee 100644 --- a/tests/ui/dropck/dropck-union.stderr +++ b/tests/ui/dropck/dropck-union.stderr @@ -1,6 +1,8 @@ error[E0597]: `v` does not live long enough --> $DIR/dropck-union.rs:37:18 | +LL | let v : Wrap<C> = Wrap::new(C(Cell::new(None))); + | - binding `v` declared here LL | v.0.set(Some(&v)); | ^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/dropck/dropck_trait_cycle_checked.stderr b/tests/ui/dropck/dropck_trait_cycle_checked.stderr index dc3fbed593b..4d4f7b9df11 100644 --- a/tests/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/tests/ui/dropck/dropck_trait_cycle_checked.stderr @@ -2,7 +2,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:111:13 | LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static` LL | o1.set0(&o2); | ^^^ borrowed value does not live long enough ... @@ -13,7 +13,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 | LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here -------- cast requires that `o3` is borrowed for `'static` LL | o1.set0(&o2); LL | o1.set1(&o3); | ^^^ borrowed value does not live long enough @@ -25,7 +25,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:113:13 | LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static` ... LL | o2.set0(&o2); | ^^^ borrowed value does not live long enough @@ -37,7 +37,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -- binding `o3` declared here -------- cast requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough @@ -49,7 +49,7 @@ error[E0597]: `o1` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:115:13 | LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o1` is borrowed for `'static` + | -- binding `o1` declared here -------- cast requires that `o1` is borrowed for `'static` ... LL | o3.set0(&o1); | ^^^ borrowed value does not live long enough @@ -61,7 +61,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -- binding `o2` declared here -------- cast requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough diff --git a/tests/ui/dst/dst-bad-coerce3.stderr b/tests/ui/dst/dst-bad-coerce3.stderr index 957e98bbeee..1254250bcbd 100644 --- a/tests/ui/dst/dst-bad-coerce3.stderr +++ b/tests/ui/dst/dst-bad-coerce3.stderr @@ -3,7 +3,9 @@ error[E0597]: `f1` does not live long enough | LL | fn baz<'a>() { | -- lifetime `'a` defined here -... +LL | // With a vec of ints. +LL | let f1 = Fat { ptr: [1, 2, 3] }; + | -- binding `f1` declared here LL | let f2: &Fat<[isize; 3]> = &f1; | ^^^ borrowed value does not live long enough LL | let f3: &'a Fat<[isize]> = f2; @@ -18,6 +20,8 @@ error[E0597]: `f1` does not live long enough LL | fn baz<'a>() { | -- lifetime `'a` defined here ... +LL | let f1 = Fat { ptr: Foo }; + | -- binding `f1` declared here LL | let f2: &Fat<Foo> = &f1; | ^^^ borrowed value does not live long enough LL | let f3: &'a Fat<dyn Bar> = f2; @@ -32,6 +36,8 @@ error[E0597]: `f1` does not live long enough LL | fn baz<'a>() { | -- lifetime `'a` defined here ... +LL | let f1 = ([1, 2, 3],); + | -- binding `f1` declared here LL | let f2: &([isize; 3],) = &f1; | ^^^ borrowed value does not live long enough LL | let f3: &'a ([isize],) = f2; @@ -46,6 +52,8 @@ error[E0597]: `f1` does not live long enough LL | fn baz<'a>() { | -- lifetime `'a` defined here ... +LL | let f1 = (Foo,); + | -- binding `f1` declared here LL | let f2: &(Foo,) = &f1; | ^^^ borrowed value does not live long enough LL | let f3: &'a (dyn Bar,) = f2; diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs index c67d42889d6..74c138af483 100644 --- a/tests/ui/error-codes/E0208.rs +++ b/tests/ui/error-codes/E0208.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct Foo<'a, T> { //~ ERROR [-, o] +struct Foo<'a, T> { //~ ERROR [+, o] t: &'a mut T, } diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr index dbbb41e7950..2c7072a7e76 100644 --- a/tests/ui/error-codes/E0208.stderr +++ b/tests/ui/error-codes/E0208.stderr @@ -1,4 +1,4 @@ -error: [-, o] +error: [+, o] --> $DIR/E0208.rs:4:1 | LL | struct Foo<'a, T> { diff --git a/tests/ui/error-codes/E0503.stderr b/tests/ui/error-codes/E0503.stderr index fafe363eb47..2f02e3b1a61 100644 --- a/tests/ui/error-codes/E0503.stderr +++ b/tests/ui/error-codes/E0503.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `value` because it was mutably borrowed --> $DIR/E0503.rs:4:16 | LL | let _borrow = &mut value; - | ---------- borrow of `value` occurs here + | ---------- `value` is borrowed here LL | let _sum = value + 1; | ^^^^^ use of borrowed `value` LL | _borrow.use_mut(); diff --git a/tests/ui/error-codes/E0504.stderr b/tests/ui/error-codes/E0504.stderr index e677e891615..20e16a53810 100644 --- a/tests/ui/error-codes/E0504.stderr +++ b/tests/ui/error-codes/E0504.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `fancy_num` because it is borrowed --> $DIR/E0504.rs:9:13 | +LL | let fancy_num = FancyNum { num: 5 }; + | --------- binding `fancy_num` declared here LL | let fancy_ref = &fancy_num; | ---------- borrow of `fancy_num` occurs here LL | diff --git a/tests/ui/error-codes/E0505.stderr b/tests/ui/error-codes/E0505.stderr index bd3f37f54e0..2ecb4a75c43 100644 --- a/tests/ui/error-codes/E0505.stderr +++ b/tests/ui/error-codes/E0505.stderr @@ -1,6 +1,9 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/E0505.rs:9:13 | +LL | let x = Value{}; + | - binding `x` declared here +LL | { LL | let _ref_to_val: &Value = &x; | -- borrow of `x` occurs here LL | eat(x); diff --git a/tests/ui/error-codes/E0506.stderr b/tests/ui/error-codes/E0506.stderr index d70406b750a..17ad7c611f8 100644 --- a/tests/ui/error-codes/E0506.stderr +++ b/tests/ui/error-codes/E0506.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `fancy_num` because it is borrowed --> $DIR/E0506.rs:8:5 | LL | let fancy_ref = &fancy_num; - | ---------- borrow of `fancy_num` occurs here + | ---------- `fancy_num` is borrowed here LL | fancy_num = FancyNum { num: 6 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fancy_num` is assigned to here but it was already borrowed LL | LL | println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); | ------------- borrow later used here diff --git a/tests/ui/error-codes/E0597.stderr b/tests/ui/error-codes/E0597.stderr index b4a1180ad54..82e3481b65a 100644 --- a/tests/ui/error-codes/E0597.stderr +++ b/tests/ui/error-codes/E0597.stderr @@ -1,6 +1,8 @@ error[E0597]: `y` does not live long enough --> $DIR/E0597.rs:8:16 | +LL | let y = 0; + | - binding `y` declared here LL | x.x = Some(&y); | ^^ borrowed value does not live long enough LL | diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs new file mode 100644 index 00000000000..c0cbbcc9d2d --- /dev/null +++ b/tests/ui/error-codes/E0789.rs @@ -0,0 +1,12 @@ +// compile-flags: --crate-type lib + +#![feature(rustc_attrs)] +#![feature(staged_api)] +#![unstable(feature = "foo_module", reason = "...", issue = "123")] + +#[rustc_allowed_through_unstable_modules] +// #[stable(feature = "foo", since = "1.0")] +struct Foo; +//~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +//~^^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +// FIXME: we shouldn't have two errors here, only occurs when using `-Zdeduplicate-diagnostics=no` diff --git a/tests/ui/error-codes/E0789.stderr b/tests/ui/error-codes/E0789.stderr new file mode 100644 index 00000000000..faab92bae03 --- /dev/null +++ b/tests/ui/error-codes/E0789.stderr @@ -0,0 +1,15 @@ +error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute + --> $DIR/E0789.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^^ + +error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute + --> $DIR/E0789.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0789`. diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs new file mode 100644 index 00000000000..83366ea02b0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs @@ -0,0 +1,9 @@ +// Check that even though Cell: DispatchFromDyn it remains an invalid self parameter type + +use std::cell::Cell; + +trait Trait{ + fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: Cell<&Self> +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr new file mode 100644 index 00000000000..ce06ce916a7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr @@ -0,0 +1,12 @@ +error[E0307]: invalid `self` parameter type: Cell<&Self> + --> $DIR/feature-gate-dispatch-from-dyn-cell.rs:6:19 + | +LL | fn cell(self: Cell<&Self>); + | ^^^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs new file mode 100644 index 00000000000..23857cbaca8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs @@ -0,0 +1,35 @@ +// Check that a self parameter type requires a DispatchFromDyn impl to be object safe + +#![feature(arbitrary_self_types, unsize, coerce_unsized)] + +use std::{ + marker::Unsize, + ops::{CoerceUnsized, Deref}, +}; + +struct Ptr<T: ?Sized>(Box<T>); + +impl<T: ?Sized> Deref for Ptr<T> { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {} +// Because this impl is missing the coercion below fails. +// impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {} + +trait Trait { + fn ptr(self: Ptr<Self>); +} +impl Trait for i32 { + fn ptr(self: Ptr<Self>) {} +} + +fn main() { + Ptr(Box::new(4)) as Ptr<dyn Trait>; + //~^ ERROR the trait `Trait` cannot be made into an object + //~^^ ERROR the trait `Trait` cannot be made into an object +} diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr new file mode 100644 index 00000000000..d81eade8e9b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -0,0 +1,45 @@ +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25 + | +LL | fn ptr(self: Ptr<Self>); + | --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self` +... +LL | Ptr(Box::new(4)) as Ptr<dyn Trait>; + | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 + | +LL | trait Trait { + | ----- this trait cannot be made into an object... +LL | fn ptr(self: Ptr<Self>); + | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5 + | +LL | fn ptr(self: Ptr<Self>); + | --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self` +... +LL | Ptr(Box::new(4)) as Ptr<dyn Trait>; + | ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 + | +LL | trait Trait { + | ----- this trait cannot be made into an object... +LL | fn ptr(self: Ptr<Self>); + | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on +note: required for `Ptr<{integer}>` to implement `CoerceUnsized<Ptr<dyn Trait>>` + --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:20:40 + | +LL | impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {} + | --------- ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: required by cast to type `Ptr<dyn Trait>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs new file mode 100644 index 00000000000..0467dea621b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(multiple_supertrait_upcastable)] +//~^ WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` +#![warn(multiple_supertrait_upcastable)] +//~^ WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr new file mode 100644 index 00000000000..1f725f35417 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr @@ -0,0 +1,57 @@ +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + = note: `#[warn(unknown_lints)]` on by default + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1 + | +LL | #![warn(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1 + | +LL | #![warn(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1 + | +LL | #![warn(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: 6 warnings emitted + diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index be321c3c5c0..3480a2ec815 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -15,7 +15,7 @@ LL | format!("{:X}", "3"); NonZeroIsize and 21 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `ArgumentV1::<'a>::new_upper_hex` +note: required by a bound in `core::fmt::ArgumentV1::<'a>::new_upper_hex` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index 3ed040c3ab3..d43f4f0d957 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -6,11 +6,11 @@ LL | send(format_args!("{:?}", c)); | | | required by a bound introduced by this call | - = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` + = help: within `[core::fmt::ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `ArgumentV1<'_>` = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required for `&[ArgumentV1<'_>]` to implement `Send` + = note: required for `&[core::fmt::ArgumentV1<'_>]` to implement `Send` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `send` --> $DIR/send-sync.rs:1:12 diff --git a/tests/ui/fn/fn-compare-mismatch.stderr b/tests/ui/fn/fn-compare-mismatch.stderr index df838cb1181..b4e71e75fdb 100644 --- a/tests/ui/fn/fn-compare-mismatch.stderr +++ b/tests/ui/fn/fn-compare-mismatch.stderr @@ -19,6 +19,8 @@ LL | let x = f == g; | = note: expected fn item `fn() {f}` found fn item `fn() {g}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn()` error: aborting due to 2 previous errors diff --git a/tests/ui/fn/fn-item-type.rs b/tests/ui/fn/fn-item-type.rs index 1831e6cbf10..b6ebc867d28 100644 --- a/tests/ui/fn/fn-item-type.rs +++ b/tests/ui/fn/fn-item-type.rs @@ -1,13 +1,22 @@ // Test that the types of distinct fn items are not compatible by // default. See also `run-pass/fn-item-type-*.rs`. -fn foo<T>(x: isize) -> isize { x * 2 } -fn bar<T>(x: isize) -> isize { x * 4 } +fn foo<T>(x: isize) -> isize { + x * 2 +} +fn bar<T>(x: isize) -> isize { + x * 4 +} -fn eq<T>(x: T, y: T) { } +fn eq<T>(x: T, y: T) {} -trait Foo { fn foo() { /* this is a default fn */ } } -impl<T> Foo for T { /* `foo` is still default here */ } +trait Foo { + fn foo() { /* this is a default fn */ + } +} +impl<T> Foo for T { + /* `foo` is still default here */ +} fn main() { eq(foo::<u8>, bar::<u8>); @@ -15,39 +24,29 @@ fn main() { //~| expected fn item `fn(_) -> _ {foo::<u8>}` //~| found fn item `fn(_) -> _ {bar::<u8>}` //~| expected fn item, found a different fn item - //~| different `fn` items always have unique types, even if their signatures are the same - //~| change the expected type to be function pointer - //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer + //~| different fn items have unique types, even if their signatures are the same eq(foo::<u8>, foo::<i8>); //~^ ERROR mismatched types //~| expected `u8`, found `i8` - //~| different `fn` items always have unique types, even if their signatures are the same - //~| change the expected type to be function pointer - //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer + //~| different fn items have unique types, even if their signatures are the same eq(bar::<String>, bar::<Vec<u8>>); //~^ ERROR mismatched types //~| found fn item `fn(_) -> _ {bar::<Vec<u8>>}` //~| expected struct `String`, found struct `Vec` - //~| different `fn` items always have unique types, even if their signatures are the same - //~| change the expected type to be function pointer - //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer + //~| different fn items have unique types, even if their signatures are the same // Make sure we distinguish between trait methods correctly. eq(<u8 as Foo>::foo, <u16 as Foo>::foo); //~^ ERROR mismatched types //~| expected `u8`, found `u16` - //~| different `fn` items always have unique types, even if their signatures are the same - //~| change the expected type to be function pointer - //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer + //~| different fn items have unique types, even if their signatures are the same eq(foo::<u8>, bar::<u8> as fn(isize) -> isize); //~^ ERROR mismatched types //~| found fn pointer `fn(_) -> _` //~| expected fn item, found fn pointer - //~| change the expected type to be function pointer - //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok! } diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr index f03a47d5c2c..9d41243ef11 100644 --- a/tests/ui/fn/fn-item-type.stderr +++ b/tests/ui/fn/fn-item-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/fn-item-type.rs:13:19 + --> $DIR/fn-item-type.rs:22:19 | LL | eq(foo::<u8>, bar::<u8>); | -- ^^^^^^^^^ expected fn item, found a different fn item @@ -8,17 +8,16 @@ LL | eq(foo::<u8>, bar::<u8>); | = note: expected fn item `fn(_) -> _ {foo::<u8>}` found fn item `fn(_) -> _ {bar::<u8>}` - = note: different `fn` items always have unique types, even if their signatures are the same - = help: change the expected type to be function pointer `fn(isize) -> isize` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize` + = note: different fn items have unique types, even if their signatures are the same note: function defined here - --> $DIR/fn-item-type.rs:7:4 + --> $DIR/fn-item-type.rs:11:4 | -LL | fn eq<T>(x: T, y: T) { } +LL | fn eq<T>(x: T, y: T) {} | ^^ ---- + = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types - --> $DIR/fn-item-type.rs:22:19 + --> $DIR/fn-item-type.rs:29:19 | LL | eq(foo::<u8>, foo::<i8>); | -- ^^^^^^^^^ expected `u8`, found `i8` @@ -27,17 +26,16 @@ LL | eq(foo::<u8>, foo::<i8>); | = note: expected fn item `fn(_) -> _ {foo::<u8>}` found fn item `fn(_) -> _ {foo::<i8>}` - = note: different `fn` items always have unique types, even if their signatures are the same - = help: change the expected type to be function pointer `fn(isize) -> isize` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize` + = note: different fn items have unique types, even if their signatures are the same note: function defined here - --> $DIR/fn-item-type.rs:7:4 + --> $DIR/fn-item-type.rs:11:4 | -LL | fn eq<T>(x: T, y: T) { } +LL | fn eq<T>(x: T, y: T) {} | ^^ ---- + = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types - --> $DIR/fn-item-type.rs:29:23 + --> $DIR/fn-item-type.rs:34:23 | LL | eq(bar::<String>, bar::<Vec<u8>>); | -- ^^^^^^^^^^^^^^ expected struct `String`, found struct `Vec` @@ -46,17 +44,16 @@ LL | eq(bar::<String>, bar::<Vec<u8>>); | = note: expected fn item `fn(_) -> _ {bar::<String>}` found fn item `fn(_) -> _ {bar::<Vec<u8>>}` - = note: different `fn` items always have unique types, even if their signatures are the same - = help: change the expected type to be function pointer `fn(isize) -> isize` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<String> as fn(isize) -> isize` + = note: different fn items have unique types, even if their signatures are the same note: function defined here - --> $DIR/fn-item-type.rs:7:4 + --> $DIR/fn-item-type.rs:11:4 | -LL | fn eq<T>(x: T, y: T) { } +LL | fn eq<T>(x: T, y: T) {} | ^^ ---- + = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types - --> $DIR/fn-item-type.rs:38:26 + --> $DIR/fn-item-type.rs:41:26 | LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo); | -- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` @@ -65,17 +62,16 @@ LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo); | = note: expected fn item `fn() {<u8 as Foo>::foo}` found fn item `fn() {<u16 as Foo>::foo}` - = note: different `fn` items always have unique types, even if their signatures are the same - = help: change the expected type to be function pointer `fn()` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()` + = note: different fn items have unique types, even if their signatures are the same note: function defined here - --> $DIR/fn-item-type.rs:7:4 + --> $DIR/fn-item-type.rs:11:4 | -LL | fn eq<T>(x: T, y: T) { } +LL | fn eq<T>(x: T, y: T) {} | ^^ ---- + = help: consider casting both fn items to fn pointers using `as fn()` error[E0308]: mismatched types - --> $DIR/fn-item-type.rs:45:19 + --> $DIR/fn-item-type.rs:46:19 | LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize); | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer @@ -84,12 +80,11 @@ LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize); | = note: expected fn item `fn(_) -> _ {foo::<u8>}` found fn pointer `fn(_) -> _` - = help: change the expected type to be function pointer `fn(isize) -> isize` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize` + = help: consider casting the fn item to a fn pointer: `foo::<u8> as fn(isize) -> isize` note: function defined here - --> $DIR/fn-item-type.rs:7:4 + --> $DIR/fn-item-type.rs:11:4 | -LL | fn eq<T>(x: T, y: T) { } +LL | fn eq<T>(x: T, y: T) {} | ^^ ---- error: aborting due to 5 previous errors diff --git a/tests/ui/fn/fn-pointer-mismatch.rs b/tests/ui/fn/fn-pointer-mismatch.rs new file mode 100644 index 00000000000..0597478cb42 --- /dev/null +++ b/tests/ui/fn/fn-pointer-mismatch.rs @@ -0,0 +1,56 @@ +fn foo(x: u32) -> u32 { + x * 2 +} + +fn bar(x: u32) -> u32 { + x * 3 +} + +// original example from Issue #102608 +fn foobar(n: u32) -> u32 { + let g = if n % 2 == 0 { &foo } else { &bar }; + //~^ ERROR `if` and `else` have incompatible types + //~| different fn items have unique types, even if their signatures are the same + g(n) +} + +fn main() { + assert_eq!(foobar(7), 21); + assert_eq!(foobar(8), 16); + + // general mismatch of fn item types + let mut a = foo; + a = bar; + //~^ ERROR mismatched types + //~| expected fn item `fn(_) -> _ {foo}` + //~| found fn item `fn(_) -> _ {bar}` + //~| different fn items have unique types, even if their signatures are the same + + // display note even when boxed + let mut b = Box::new(foo); + b = Box::new(bar); + //~^ ERROR mismatched types + //~| different fn items have unique types, even if their signatures are the same + + // suggest removing reference + let c: fn(u32) -> u32 = &foo; + //~^ ERROR mismatched types + //~| expected fn pointer `fn(u32) -> u32` + //~| found reference `&fn(u32) -> u32 {foo}` + + // suggest using reference + let d: &fn(u32) -> u32 = foo; + //~^ ERROR mismatched types + //~| expected reference `&fn(u32) -> u32` + //~| found fn item `fn(u32) -> u32 {foo}` + + // suggest casting with reference + let e: &fn(u32) -> u32 = &foo; + //~^ ERROR mismatched types + //~| expected reference `&fn(u32) -> u32` + //~| found reference `&fn(u32) -> u32 {foo}` + + // OK + let mut z: fn(u32) -> u32 = foo as fn(u32) -> u32; + z = bar; +} diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr new file mode 100644 index 00000000000..e0bd60fbc0b --- /dev/null +++ b/tests/ui/fn/fn-pointer-mismatch.stderr @@ -0,0 +1,84 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/fn-pointer-mismatch.rs:11:43 + | +LL | let g = if n % 2 == 0 { &foo } else { &bar }; + | ---- ^^^^ expected fn item, found a different fn item + | | + | expected because of this + | + = note: expected reference `&fn(u32) -> u32 {foo}` + found reference `&fn(u32) -> u32 {bar}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32` + +error[E0308]: mismatched types + --> $DIR/fn-pointer-mismatch.rs:23:9 + | +LL | let mut a = foo; + | --- expected due to this value +LL | a = bar; + | ^^^ expected fn item, found a different fn item + | + = note: expected fn item `fn(_) -> _ {foo}` + found fn item `fn(_) -> _ {bar}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32` + +error[E0308]: mismatched types + --> $DIR/fn-pointer-mismatch.rs:31:18 + | +LL | b = Box::new(bar); + | -------- ^^^ expected fn item, found a different fn item + | | + | arguments to this function are incorrect + | + = note: expected fn item `fn(_) -> _ {foo}` + found fn item `fn(_) -> _ {bar}` + = note: different fn items have unique types, even if their signatures are the same +note: associated function defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32` + +error[E0308]: mismatched types + --> $DIR/fn-pointer-mismatch.rs:36:29 + | +LL | let c: fn(u32) -> u32 = &foo; + | -------------- ^^^^ + | | | + | | expected fn pointer, found reference + | | help: consider removing the reference: `foo` + | expected due to this + | + = note: expected fn pointer `fn(u32) -> u32` + found reference `&fn(u32) -> u32 {foo}` + +error[E0308]: mismatched types + --> $DIR/fn-pointer-mismatch.rs:42:30 + | +LL | let d: &fn(u32) -> u32 = foo; + | --------------- ^^^ + | | | + | | expected `&fn(u32) -> u32`, found fn item + | | help: consider using a reference: `&foo` + | expected due to this + | + = note: expected reference `&fn(u32) -> u32` + found fn item `fn(u32) -> u32 {foo}` + +error[E0308]: mismatched types + --> $DIR/fn-pointer-mismatch.rs:48:30 + | +LL | let e: &fn(u32) -> u32 = &foo; + | --------------- ^^^^ + | | | + | | expected fn pointer, found fn item + | | help: consider casting to a fn pointer: `&(foo as fn(u32) -> u32)` + | expected due to this + | + = note: expected reference `&fn(u32) -> u32` + found reference `&fn(u32) -> u32 {foo}` + = note: fn items are distinct from fn pointers + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr index fcbaa91d19f..4df639232a3 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type-4.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10 | +LL | let x = String::from("Hello World!"); + | - binding `x` declared here LL | let y = f(&x, ()); | -- borrow of `x` occurs here LL | drop(x); diff --git a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr index e35f46e4439..d417f288393 100644 --- a/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr +++ b/tests/ui/fn/implied-bounds-unnorm-associated-type.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10 | +LL | let x = String::from("Hello World!"); + | - binding `x` declared here LL | let y = f(&x, ()); | -- borrow of `x` occurs here LL | drop(x); diff --git a/tests/ui/generator/addassign-yield.rs b/tests/ui/generator/addassign-yield.rs index 66f22bf31fc..7211367afee 100644 --- a/tests/ui/generator/addassign-yield.rs +++ b/tests/ui/generator/addassign-yield.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // run-pass // Regression test for broken MIR error (#61442) // Due to the two possible evaluation orders for diff --git a/tests/ui/generator/auto-trait-regions.drop_tracking.stderr b/tests/ui/generator/auto-trait-regions.drop_tracking.stderr new file mode 100644 index 00000000000..165748d4430 --- /dev/null +++ b/tests/ui/generator/auto-trait-regions.drop_tracking.stderr @@ -0,0 +1,47 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:48:24 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:48:35 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: implementation of `Foo` is not general enough + --> $DIR/auto-trait-regions.rs:34:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` + +error: implementation of `Foo` is not general enough + --> $DIR/auto-trait-regions.rs:54:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr b/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr new file mode 100644 index 00000000000..165748d4430 --- /dev/null +++ b/tests/ui/generator/auto-trait-regions.drop_tracking_mir.stderr @@ -0,0 +1,47 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:48:24 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:48:35 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: implementation of `Foo` is not general enough + --> $DIR/auto-trait-regions.rs:34:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` + +error: implementation of `Foo` is not general enough + --> $DIR/auto-trait-regions.rs:54:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr b/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr new file mode 100644 index 00000000000..165748d4430 --- /dev/null +++ b/tests/ui/generator/auto-trait-regions.no_drop_tracking.stderr @@ -0,0 +1,47 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:48:24 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/auto-trait-regions.rs:48:35 + | +LL | let a = A(&mut true, &mut true, No); + | ^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | assert_foo(a); + | - borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: implementation of `Foo` is not general enough + --> $DIR/auto-trait-regions.rs:34:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` + +error: implementation of `Foo` is not general enough + --> $DIR/auto-trait-regions.rs:54:5 + | +LL | assert_foo(gen); + | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough + | + = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/generator/auto-trait-regions.rs b/tests/ui/generator/auto-trait-regions.rs index ea4b0d554cd..fd13e41319f 100644 --- a/tests/ui/generator/auto-trait-regions.rs +++ b/tests/ui/generator/auto-trait-regions.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(generators)] #![feature(auto_traits)] #![feature(negative_impls)] diff --git a/tests/ui/generator/auto-trait-regions.stderr b/tests/ui/generator/auto-trait-regions.stderr index 0b1f34aeb96..165748d4430 100644 --- a/tests/ui/generator/auto-trait-regions.stderr +++ b/tests/ui/generator/auto-trait-regions.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/auto-trait-regions.rs:45:24 + --> $DIR/auto-trait-regions.rs:48:24 | LL | let a = A(&mut true, &mut true, No); | ^^^^ - temporary value is freed at the end of this statement @@ -12,7 +12,7 @@ LL | assert_foo(a); = note: consider using a `let` binding to create a longer lived value error[E0716]: temporary value dropped while borrowed - --> $DIR/auto-trait-regions.rs:45:35 + --> $DIR/auto-trait-regions.rs:48:35 | LL | let a = A(&mut true, &mut true, No); | ^^^^ - temporary value is freed at the end of this statement @@ -25,7 +25,7 @@ LL | assert_foo(a); = note: consider using a `let` binding to create a longer lived value error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:31:5 + --> $DIR/auto-trait-regions.rs:34:5 | LL | assert_foo(gen); | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough @@ -34,7 +34,7 @@ LL | assert_foo(gen); = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:51:5 + --> $DIR/auto-trait-regions.rs:54:5 | LL | assert_foo(gen); | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough diff --git a/tests/ui/generator/borrowing.drop_tracking.stderr b/tests/ui/generator/borrowing.drop_tracking.stderr new file mode 100644 index 00000000000..96e3c327f8b --- /dev/null +++ b/tests/ui/generator/borrowing.drop_tracking.stderr @@ -0,0 +1,31 @@ +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:13:33 + | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; +LL | Pin::new(&mut || yield &a).resume(()) + | -- ^ borrowed value does not live long enough + | | + | value captured here by generator +LL | +LL | }; + | - `a` dropped here while still borrowed + +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:20:20 + | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; +LL | || { + | -- value captured here by generator +LL | yield &a + | ^ borrowed value does not live long enough +... +LL | }; + | - `a` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/generator/borrowing.drop_tracking_mir.stderr b/tests/ui/generator/borrowing.drop_tracking_mir.stderr new file mode 100644 index 00000000000..8fbad276db4 --- /dev/null +++ b/tests/ui/generator/borrowing.drop_tracking_mir.stderr @@ -0,0 +1,39 @@ +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:13:33 + | +LL | Pin::new(&mut || yield &a).resume(()) + | ----------^ + | | | + | | borrowed value does not live long enough + | value captured here by generator + | a temporary with access to the borrow is created here ... +LL | +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator + | | + | `a` dropped here while still borrowed + | + = note: the temporary is part of an expression at the end of a block; + consider forcing this temporary to be dropped sooner, before the block's local variables are dropped +help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block + | +LL | let x = Pin::new(&mut || yield &a).resume(()); x + | +++++++ +++ + +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:20:20 + | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; +LL | || { + | -- value captured here by generator +LL | yield &a + | ^ borrowed value does not live long enough +... +LL | }; + | - `a` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/generator/borrowing.no_drop_tracking.stderr b/tests/ui/generator/borrowing.no_drop_tracking.stderr new file mode 100644 index 00000000000..96e3c327f8b --- /dev/null +++ b/tests/ui/generator/borrowing.no_drop_tracking.stderr @@ -0,0 +1,31 @@ +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:13:33 + | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; +LL | Pin::new(&mut || yield &a).resume(()) + | -- ^ borrowed value does not live long enough + | | + | value captured here by generator +LL | +LL | }; + | - `a` dropped here while still borrowed + +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:20:20 + | +LL | let _b = { + | -- borrow later stored here +LL | let a = 3; +LL | || { + | -- value captured here by generator +LL | yield &a + | ^ borrowed value does not live long enough +... +LL | }; + | - `a` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/generator/borrowing.rs b/tests/ui/generator/borrowing.rs index d36592583cd..29f39437f8f 100644 --- a/tests/ui/generator/borrowing.rs +++ b/tests/ui/generator/borrowing.rs @@ -1,3 +1,7 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + #![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/tests/ui/generator/borrowing.stderr b/tests/ui/generator/borrowing.stderr index 38e1ace8c4e..96e3c327f8b 100644 --- a/tests/ui/generator/borrowing.stderr +++ b/tests/ui/generator/borrowing.stderr @@ -1,5 +1,5 @@ error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:9:33 + --> $DIR/borrowing.rs:13:33 | LL | let _b = { | -- borrow later stored here @@ -13,7 +13,7 @@ LL | }; | - `a` dropped here while still borrowed error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:16:20 + --> $DIR/borrowing.rs:20:20 | LL | let _b = { | -- borrow later stored here diff --git a/tests/ui/generator/drop-tracking-parent-expression.stderr b/tests/ui/generator/drop-tracking-parent-expression.drop_tracking.stderr index fbf5d6e0725..c07906ec37d 100644 --- a/tests/ui/generator/drop-tracking-parent-expression.stderr +++ b/tests/ui/generator/drop-tracking-parent-expression.drop_tracking.stderr @@ -1,5 +1,5 @@ error: generator cannot be sent between threads safely - --> $DIR/drop-tracking-parent-expression.rs:24:25 + --> $DIR/drop-tracking-parent-expression.rs:27:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -13,9 +13,9 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `derived_drop::Client` + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/drop-tracking-parent-expression.rs:22:22 + --> $DIR/drop-tracking-parent-expression.rs:25:22 | LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { | ------------------------ has type `derived_drop::Client` which is not `Send` @@ -34,14 +34,14 @@ LL | | }; LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/drop-tracking-parent-expression.rs:41:19 + --> $DIR/drop-tracking-parent-expression.rs:49:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/drop-tracking-parent-expression.rs:24:25 + --> $DIR/drop-tracking-parent-expression.rs:27:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -55,9 +55,9 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `significant_drop::Client` + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/drop-tracking-parent-expression.rs:22:22 + --> $DIR/drop-tracking-parent-expression.rs:25:22 | LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { | ------------------------ has type `significant_drop::Client` which is not `Send` @@ -76,14 +76,14 @@ LL | | }; LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/drop-tracking-parent-expression.rs:41:19 + --> $DIR/drop-tracking-parent-expression.rs:49:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/drop-tracking-parent-expression.rs:24:25 + --> $DIR/drop-tracking-parent-expression.rs:27:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -97,9 +97,9 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/drop-tracking-parent-expression.rs:22:22 + --> $DIR/drop-tracking-parent-expression.rs:25:22 | LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { | ------------------------ has type `insignificant_dtor::Client` which is not `Send` @@ -118,7 +118,7 @@ LL | | }; LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/drop-tracking-parent-expression.rs:41:19 + --> $DIR/drop-tracking-parent-expression.rs:49:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` diff --git a/tests/ui/generator/drop-tracking-parent-expression.drop_tracking_mir.stderr b/tests/ui/generator/drop-tracking-parent-expression.drop_tracking_mir.stderr new file mode 100644 index 00000000000..35698a98dbd --- /dev/null +++ b/tests/ui/generator/drop-tracking-parent-expression.drop_tracking_mir.stderr @@ -0,0 +1,122 @@ +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/generator/drop-tracking-parent-expression.no_drop_tracking.stderr b/tests/ui/generator/drop-tracking-parent-expression.no_drop_tracking.stderr new file mode 100644 index 00000000000..1a05bfe4f0e --- /dev/null +++ b/tests/ui/generator/drop-tracking-parent-expression.no_drop_tracking.stderr @@ -0,0 +1,334 @@ +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `copy::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `copy::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `copy::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `copy::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + diff --git a/tests/ui/generator/drop-tracking-parent-expression.rs b/tests/ui/generator/drop-tracking-parent-expression.rs index d40f1b8f64d..ed9ac6d11ad 100644 --- a/tests/ui/generator/drop-tracking-parent-expression.rs +++ b/tests/ui/generator/drop-tracking-parent-expression.rs @@ -1,4 +1,7 @@ -// compile-flags: -Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + #![feature(generators, negative_impls, rustc_attrs)] macro_rules! type_combinations { @@ -18,13 +21,14 @@ macro_rules! type_combinations { let g = move || match drop($name::Client { ..$name::Client::default() }) { //~^ `significant_drop::Client` which is not `Send` //~| `insignificant_dtor::Client` which is not `Send` - //~| `derived_drop::Client` which is not `Send` + //[no_drop_tracking,drop_tracking]~| `derived_drop::Client` which is not `Send` _ => yield, }; assert_send(g); //~^ ERROR cannot be sent between threads //~| ERROR cannot be sent between threads //~| ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads } // Simple owned value. This works because the Client is considered moved into `drop`, @@ -34,6 +38,10 @@ macro_rules! type_combinations { _ => yield, }; assert_send(g); + //[no_drop_tracking]~^ ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads } )* } } diff --git a/tests/ui/generator/drop-tracking-yielding-in-match-guards.rs b/tests/ui/generator/drop-tracking-yielding-in-match-guards.rs index 646365e4359..cbc291701cb 100644 --- a/tests/ui/generator/drop-tracking-yielding-in-match-guards.rs +++ b/tests/ui/generator/drop-tracking-yielding-in-match-guards.rs @@ -1,6 +1,8 @@ // build-pass // edition:2018 -// compile-flags: -Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(generators)] diff --git a/tests/ui/generator/dropck.stderr b/tests/ui/generator/dropck.stderr index 7bb188352d7..b9a3a124acb 100644 --- a/tests/ui/generator/dropck.stderr +++ b/tests/ui/generator/dropck.stderr @@ -1,6 +1,9 @@ error[E0597]: `*cell` does not live long enough --> $DIR/dropck.rs:10:40 | +LL | let (mut gen, cell); + | ---- binding `cell` declared here +LL | cell = Box::new(RefCell::new(0)); LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); | ^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/generator/issue-105084.drop_tracking_mir.stderr b/tests/ui/generator/issue-105084.drop_tracking_mir.stderr new file mode 100644 index 00000000000..cfc0cf7cdd7 --- /dev/null +++ b/tests/ui/generator/issue-105084.drop_tracking_mir.stderr @@ -0,0 +1,51 @@ +error[E0382]: borrow of moved value: `g` + --> $DIR/issue-105084.rs:44:14 + | +LL | let mut g = || { + | ----- move occurs because `g` has type `[generator@$DIR/issue-105084.rs:22:17: 22:19]`, which does not implement the `Copy` trait +... +LL | let mut h = copy(g); + | - value moved here +... +LL | Pin::new(&mut g).resume(()); + | ^^^^^^ value borrowed here after move + | +note: consider changing this parameter type in function `copy` to borrow instead if owning the value isn't necessary + --> $DIR/issue-105084.rs:17:21 + | +LL | fn copy<T: Copy>(x: T) -> T { + | ---- ^ this parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | let mut h = copy(g.clone()); + | ++++++++ + +error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `[generator@$DIR/issue-105084.rs:22:17: 22:19]` + --> $DIR/issue-105084.rs:38:17 + | +LL | let mut g = || { + | -- within this `[generator@$DIR/issue-105084.rs:22:17: 22:19]` +... +LL | let mut h = copy(g); + | ^^^^ within `[generator@$DIR/issue-105084.rs:22:17: 22:19]`, the trait `Copy` is not implemented for `Box<(i32, ())>` + | +note: generator does not implement `Copy` as this value is used across a yield + --> $DIR/issue-105084.rs:28:25 + | +LL | let t = box (5, yield); + | --------^^^^^- + | | | + | | yield occurs here, with `box (5, yield)` maybe used later + | has type `Box<(i32, ())>` which does not implement `Copy` +note: required by a bound in `copy` + --> $DIR/issue-105084.rs:17:12 + | +LL | fn copy<T: Copy>(x: T) -> T { + | ^^^^ required by this bound in `copy` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0382. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/issue-105084.rs b/tests/ui/generator/issue-105084.rs new file mode 100644 index 00000000000..7c9a97b40a5 --- /dev/null +++ b/tests/ui/generator/issue-105084.rs @@ -0,0 +1,49 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// [no_drop_tracking] known-bug: #105084 +// [no_drop_tracking] check-pass +// [drop_tracking] known-bug: #105084 +// [drop_tracking] check-pass + +#![feature(generators)] +#![feature(generator_clone)] +#![feature(generator_trait)] +#![feature(box_syntax)] + +use std::ops::Generator; +use std::pin::Pin; + +fn copy<T: Copy>(x: T) -> T { + x +} + +fn main() { + let mut g = || { + // This is desuraged as 4 stages: + // - allocate a `*mut u8` with `exchange_malloc`; + // - create a Box that is ignored for trait computations; + // - compute fields (and yields); + // - assign to `t`. + let t = box (5, yield); + drop(t); + }; + + // Allocate the temporary box. + Pin::new(&mut g).resume(()); + + // The temporary box is in generator locals. + // As it is not taken into account for trait computation, + // the generator is `Copy`. + let mut h = copy(g); + //[drop_tracking_mir]~^ ERROR the trait bound `Box<(i32, ())>: Copy` is not satisfied in + + // We now have 2 boxes with the same backing allocation: + // one inside `g` and one inside `h`. + // Proceed and drop `t` in `g`. + Pin::new(&mut g).resume(()); + //[drop_tracking_mir]~^ ERROR borrow of moved value: `g` + + // Proceed and drop `t` in `h` -> double free! + Pin::new(&mut h).resume(()); +} diff --git a/tests/ui/generator/issue-57017.no_drop_tracking.stderr b/tests/ui/generator/issue-57017.no_drop_tracking.stderr new file mode 100644 index 00000000000..06d2d23b9ef --- /dev/null +++ b/tests/ui/generator/issue-57017.no_drop_tracking.stderr @@ -0,0 +1,248 @@ +error: generator cannot be sent between threads safely + --> $DIR/issue-57017.rs:31:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation + | + = help: the trait `Sync` is not implemented for `copy::unsync::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57017.rs:29:28 + | +LL | let g = move || match drop(&$name::unsync::Client::default()) { + | --------------------------------- has type `©::unsync::Client` which is not `Send` +LL | _status => yield, + | ^^^^^ yield occurs here, with `&$name::unsync::Client::default()` maybe used later +LL | }; + | - `&$name::unsync::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/issue-57017.rs:51:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/issue-57017.rs:43:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `copy::unsend::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57017.rs:41:28 + | +LL | let g = move || match drop($name::unsend::Client::default()) { + | -------------------------------- has type `copy::unsend::Client` which is not `Send` +LL | _status => yield, + | ^^^^^ yield occurs here, with `$name::unsend::Client::default()` maybe used later +LL | }; + | - `$name::unsend::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/issue-57017.rs:51:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/issue-57017.rs:31:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation + | + = help: the trait `Sync` is not implemented for `derived_drop::unsync::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57017.rs:29:28 + | +LL | let g = move || match drop(&$name::unsync::Client::default()) { + | --------------------------------- has type `&derived_drop::unsync::Client` which is not `Send` +LL | _status => yield, + | ^^^^^ yield occurs here, with `&$name::unsync::Client::default()` maybe used later +LL | }; + | - `&$name::unsync::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/issue-57017.rs:51:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/issue-57017.rs:43:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `derived_drop::unsend::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57017.rs:41:28 + | +LL | let g = move || match drop($name::unsend::Client::default()) { + | -------------------------------- has type `derived_drop::unsend::Client` which is not `Send` +LL | _status => yield, + | ^^^^^ yield occurs here, with `$name::unsend::Client::default()` maybe used later +LL | }; + | - `$name::unsend::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/issue-57017.rs:51:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/issue-57017.rs:31:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation + | + = help: the trait `Sync` is not implemented for `significant_drop::unsync::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57017.rs:29:28 + | +LL | let g = move || match drop(&$name::unsync::Client::default()) { + | --------------------------------- has type `&significant_drop::unsync::Client` which is not `Send` +LL | _status => yield, + | ^^^^^ yield occurs here, with `&$name::unsync::Client::default()` maybe used later +LL | }; + | - `&$name::unsync::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/issue-57017.rs:51:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/issue-57017.rs:43:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `significant_drop::unsend::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57017.rs:41:28 + | +LL | let g = move || match drop($name::unsend::Client::default()) { + | -------------------------------- has type `significant_drop::unsend::Client` which is not `Send` +LL | _status => yield, + | ^^^^^ yield occurs here, with `$name::unsend::Client::default()` maybe used later +LL | }; + | - `$name::unsend::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; +LL | | significant_drop => { +... | +LL | | } +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/issue-57017.rs:51:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + diff --git a/tests/ui/generator/issue-57017.rs b/tests/ui/generator/issue-57017.rs index c0bde3b4473..03b00ac99ad 100644 --- a/tests/ui/generator/issue-57017.rs +++ b/tests/ui/generator/issue-57017.rs @@ -1,5 +1,9 @@ -// build-pass -// compile-flags: -Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// [drop_tracking] build-pass +// [drop_tracking_mir] build-pass + #![feature(generators, negative_impls)] macro_rules! type_combinations { @@ -25,6 +29,9 @@ macro_rules! type_combinations { _status => yield, }; assert_send(g); + //[no_drop_tracking]~^ ERROR generator cannot be sent between threads safely + //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely + //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely } // This tests that `Client` is properly considered to be dropped after moving it into the @@ -34,6 +41,9 @@ macro_rules! type_combinations { _status => yield, }; assert_send(g); + //[no_drop_tracking]~^ ERROR generator cannot be sent between threads safely + //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely + //[no_drop_tracking]~| ERROR generator cannot be sent between threads safely } )* } } diff --git a/tests/ui/generator/issue-57478.no_drop_tracking.stderr b/tests/ui/generator/issue-57478.no_drop_tracking.stderr new file mode 100644 index 00000000000..612dd9c37f7 --- /dev/null +++ b/tests/ui/generator/issue-57478.no_drop_tracking.stderr @@ -0,0 +1,31 @@ +error: generator cannot be sent between threads safely + --> $DIR/issue-57478.rs:13:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let guard = Foo; +LL | | drop(guard); +LL | | yield; +LL | | }) + | |_____^ generator is not `Send` + | + = help: within `[generator@$DIR/issue-57478.rs:13:17: 13:19]`, the trait `Send` is not implemented for `Foo` +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-57478.rs:17:9 + | +LL | let guard = Foo; + | ----- has type `Foo` which is not `Send` +LL | drop(guard); +LL | yield; + | ^^^^^ yield occurs here, with `guard` maybe used later +LL | }) + | - `guard` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/issue-57478.rs:21:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + diff --git a/tests/ui/generator/issue-57478.rs b/tests/ui/generator/issue-57478.rs index 91407ea1844..3c23b599271 100644 --- a/tests/ui/generator/issue-57478.rs +++ b/tests/ui/generator/issue-57478.rs @@ -1,5 +1,8 @@ -// check-pass -// compile-flags: -Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// [drop_tracking] check-pass +// [drop_tracking_mir] check-pass #![feature(negative_impls, generators)] @@ -8,6 +11,7 @@ impl !Send for Foo {} fn main() { assert_send(|| { + //[no_drop_tracking]~^ ERROR generator cannot be sent between threads safely let guard = Foo; drop(guard); yield; diff --git a/tests/ui/generator/issue-68112.stderr b/tests/ui/generator/issue-68112.drop_tracking.stderr index eb99d42c920..282eac1b686 100644 --- a/tests/ui/generator/issue-68112.stderr +++ b/tests/ui/generator/issue-68112.drop_tracking.stderr @@ -1,12 +1,13 @@ error: generator cannot be sent between threads safely - --> $DIR/issue-68112.rs:40:18 + --> $DIR/issue-68112.rs:43:18 | LL | require_send(send_gen); | ^^^^^^^^ generator is not `Send` | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-68112.rs:36:9 + --> $DIR/issue-68112.rs:39:9 | LL | let _non_send_gen = make_non_send_generator(); | ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send` @@ -17,13 +18,13 @@ LL | yield; LL | }; | - `_non_send_gen` is later dropped here note: required by a bound in `require_send` - --> $DIR/issue-68112.rs:22:25 + --> $DIR/issue-68112.rs:25:25 | LL | fn require_send(_: impl Send) {} | ^^^^ required by this bound in `require_send` error[E0277]: `RefCell<i32>` cannot be shared between threads safely - --> $DIR/issue-68112.rs:63:18 + --> $DIR/issue-68112.rs:67:18 | LL | require_send(send_gen); | ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely @@ -31,30 +32,31 @@ LL | require_send(send_gen); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this generator - --> $DIR/issue-68112.rs:48:5 + --> $DIR/issue-68112.rs:52:5 | LL | || { | ^^ note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` - --> $DIR/issue-68112.rs:45:30 + --> $DIR/issue-68112.rs:49:30 | LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` - --> $DIR/issue-68112.rs:53:34 + --> $DIR/issue-68112.rs:57:34 | LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: required because it captures the following types: `impl Generator<Return = Arc<RefCell<i32>>>`, `()` note: required because it's used within this generator - --> $DIR/issue-68112.rs:59:20 + --> $DIR/issue-68112.rs:63:20 | LL | let send_gen = || { | ^^ note: required by a bound in `require_send` - --> $DIR/issue-68112.rs:22:25 + --> $DIR/issue-68112.rs:25:25 | LL | fn require_send(_: impl Send) {} | ^^^^ required by this bound in `require_send` diff --git a/tests/ui/generator/issue-68112.drop_tracking_mir.stderr b/tests/ui/generator/issue-68112.drop_tracking_mir.stderr new file mode 100644 index 00000000000..a83522b714d --- /dev/null +++ b/tests/ui/generator/issue-68112.drop_tracking_mir.stderr @@ -0,0 +1,61 @@ +error: generator cannot be sent between threads safely + --> $DIR/issue-68112.rs:43:5 + | +LL | require_send(send_gen); + | ^^^^^^^^^^^^ generator is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-68112.rs:39:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send` +LL | +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:25:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error[E0277]: `RefCell<i32>` cannot be shared between threads safely + --> $DIR/issue-68112.rs:67:5 + | +LL | require_send(send_gen); + | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead + = note: required for `Arc<RefCell<i32>>` to implement `Send` +note: required because it's used within this generator + --> $DIR/issue-68112.rs:52:5 + | +LL | || { + | ^^ +note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` + --> $DIR/issue-68112.rs:49:30 + | +LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` + --> $DIR/issue-68112.rs:57:34 + | +LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `impl Generator<Return = Arc<RefCell<i32>>>` +note: required because it's used within this generator + --> $DIR/issue-68112.rs:63:20 + | +LL | let send_gen = || { + | ^^ +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:25:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/issue-68112.no_drop_tracking.stderr b/tests/ui/generator/issue-68112.no_drop_tracking.stderr new file mode 100644 index 00000000000..282eac1b686 --- /dev/null +++ b/tests/ui/generator/issue-68112.no_drop_tracking.stderr @@ -0,0 +1,66 @@ +error: generator cannot be sent between threads safely + --> $DIR/issue-68112.rs:43:18 + | +LL | require_send(send_gen); + | ^^^^^^^^ generator is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: generator is not `Send` as this value is used across a yield + --> $DIR/issue-68112.rs:39:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send` +LL | +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +... +LL | }; + | - `_non_send_gen` is later dropped here +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:25:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error[E0277]: `RefCell<i32>` cannot be shared between threads safely + --> $DIR/issue-68112.rs:67:18 + | +LL | require_send(send_gen); + | ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead + = note: required for `Arc<RefCell<i32>>` to implement `Send` +note: required because it's used within this generator + --> $DIR/issue-68112.rs:52:5 + | +LL | || { + | ^^ +note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` + --> $DIR/issue-68112.rs:49:30 + | +LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` + --> $DIR/issue-68112.rs:57:34 + | +LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `impl Generator<Return = Arc<RefCell<i32>>>`, `()` +note: required because it's used within this generator + --> $DIR/issue-68112.rs:63:20 + | +LL | let send_gen = || { + | ^^ +note: required by a bound in `require_send` + --> $DIR/issue-68112.rs:25:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/issue-68112.rs b/tests/ui/generator/issue-68112.rs index 21026f45cb8..48b53b7693d 100644 --- a/tests/ui/generator/issue-68112.rs +++ b/tests/ui/generator/issue-68112.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(generators, generator_trait)] use std::{ @@ -8,7 +11,7 @@ use std::{ }; pub struct Ready<T>(Option<T>); -impl<T> Generator<()> for Ready<T> { +impl<T: Unpin> Generator<()> for Ready<T> { type Return = T; type Yield = (); fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> { @@ -36,10 +39,11 @@ fn test1() { yield; //~^ NOTE yield occurs here //~| NOTE value is used across a yield - }; //~ NOTE later dropped here + }; //[no_drop_tracking,drop_tracking]~ NOTE later dropped here require_send(send_gen); //~^ ERROR generator cannot be sent between threads //~| NOTE not `Send` + //~| NOTE use `std::sync::RwLock` instead } pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { @@ -64,8 +68,9 @@ fn test2() { //~^ ERROR `RefCell<i32>` cannot be shared between threads safely //~| NOTE `RefCell<i32>` cannot be shared between threads safely //~| NOTE required for - //~| NOTE required by a bound introduced by this call + //[no_drop_tracking,drop_tracking]~| NOTE required by a bound introduced by this call //~| NOTE captures the following types + //~| NOTE use `std::sync::RwLock` instead } fn main() {} diff --git a/tests/ui/generator/issue-93161.rs b/tests/ui/generator/issue-93161.rs index 92305609c83..8d3f7c62f39 100644 --- a/tests/ui/generator/issue-93161.rs +++ b/tests/ui/generator/issue-93161.rs @@ -1,6 +1,8 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2021 // run-pass -// compile-flags: -Zdrop-tracking #![feature(never_type)] diff --git a/tests/ui/generator/not-send-sync.drop_tracking.stderr b/tests/ui/generator/not-send-sync.drop_tracking.stderr new file mode 100644 index 00000000000..718fd42245a --- /dev/null +++ b/tests/ui/generator/not-send-sync.drop_tracking.stderr @@ -0,0 +1,60 @@ +error: generator cannot be shared between threads safely + --> $DIR/not-send-sync.rs:17:17 + | +LL | assert_sync(|| { + | _________________^ +LL | | +LL | | let a = NotSync; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Sync` + | + = help: within `[generator@$DIR/not-send-sync.rs:17:17: 17:19]`, the trait `Sync` is not implemented for `NotSync` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/not-send-sync.rs:20:9 + | +LL | let a = NotSync; + | - has type `NotSync` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_sync` + --> $DIR/not-send-sync.rs:14:23 + | +LL | fn assert_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `assert_sync` + +error: generator cannot be sent between threads safely + --> $DIR/not-send-sync.rs:24:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let a = NotSend; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Send` + | + = help: within `[generator@$DIR/not-send-sync.rs:24:17: 24:19]`, the trait `Send` is not implemented for `NotSend` +note: generator is not `Send` as this value is used across a yield + --> $DIR/not-send-sync.rs:27:9 + | +LL | let a = NotSend; + | - has type `NotSend` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/not-send-sync.rs:15:23 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/not-send-sync.drop_tracking_mir.stderr b/tests/ui/generator/not-send-sync.drop_tracking_mir.stderr new file mode 100644 index 00000000000..66f01ae37d8 --- /dev/null +++ b/tests/ui/generator/not-send-sync.drop_tracking_mir.stderr @@ -0,0 +1,42 @@ +error: generator cannot be shared between threads safely + --> $DIR/not-send-sync.rs:17:5 + | +LL | assert_sync(|| { + | ^^^^^^^^^^^ generator is not `Sync` + | + = help: within `[generator@$DIR/not-send-sync.rs:17:17: 17:19]`, the trait `Sync` is not implemented for `NotSync` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/not-send-sync.rs:20:9 + | +LL | let a = NotSync; + | - has type `NotSync` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +note: required by a bound in `assert_sync` + --> $DIR/not-send-sync.rs:14:23 + | +LL | fn assert_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `assert_sync` + +error: generator cannot be sent between threads safely + --> $DIR/not-send-sync.rs:24:5 + | +LL | assert_send(|| { + | ^^^^^^^^^^^ generator is not `Send` + | + = help: within `[generator@$DIR/not-send-sync.rs:24:17: 24:19]`, the trait `Send` is not implemented for `NotSend` +note: generator is not `Send` as this value is used across a yield + --> $DIR/not-send-sync.rs:27:9 + | +LL | let a = NotSend; + | - has type `NotSend` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +note: required by a bound in `assert_send` + --> $DIR/not-send-sync.rs:15:23 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/not-send-sync.no_drop_tracking.stderr b/tests/ui/generator/not-send-sync.no_drop_tracking.stderr new file mode 100644 index 00000000000..718fd42245a --- /dev/null +++ b/tests/ui/generator/not-send-sync.no_drop_tracking.stderr @@ -0,0 +1,60 @@ +error: generator cannot be shared between threads safely + --> $DIR/not-send-sync.rs:17:17 + | +LL | assert_sync(|| { + | _________________^ +LL | | +LL | | let a = NotSync; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Sync` + | + = help: within `[generator@$DIR/not-send-sync.rs:17:17: 17:19]`, the trait `Sync` is not implemented for `NotSync` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/not-send-sync.rs:20:9 + | +LL | let a = NotSync; + | - has type `NotSync` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_sync` + --> $DIR/not-send-sync.rs:14:23 + | +LL | fn assert_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `assert_sync` + +error: generator cannot be sent between threads safely + --> $DIR/not-send-sync.rs:24:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let a = NotSend; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Send` + | + = help: within `[generator@$DIR/not-send-sync.rs:24:17: 24:19]`, the trait `Send` is not implemented for `NotSend` +note: generator is not `Send` as this value is used across a yield + --> $DIR/not-send-sync.rs:27:9 + | +LL | let a = NotSend; + | - has type `NotSend` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/not-send-sync.rs:15:23 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/not-send-sync.rs b/tests/ui/generator/not-send-sync.rs index 8ca5565fb2a..8794db452b4 100644 --- a/tests/ui/generator/not-send-sync.rs +++ b/tests/ui/generator/not-send-sync.rs @@ -1,6 +1,14 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(generators)] +#![feature(negative_impls)] -use std::cell::Cell; +struct NotSend; +struct NotSync; + +impl !Send for NotSend {} +impl !Sync for NotSync {} fn main() { fn assert_sync<T: Sync>(_: T) {} @@ -8,14 +16,15 @@ fn main() { assert_sync(|| { //~^ ERROR: generator cannot be shared between threads safely - let a = Cell::new(2); + let a = NotSync; yield; + drop(a); }); - let a = Cell::new(2); assert_send(|| { - //~^ ERROR: E0277 - drop(&a); + //~^ ERROR: generator cannot be sent between threads safely + let a = NotSend; yield; + drop(a); }); } diff --git a/tests/ui/generator/not-send-sync.stderr b/tests/ui/generator/not-send-sync.stderr deleted file mode 100644 index a821c57b923..00000000000 --- a/tests/ui/generator/not-send-sync.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error[E0277]: `Cell<i32>` cannot be shared between threads safely - --> $DIR/not-send-sync.rs:16:17 - | -LL | assert_send(|| { - | _____-----------_^ - | | | - | | required by a bound introduced by this call -LL | | -LL | | drop(&a); -LL | | yield; -LL | | }); - | |_____^ `Cell<i32>` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `Cell<i32>` - = note: required for `&Cell<i32>` to implement `Send` -note: required because it's used within this generator - --> $DIR/not-send-sync.rs:16:17 - | -LL | assert_send(|| { - | ^^ -note: required by a bound in `assert_send` - --> $DIR/not-send-sync.rs:7:23 - | -LL | fn assert_send<T: Send>(_: T) {} - | ^^^^ required by this bound in `assert_send` - -error: generator cannot be shared between threads safely - --> $DIR/not-send-sync.rs:9:17 - | -LL | assert_sync(|| { - | _________________^ -LL | | -LL | | let a = Cell::new(2); -LL | | yield; -LL | | }); - | |_____^ generator is not `Sync` - | - = help: within `[generator@$DIR/not-send-sync.rs:9:17: 9:19]`, the trait `Sync` is not implemented for `Cell<i32>` -note: generator is not `Sync` as this value is used across a yield - --> $DIR/not-send-sync.rs:12:9 - | -LL | let a = Cell::new(2); - | - has type `Cell<i32>` which is not `Sync` -LL | yield; - | ^^^^^ yield occurs here, with `a` maybe used later -LL | }); - | - `a` is later dropped here -note: required by a bound in `assert_sync` - --> $DIR/not-send-sync.rs:6:23 - | -LL | fn assert_sync<T: Sync>(_: T) {} - | ^^^^ required by this bound in `assert_sync` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/parent-expression.drop_tracking.stderr b/tests/ui/generator/parent-expression.drop_tracking.stderr new file mode 100644 index 00000000000..ef489088bf8 --- /dev/null +++ b/tests/ui/generator/parent-expression.drop_tracking.stderr @@ -0,0 +1,128 @@ +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/generator/parent-expression.drop_tracking_mir.stderr b/tests/ui/generator/parent-expression.drop_tracking_mir.stderr new file mode 100644 index 00000000000..bf814456427 --- /dev/null +++ b/tests/ui/generator/parent-expression.drop_tracking_mir.stderr @@ -0,0 +1,122 @@ +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/generator/parent-expression.no_drop_tracking.stderr b/tests/ui/generator/parent-expression.no_drop_tracking.stderr new file mode 100644 index 00000000000..2e1313a8004 --- /dev/null +++ b/tests/ui/generator/parent-expression.no_drop_tracking.stderr @@ -0,0 +1,334 @@ +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `copy::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `copy::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `copy::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `copy::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:27:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:21:21: 21:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:25:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/parent-expression.rs:40:25 + | +LL | assert_send(g); + | ^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/parent-expression.rs:37:21: 37:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/parent-expression.rs:38:22 + | +LL | let g = move || match drop($name::Client::default()) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/parent-expression.rs:49:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + diff --git a/tests/ui/generator/parent-expression.rs b/tests/ui/generator/parent-expression.rs new file mode 100644 index 00000000000..239034e3d4e --- /dev/null +++ b/tests/ui/generator/parent-expression.rs @@ -0,0 +1,77 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + +#![feature(generators, negative_impls, rustc_attrs)] + +macro_rules! type_combinations { + ( + $( $name:ident => { $( $tt:tt )* } );* $(;)? + ) => { $( + mod $name { + $( $tt )* + + impl !Sync for Client {} + impl !Send for Client {} + } + + // Struct update syntax. This fails because the Client used in the update is considered + // dropped *after* the yield. + { + let g = move || match drop($name::Client { ..$name::Client::default() }) { + //~^ `significant_drop::Client` which is not `Send` + //~| `insignificant_dtor::Client` which is not `Send` + //~| `derived_drop::Client` which is not `Send` + _ => yield, + }; + assert_send(g); + //~^ ERROR cannot be sent between threads + //~| ERROR cannot be sent between threads + //~| ERROR cannot be sent between threads + //[no_drop_tracking]~^^^^ ERROR cannot be sent between threads + } + + // Simple owned value. This works because the Client is considered moved into `drop`, + // even though the temporary expression doesn't end until after the yield. + { + let g = move || match drop($name::Client::default()) { + _ => yield, + }; + assert_send(g); + //[no_drop_tracking]~^ ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads + //[no_drop_tracking]~| ERROR cannot be sent between threads + } + )* } +} + +fn assert_send<T: Send>(_thing: T) {} + +fn main() { + type_combinations!( + // OK + copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; + // NOT OK: MIR borrowck thinks that this is used after the yield, even though + // this has no `Drop` impl and only the drops of the fields are observable. + // FIXME: this should compile. + derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; + // NOT OK + significant_drop => { + #[derive(Default)] + pub struct Client; + impl Drop for Client { + fn drop(&mut self) {} + } + }; + // NOT OK (we need to agree with MIR borrowck) + insignificant_dtor => { + #[derive(Default)] + #[rustc_insignificant_dtor] + pub struct Client; + impl Drop for Client { + fn drop(&mut self) {} + } + }; + ); +} diff --git a/tests/ui/generator/partial-drop.stderr b/tests/ui/generator/partial-drop.drop_tracking.stderr index 9baafe54e84..f1b25cb8c34 100644 --- a/tests/ui/generator/partial-drop.stderr +++ b/tests/ui/generator/partial-drop.drop_tracking.stderr @@ -1,19 +1,18 @@ error: generator cannot be sent between threads safely - --> $DIR/partial-drop.rs:14:17 + --> $DIR/partial-drop.rs:17:17 | LL | assert_send(|| { | _________________^ LL | | -LL | | // FIXME: it would be nice to make this work. LL | | let guard = Bar { foo: Foo, x: 42 }; LL | | drop(guard.foo); LL | | yield; LL | | }); | |_____^ generator is not `Send` | - = help: within `[generator@$DIR/partial-drop.rs:14:17: 14:19]`, the trait `Send` is not implemented for `Foo` + = help: within `[generator@$DIR/partial-drop.rs:17:17: 17:19]`, the trait `Send` is not implemented for `Foo` note: generator is not `Send` as this value is used across a yield - --> $DIR/partial-drop.rs:19:9 + --> $DIR/partial-drop.rs:21:9 | LL | let guard = Bar { foo: Foo, x: 42 }; | ----- has type `Bar` which is not `Send` @@ -23,25 +22,25 @@ LL | yield; LL | }); | - `guard` is later dropped here note: required by a bound in `assert_send` - --> $DIR/partial-drop.rs:42:19 + --> $DIR/partial-drop.rs:33:19 | LL | fn assert_send<T: Send>(_: T) {} | ^^^^ required by this bound in `assert_send` error: generator cannot be sent between threads safely - --> $DIR/partial-drop.rs:22:17 + --> $DIR/partial-drop.rs:24:17 | LL | assert_send(|| { | _________________^ LL | | -LL | | // FIXME: it would be nice to make this work. LL | | let guard = Bar { foo: Foo, x: 42 }; -... | +LL | | let Bar { foo, x } = guard; +LL | | drop(foo); LL | | yield; LL | | }); | |_____^ generator is not `Send` | - = help: within `[generator@$DIR/partial-drop.rs:22:17: 22:19]`, the trait `Send` is not implemented for `Foo` + = help: within `[generator@$DIR/partial-drop.rs:24:17: 24:19]`, the trait `Send` is not implemented for `Foo` note: generator is not `Send` as this value is used across a yield --> $DIR/partial-drop.rs:29:9 | @@ -53,40 +52,10 @@ LL | yield; LL | }); | - `guard` is later dropped here note: required by a bound in `assert_send` - --> $DIR/partial-drop.rs:42:19 + --> $DIR/partial-drop.rs:33:19 | LL | fn assert_send<T: Send>(_: T) {} | ^^^^ required by this bound in `assert_send` -error: generator cannot be sent between threads safely - --> $DIR/partial-drop.rs:32:17 - | -LL | assert_send(|| { - | _________________^ -LL | | -LL | | // FIXME: it would be nice to make this work. -LL | | let guard = Bar { foo: Foo, x: 42 }; -... | -LL | | yield; -LL | | }); - | |_____^ generator is not `Send` - | - = help: within `[generator@$DIR/partial-drop.rs:32:17: 32:19]`, the trait `Send` is not implemented for `Foo` -note: generator is not `Send` as this value is used across a yield - --> $DIR/partial-drop.rs:38:9 - | -LL | let guard = Bar { foo: Foo, x: 42 }; - | ----- has type `Bar` which is not `Send` -... -LL | yield; - | ^^^^^ yield occurs here, with `guard` maybe used later -LL | }); - | - `guard` is later dropped here -note: required by a bound in `assert_send` - --> $DIR/partial-drop.rs:42:19 - | -LL | fn assert_send<T: Send>(_: T) {} - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/generator/partial-drop.no_drop_tracking.stderr b/tests/ui/generator/partial-drop.no_drop_tracking.stderr new file mode 100644 index 00000000000..91152b5ea6f --- /dev/null +++ b/tests/ui/generator/partial-drop.no_drop_tracking.stderr @@ -0,0 +1,61 @@ +error: generator cannot be sent between threads safely + --> $DIR/partial-drop.rs:17:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let guard = Bar { foo: Foo, x: 42 }; +LL | | drop(guard.foo); +LL | | yield; +LL | | }); + | |_____^ generator is not `Send` + | + = help: within `[generator@$DIR/partial-drop.rs:17:17: 17:19]`, the trait `Send` is not implemented for `Foo` +note: generator is not `Send` as this value is used across a yield + --> $DIR/partial-drop.rs:21:9 + | +LL | let guard = Bar { foo: Foo, x: 42 }; + | ----- has type `Bar` which is not `Send` +LL | drop(guard.foo); +LL | yield; + | ^^^^^ yield occurs here, with `guard` maybe used later +LL | }); + | - `guard` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/partial-drop.rs:33:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: generator cannot be sent between threads safely + --> $DIR/partial-drop.rs:24:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let guard = Bar { foo: Foo, x: 42 }; +LL | | let Bar { foo, x } = guard; +LL | | drop(foo); +LL | | yield; +LL | | }); + | |_____^ generator is not `Send` + | + = help: within `[generator@$DIR/partial-drop.rs:24:17: 24:19]`, the trait `Send` is not implemented for `Foo` +note: generator is not `Send` as this value is used across a yield + --> $DIR/partial-drop.rs:29:9 + | +LL | let Bar { foo, x } = guard; + | --- has type `Foo` which is not `Send` +LL | drop(foo); +LL | yield; + | ^^^^^ yield occurs here, with `foo` maybe used later +LL | }); + | - `foo` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/partial-drop.rs:33:19 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/partial-drop.rs b/tests/ui/generator/partial-drop.rs index c872fb7f3e6..1d3ae075d43 100644 --- a/tests/ui/generator/partial-drop.rs +++ b/tests/ui/generator/partial-drop.rs @@ -1,4 +1,7 @@ -// compile-flags: -Zdrop-tracking +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir +// [drop_tracking_mir] check-pass #![feature(negative_impls, generators)] @@ -12,26 +15,14 @@ struct Bar { fn main() { assert_send(|| { - //~^ ERROR generator cannot be sent between threads safely - // FIXME: it would be nice to make this work. + //[no_drop_tracking,drop_tracking]~^ ERROR generator cannot be sent between threads safely let guard = Bar { foo: Foo, x: 42 }; drop(guard.foo); yield; }); assert_send(|| { - //~^ ERROR generator cannot be sent between threads safely - // FIXME: it would be nice to make this work. - let guard = Bar { foo: Foo, x: 42 }; - drop(guard); - guard.foo = Foo; - guard.x = 23; - yield; - }); - - assert_send(|| { - //~^ ERROR generator cannot be sent between threads safely - // FIXME: it would be nice to make this work. + //[no_drop_tracking,drop_tracking]~^ ERROR generator cannot be sent between threads safely let guard = Bar { foo: Foo, x: 42 }; let Bar { foo, x } = guard; drop(foo); diff --git a/tests/ui/generator/print/generator-print-verbose-1.stderr b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr index ebf35be581c..7d0a201699b 100644 --- a/tests/ui/generator/print/generator-print-verbose-1.stderr +++ b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr @@ -1,12 +1,13 @@ error: generator cannot be sent between threads safely - --> $DIR/generator-print-verbose-1.rs:37:18 + --> $DIR/generator-print-verbose-1.rs:40:18 | LL | require_send(send_gen); | ^^^^^^^^ generator is not `Send` | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: generator is not `Send` as this value is used across a yield - --> $DIR/generator-print-verbose-1.rs:35:9 + --> $DIR/generator-print-verbose-1.rs:38:9 | LL | let _non_send_gen = make_non_send_generator(); | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send` @@ -15,13 +16,13 @@ LL | yield; LL | }; | - `_non_send_gen` is later dropped here note: required by a bound in `require_send` - --> $DIR/generator-print-verbose-1.rs:26:25 + --> $DIR/generator-print-verbose-1.rs:29:25 | LL | fn require_send(_: impl Send) {} | ^^^^ required by this bound in `require_send` error[E0277]: `RefCell<i32>` cannot be shared between threads safely - --> $DIR/generator-print-verbose-1.rs:56:18 + --> $DIR/generator-print-verbose-1.rs:59:18 | LL | require_send(send_gen); | ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely @@ -29,30 +30,31 @@ LL | require_send(send_gen); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` note: required because it's used within this generator - --> $DIR/generator-print-verbose-1.rs:42:5 + --> $DIR/generator-print-verbose-1.rs:45:5 | LL | || { | ^^ note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])` - --> $DIR/generator-print-verbose-1.rs:41:30 + --> $DIR/generator-print-verbose-1.rs:44:30 | LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` - --> $DIR/generator-print-verbose-1.rs:47:34 + --> $DIR/generator-print-verbose-1.rs:50:34 | LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()` note: required because it's used within this generator - --> $DIR/generator-print-verbose-1.rs:52:20 + --> $DIR/generator-print-verbose-1.rs:55:20 | LL | let send_gen = || { | ^^ note: required by a bound in `require_send` - --> $DIR/generator-print-verbose-1.rs:26:25 + --> $DIR/generator-print-verbose-1.rs:29:25 | LL | fn require_send(_: impl Send) {} | ^^^^ required by this bound in `require_send` diff --git a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr new file mode 100644 index 00000000000..c045b1441c1 --- /dev/null +++ b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr @@ -0,0 +1,60 @@ +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-1.rs:40:5 + | +LL | require_send(send_gen); + | ^^^^^^^^^^^^ generator is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-1.rs:38:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +note: required by a bound in `require_send` + --> $DIR/generator-print-verbose-1.rs:29:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error[E0277]: `RefCell<i32>` cannot be shared between threads safely + --> $DIR/generator-print-verbose-1.rs:59:5 + | +LL | require_send(send_gen); + | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead + = note: required for `Arc<RefCell<i32>>` to implement `Send` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-1.rs:45:5 + | +LL | || { + | ^^ +note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])` + --> $DIR/generator-print-verbose-1.rs:44:30 + | +LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` + --> $DIR/generator-print-verbose-1.rs:50:34 + | +LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-1.rs:55:20 + | +LL | let send_gen = || { + | ^^ +note: required by a bound in `require_send` + --> $DIR/generator-print-verbose-1.rs:29:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr new file mode 100644 index 00000000000..7d0a201699b --- /dev/null +++ b/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr @@ -0,0 +1,64 @@ +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-1.rs:40:18 + | +LL | require_send(send_gen); + | ^^^^^^^^ generator is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-1.rs:38:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +LL | }; + | - `_non_send_gen` is later dropped here +note: required by a bound in `require_send` + --> $DIR/generator-print-verbose-1.rs:29:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error[E0277]: `RefCell<i32>` cannot be shared between threads safely + --> $DIR/generator-print-verbose-1.rs:59:18 + | +LL | require_send(send_gen); + | ------------ ^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead + = note: required for `Arc<RefCell<i32>>` to implement `Send` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-1.rs:45:5 + | +LL | || { + | ^^ +note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])` + --> $DIR/generator-print-verbose-1.rs:44:30 + | +LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])` + --> $DIR/generator-print-verbose-1.rs:50:34 + | +LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()` +note: required because it's used within this generator + --> $DIR/generator-print-verbose-1.rs:55:20 + | +LL | let send_gen = || { + | ^^ +note: required by a bound in `require_send` + --> $DIR/generator-print-verbose-1.rs:29:25 + | +LL | fn require_send(_: impl Send) {} + | ^^^^ required by this bound in `require_send` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/print/generator-print-verbose-1.rs b/tests/ui/generator/print/generator-print-verbose-1.rs index 89124ad7289..c7052c7d1b0 100644 --- a/tests/ui/generator/print/generator-print-verbose-1.rs +++ b/tests/ui/generator/print/generator-print-verbose-1.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // compile-flags: -Zverbose // Same as: tests/ui/generator/issue-68112.stderr @@ -12,7 +15,7 @@ use std::{ }; pub struct Ready<T>(Option<T>); -impl<T> Generator<()> for Ready<T> { +impl<T: Unpin> Generator<()> for Ready<T> { type Return = T; type Yield = (); fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> { diff --git a/tests/ui/generator/print/generator-print-verbose-2.drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-2.drop_tracking.stderr new file mode 100644 index 00000000000..1f2e530f6f5 --- /dev/null +++ b/tests/ui/generator/print/generator-print-verbose-2.drop_tracking.stderr @@ -0,0 +1,60 @@ +error: generator cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:20:17 + | +LL | assert_sync(|| { + | _________________^ +LL | | +LL | | let a = NotSync; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Sync` + | + = help: within `[main::{closure#0} upvar_tys=() {NotSync, ()}]`, the trait `Sync` is not implemented for `NotSync` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:23:9 + | +LL | let a = NotSync; + | - has type `NotSync` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_sync` + --> $DIR/generator-print-verbose-2.rs:17:23 + | +LL | fn assert_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `assert_sync` + +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-2.rs:27:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let a = NotSend; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Send` + | + = help: within `[main::{closure#1} upvar_tys=() {NotSend, ()}]`, the trait `Send` is not implemented for `NotSend` +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:30:9 + | +LL | let a = NotSend; + | - has type `NotSend` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/generator-print-verbose-2.rs:18:23 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/print/generator-print-verbose-2.drop_tracking_mir.stderr b/tests/ui/generator/print/generator-print-verbose-2.drop_tracking_mir.stderr new file mode 100644 index 00000000000..354369f1954 --- /dev/null +++ b/tests/ui/generator/print/generator-print-verbose-2.drop_tracking_mir.stderr @@ -0,0 +1,42 @@ +error: generator cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:20:5 + | +LL | assert_sync(|| { + | ^^^^^^^^^^^ generator is not `Sync` + | + = help: within `[main::{closure#0} upvar_tys=() [main::{closure#0}]]`, the trait `Sync` is not implemented for `NotSync` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:23:9 + | +LL | let a = NotSync; + | - has type `NotSync` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +note: required by a bound in `assert_sync` + --> $DIR/generator-print-verbose-2.rs:17:23 + | +LL | fn assert_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `assert_sync` + +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-2.rs:27:5 + | +LL | assert_send(|| { + | ^^^^^^^^^^^ generator is not `Send` + | + = help: within `[main::{closure#1} upvar_tys=() [main::{closure#1}]]`, the trait `Send` is not implemented for `NotSend` +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:30:9 + | +LL | let a = NotSend; + | - has type `NotSend` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +note: required by a bound in `assert_send` + --> $DIR/generator-print-verbose-2.rs:18:23 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/print/generator-print-verbose-2.no_drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-2.no_drop_tracking.stderr new file mode 100644 index 00000000000..1f2e530f6f5 --- /dev/null +++ b/tests/ui/generator/print/generator-print-verbose-2.no_drop_tracking.stderr @@ -0,0 +1,60 @@ +error: generator cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:20:17 + | +LL | assert_sync(|| { + | _________________^ +LL | | +LL | | let a = NotSync; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Sync` + | + = help: within `[main::{closure#0} upvar_tys=() {NotSync, ()}]`, the trait `Sync` is not implemented for `NotSync` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:23:9 + | +LL | let a = NotSync; + | - has type `NotSync` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_sync` + --> $DIR/generator-print-verbose-2.rs:17:23 + | +LL | fn assert_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `assert_sync` + +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-2.rs:27:17 + | +LL | assert_send(|| { + | _________________^ +LL | | +LL | | let a = NotSend; +LL | | yield; +LL | | drop(a); +LL | | }); + | |_____^ generator is not `Send` + | + = help: within `[main::{closure#1} upvar_tys=() {NotSend, ()}]`, the trait `Send` is not implemented for `NotSend` +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:30:9 + | +LL | let a = NotSend; + | - has type `NotSend` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | drop(a); +LL | }); + | - `a` is later dropped here +note: required by a bound in `assert_send` + --> $DIR/generator-print-verbose-2.rs:18:23 + | +LL | fn assert_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generator/print/generator-print-verbose-2.rs b/tests/ui/generator/print/generator-print-verbose-2.rs index d914719cb36..ab29db6e09c 100644 --- a/tests/ui/generator/print/generator-print-verbose-2.rs +++ b/tests/ui/generator/print/generator-print-verbose-2.rs @@ -1,9 +1,17 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // compile-flags: -Zverbose // Same as test/ui/generator/not-send-sync.rs #![feature(generators)] +#![feature(negative_impls)] -use std::cell::Cell; +struct NotSend; +struct NotSync; + +impl !Send for NotSend {} +impl !Sync for NotSync {} fn main() { fn assert_sync<T: Sync>(_: T) {} @@ -11,14 +19,15 @@ fn main() { assert_sync(|| { //~^ ERROR: generator cannot be shared between threads safely - let a = Cell::new(2); + let a = NotSync; yield; + drop(a); }); - let a = Cell::new(2); assert_send(|| { - //~^ ERROR: E0277 - drop(&a); + //~^ ERROR: generator cannot be sent between threads safely + let a = NotSend; yield; + drop(a); }); } diff --git a/tests/ui/generator/print/generator-print-verbose-2.stderr b/tests/ui/generator/print/generator-print-verbose-2.stderr deleted file mode 100644 index 909e49c38b8..00000000000 --- a/tests/ui/generator/print/generator-print-verbose-2.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error[E0277]: `Cell<i32>` cannot be shared between threads safely - --> $DIR/generator-print-verbose-2.rs:19:17 - | -LL | assert_send(|| { - | _____-----------_^ - | | | - | | required by a bound introduced by this call -LL | | -LL | | drop(&a); -LL | | yield; -LL | | }); - | |_____^ `Cell<i32>` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `Cell<i32>` - = note: required for `&'_#4r Cell<i32>` to implement `Send` -note: required because it's used within this generator - --> $DIR/generator-print-verbose-2.rs:19:17 - | -LL | assert_send(|| { - | ^^ -note: required by a bound in `assert_send` - --> $DIR/generator-print-verbose-2.rs:10:23 - | -LL | fn assert_send<T: Send>(_: T) {} - | ^^^^ required by this bound in `assert_send` - -error: generator cannot be shared between threads safely - --> $DIR/generator-print-verbose-2.rs:12:17 - | -LL | assert_sync(|| { - | _________________^ -LL | | -LL | | let a = Cell::new(2); -LL | | yield; -LL | | }); - | |_____^ generator is not `Sync` - | - = help: within `[main::{closure#0} upvar_tys=() {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>` -note: generator is not `Sync` as this value is used across a yield - --> $DIR/generator-print-verbose-2.rs:15:9 - | -LL | let a = Cell::new(2); - | - has type `Cell<i32>` which is not `Sync` -LL | yield; - | ^^^^^ yield occurs here, with `a` maybe used later -LL | }); - | - `a` is later dropped here -note: required by a bound in `assert_sync` - --> $DIR/generator-print-verbose-2.rs:9:23 - | -LL | fn assert_sync<T: Sync>(_: T) {} - | ^^^^ required by this bound in `assert_sync` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generator/retain-resume-ref.drop_tracking.stderr b/tests/ui/generator/retain-resume-ref.drop_tracking.stderr new file mode 100644 index 00000000000..7122a951e80 --- /dev/null +++ b/tests/ui/generator/retain-resume-ref.drop_tracking.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `thing` as mutable more than once at a time + --> $DIR/retain-resume-ref.rs:27:25 + | +LL | gen.as_mut().resume(&mut thing); + | ---------- first mutable borrow occurs here +LL | gen.as_mut().resume(&mut thing); + | ------ ^^^^^^^^^^ second mutable borrow occurs here + | | + | first borrow later used by call + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/generator/retain-resume-ref.drop_tracking_mir.stderr b/tests/ui/generator/retain-resume-ref.drop_tracking_mir.stderr new file mode 100644 index 00000000000..736ed1fb608 --- /dev/null +++ b/tests/ui/generator/retain-resume-ref.drop_tracking_mir.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `thing` as mutable more than once at a time + --> $DIR/retain-resume-ref.rs:27:25 + | +LL | gen.as_mut().resume(&mut thing); + | ---------- first mutable borrow occurs here +LL | gen.as_mut().resume(&mut thing); + | ^^^^^^^^^^ second mutable borrow occurs here +LL | +LL | } + | - first borrow might be used here, when `gen` is dropped and runs the destructor for generator + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/generator/retain-resume-ref.no_drop_tracking.stderr b/tests/ui/generator/retain-resume-ref.no_drop_tracking.stderr new file mode 100644 index 00000000000..7122a951e80 --- /dev/null +++ b/tests/ui/generator/retain-resume-ref.no_drop_tracking.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `thing` as mutable more than once at a time + --> $DIR/retain-resume-ref.rs:27:25 + | +LL | gen.as_mut().resume(&mut thing); + | ---------- first mutable borrow occurs here +LL | gen.as_mut().resume(&mut thing); + | ------ ^^^^^^^^^^ second mutable borrow occurs here + | | + | first borrow later used by call + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/generator/retain-resume-ref.rs b/tests/ui/generator/retain-resume-ref.rs index 0606ea71cdf..0050d98d03b 100644 --- a/tests/ui/generator/retain-resume-ref.rs +++ b/tests/ui/generator/retain-resume-ref.rs @@ -1,3 +1,7 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + //! This test ensures that a mutable reference cannot be passed as a resume argument twice. #![feature(generators, generator_trait)] diff --git a/tests/ui/generator/retain-resume-ref.stderr b/tests/ui/generator/retain-resume-ref.stderr index e33310d12d9..7122a951e80 100644 --- a/tests/ui/generator/retain-resume-ref.stderr +++ b/tests/ui/generator/retain-resume-ref.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `thing` as mutable more than once at a time - --> $DIR/retain-resume-ref.rs:23:25 + --> $DIR/retain-resume-ref.rs:27:25 | LL | gen.as_mut().resume(&mut thing); | ---------- first mutable borrow occurs here diff --git a/tests/ui/generator/static-mut-reference-across-yield.rs b/tests/ui/generator/static-mut-reference-across-yield.rs index 0fa6d9cdc77..4784ff49be2 100644 --- a/tests/ui/generator/static-mut-reference-across-yield.rs +++ b/tests/ui/generator/static-mut-reference-across-yield.rs @@ -1,6 +1,8 @@ // build-pass -// revisions: mir thir +// revisions: mir thir drop_tracking drop_tracking_mir // [thir]compile-flags: -Zthir-unsafeck +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir #![feature(generators)] diff --git a/tests/ui/generic-associated-types/issue-74684-1.stderr b/tests/ui/generic-associated-types/issue-74684-1.stderr index cacc973077c..b93ee37987f 100644 --- a/tests/ui/generic-associated-types/issue-74684-1.stderr +++ b/tests/ui/generic-associated-types/issue-74684-1.stderr @@ -4,6 +4,7 @@ error[E0597]: `a` does not live long enough LL | fn bug<'a, T: ?Sized + Fun<F<'a> = [u8]>>(_ : Box<T>) -> &'static T::F<'a> { | -- lifetime `'a` defined here LL | let a = [0; 1]; + | - binding `a` declared here LL | let _x = T::identity(&a); | ------------^^- | | | diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs new file mode 100644 index 00000000000..7ba2b6d857c --- /dev/null +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs @@ -0,0 +1,8 @@ +fn main() { + let x = 42; + match x { + 0..=73 => {}, + 74..=> {}, //~ ERROR unexpected `=>` after open range + //~^ ERROR expected one of `=>`, `if`, or `|`, found `>` + } +} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr new file mode 100644 index 00000000000..9ba6d15113c --- /dev/null +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr @@ -0,0 +1,19 @@ +error: unexpected `=>` after open range + --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11 + | +LL | 74..=> {}, + | ^^^ + | +help: add a space between the pattern and `=>` + | +LL | 74.. => {}, + | + + +error: expected one of `=>`, `if`, or `|`, found `>` + --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14 + | +LL | 74..=> {}, + | ^ expected one of `=>`, `if`, or `|` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr index 4886a3c8bad..25af011e3fc 100644 --- a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr +++ b/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/hrtb-identity-fn-borrows.rs:14:5 | LL | let y = f.call(&x); - | -- borrow of `x` occurs here + | -- `x` is borrowed here LL | x = 5; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed ... LL | drop(y); | - borrow later used here diff --git a/tests/ui/impl-trait/feature-self-return-type.stderr b/tests/ui/impl-trait/feature-self-return-type.stderr index 601e53b7694..b9b8d00ce30 100644 --- a/tests/ui/impl-trait/feature-self-return-type.stderr +++ b/tests/ui/impl-trait/feature-self-return-type.stderr @@ -4,6 +4,7 @@ error[E0597]: `bar` does not live long enough LL | let x = { | - borrow later stored here LL | let bar = 22; + | --- binding `bar` declared here LL | Foo::new(&bar).into() | ^^^^ borrowed value does not live long enough LL | @@ -16,6 +17,7 @@ error[E0597]: `y` does not live long enough LL | let x = { | - borrow later stored here LL | let y = (); + | - binding `y` declared here LL | foo(&y) | ^^ borrowed value does not live long enough LL | @@ -28,6 +30,7 @@ error[E0597]: `y` does not live long enough LL | let x = { | - borrow later stored here LL | let y = (); + | - binding `y` declared here LL | foo(&y) | ^^ borrowed value does not live long enough LL | diff --git a/tests/ui/impl-trait/issue-55872-2.drop_tracking.stderr b/tests/ui/impl-trait/issue-55872-2.drop_tracking.stderr new file mode 100644 index 00000000000..477c964bd40 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-2.drop_tracking.stderr @@ -0,0 +1,8 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-2.rs:17:9 + | +LL | async {} + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-55872-2.drop_tracking_mir.stderr b/tests/ui/impl-trait/issue-55872-2.drop_tracking_mir.stderr new file mode 100644 index 00000000000..c14bb5cc914 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-2.drop_tracking_mir.stderr @@ -0,0 +1,14 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-2.rs:17:9 + | +LL | async {} + | ^^^^^^^^ + +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-2.rs:17:9 + | +LL | async {} + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/issue-55872-2.no_drop_tracking.stderr b/tests/ui/impl-trait/issue-55872-2.no_drop_tracking.stderr new file mode 100644 index 00000000000..477c964bd40 --- /dev/null +++ b/tests/ui/impl-trait/issue-55872-2.no_drop_tracking.stderr @@ -0,0 +1,8 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-2.rs:17:9 + | +LL | async {} + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/issue-55872-2.rs b/tests/ui/impl-trait/issue-55872-2.rs index 4443d3c4d0d..cbc7b5d62e1 100644 --- a/tests/ui/impl-trait/issue-55872-2.rs +++ b/tests/ui/impl-trait/issue-55872-2.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 #![feature(type_alias_impl_trait)] @@ -13,6 +16,7 @@ impl<S> Bar for S { fn foo<T>() -> Self::E { async {} //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //[drop_tracking_mir]~^^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias } } diff --git a/tests/ui/impl-trait/issue-55872-2.stderr b/tests/ui/impl-trait/issue-55872-2.stderr index 11b8485c8bb..477c964bd40 100644 --- a/tests/ui/impl-trait/issue-55872-2.stderr +++ b/tests/ui/impl-trait/issue-55872-2.stderr @@ -1,5 +1,5 @@ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-2.rs:14:9 + --> $DIR/issue-55872-2.rs:17:9 | LL | async {} | ^^^^^^^^ diff --git a/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr b/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr index 16a1262ec27..92a3290622e 100644 --- a/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr +++ b/tests/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr @@ -8,13 +8,13 @@ LL | Foo(bar()) | ---------- returning here with type `Foo<impl Quux>` ... LL | fn bar() -> impl Quux { - | --------- returning this opaque type `Foo<impl Quux>` + | --------- returning this type `Foo<impl Quux>` error[E0720]: cannot resolve opaque type --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 | LL | fn foo() -> impl Quux { - | --------- returning this opaque type `Bar<impl Quux>` + | --------- returning this type `Bar<impl Quux>` ... LL | fn bar() -> impl Quux { | ^^^^^^^^^ recursive opaque type diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking.stderr index ebb231ae14f..43118ae3854 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking.stderr @@ -1,5 +1,5 @@ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:7:22 + --> $DIR/recursive-impl-trait-type-indirect.rs:11:22 | LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -10,7 +10,7 @@ LL | if i < 0 { None } else { Some((option(i - 1), i)) } | returning here with type `Option<(impl Sized, i32)>` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:16:15 | LL | fn tuple() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -19,7 +19,7 @@ LL | (tuple(),) | ---------- returning here with type `(impl Sized,)` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:17:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:21:15 | LL | fn array() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -28,7 +28,7 @@ LL | [array()] | --------- returning here with type `[impl Sized; 1]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:22:13 + --> $DIR/recursive-impl-trait-type-indirect.rs:26:13 | LL | fn ptr() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -37,7 +37,7 @@ LL | &ptr() as *const _ | ------------------ returning here with type `*const impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:27:16 + --> $DIR/recursive-impl-trait-type-indirect.rs:31:16 | LL | fn fn_ptr() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -46,7 +46,7 @@ LL | fn_ptr as fn() -> _ | ------------------- returning here with type `fn() -> impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:32:25 + --> $DIR/recursive-impl-trait-type-indirect.rs:36:25 | LL | fn closure_capture() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -55,10 +55,10 @@ LL | / move || { LL | | x; | | - closure captures itself here LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:39:5: 39:12]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 + --> $DIR/recursive-impl-trait-type-indirect.rs:44:29 | LL | fn closure_ref_capture() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -67,28 +67,28 @@ LL | / move || { LL | | &x; | | - closure captures itself here LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:47:5: 47:12]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 + --> $DIR/recursive-impl-trait-type-indirect.rs:52:21 | LL | fn closure_sig() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | || closure_sig() - | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7]` + | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 + --> $DIR/recursive-impl-trait-type-indirect.rs:57:23 | LL | fn generator_sig() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | || generator_sig() - | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7]` + | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:59:5: 59:7]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 + --> $DIR/recursive-impl-trait-type-indirect.rs:62:27 | LL | fn generator_capture() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -98,10 +98,10 @@ LL | | yield; LL | | x; | | - generator captures itself here LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:65:5: 65:12]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 + --> $DIR/recursive-impl-trait-type-indirect.rs:71:35 | LL | fn substs_change<T: 'static>() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -110,7 +110,7 @@ LL | (substs_change::<&T>(),) | ------------------------ returning here with type `(impl Sized,)` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 + --> $DIR/recursive-impl-trait-type-indirect.rs:76:24 | LL | fn generator_hold() -> impl Sized { | ^^^^^^^^^^ recursive opaque type @@ -121,10 +121,10 @@ LL | | let x = generator_hold(); LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 74:12]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:78:5: 78:12]` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:90:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ recursive opaque type @@ -136,7 +136,7 @@ LL | fn mutual_recursion_b() -> impl Sized { | ---------- returning this opaque type `impl Sized` error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:95:28 | LL | fn mutual_recursion() -> impl Sync { | --------- returning this opaque type `impl Sync` diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr new file mode 100644 index 00000000000..662c74bcdc0 --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr @@ -0,0 +1,144 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:11:22 + | +LL | fn option(i: i32) -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | if i < 0 { None } else { Some((option(i - 1), i)) } + | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>` + | | + | returning here with type `Option<(impl Sized, i32)>` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:16:15 + | +LL | fn tuple() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (tuple(),) + | ---------- returning here with type `(impl Sized,)` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:21:15 + | +LL | fn array() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | [array()] + | --------- returning here with type `[impl Sized; 1]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:26:13 + | +LL | fn ptr() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | &ptr() as *const _ + | ------------------ returning here with type `*const impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:31:16 + | +LL | fn fn_ptr() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | fn_ptr as fn() -> _ + | ------------------- returning here with type `fn() -> impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:36:25 + | +LL | fn closure_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | x; + | | - closure captures itself here +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:39:5: 39:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:44:29 + | +LL | fn closure_ref_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | &x; + | | - closure captures itself here +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:47:5: 47:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:52:21 + | +LL | fn closure_sig() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || closure_sig() + | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:57:23 + | +LL | fn generator_sig() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || generator_sig() + | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:59:5: 59:7]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:62:27 + | +LL | fn generator_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | yield; +LL | | x; + | | - generator captures itself here +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:65:5: 65:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:71:35 + | +LL | fn substs_change<T: 'static>() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (substs_change::<&T>(),) + | ------------------------ returning here with type `(impl Sized,)` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:76:24 + | +LL | fn generator_hold() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:90:26 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion_b() + | -------------------- returning here with type `impl Sized` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ---------- returning this opaque type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:95:28 + | +LL | fn mutual_recursion() -> impl Sync { + | --------- returning this opaque type `impl Sync` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion() + | ------------------ returning here with type `impl Sync` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.no_drop_tracking.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.no_drop_tracking.stderr new file mode 100644 index 00000000000..43118ae3854 --- /dev/null +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.no_drop_tracking.stderr @@ -0,0 +1,152 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:11:22 + | +LL | fn option(i: i32) -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | if i < 0 { None } else { Some((option(i - 1), i)) } + | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>` + | | + | returning here with type `Option<(impl Sized, i32)>` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:16:15 + | +LL | fn tuple() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (tuple(),) + | ---------- returning here with type `(impl Sized,)` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:21:15 + | +LL | fn array() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | [array()] + | --------- returning here with type `[impl Sized; 1]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:26:13 + | +LL | fn ptr() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | &ptr() as *const _ + | ------------------ returning here with type `*const impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:31:16 + | +LL | fn fn_ptr() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | fn_ptr as fn() -> _ + | ------------------- returning here with type `fn() -> impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:36:25 + | +LL | fn closure_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | x; + | | - closure captures itself here +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:39:5: 39:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:44:29 + | +LL | fn closure_ref_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | &x; + | | - closure captures itself here +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:47:5: 47:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:52:21 + | +LL | fn closure_sig() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || closure_sig() + | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:57:23 + | +LL | fn generator_sig() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || generator_sig() + | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:59:5: 59:7]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:62:27 + | +LL | fn generator_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | yield; +LL | | x; + | | - generator captures itself here +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:65:5: 65:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:71:35 + | +LL | fn substs_change<T: 'static>() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (substs_change::<&T>(),) + | ------------------------ returning here with type `(impl Sized,)` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:76:24 + | +LL | fn generator_hold() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | / move || { +LL | | let x = generator_hold(); + | | - generator captures itself here +LL | | yield; +LL | | x; +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:78:5: 78:12]` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:90:26 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion_b() + | -------------------- returning here with type `impl Sized` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ---------- returning this opaque type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:95:28 + | +LL | fn mutual_recursion() -> impl Sync { + | --------- returning this opaque type `impl Sync` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion() + | ------------------ returning here with type `impl Sync` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs index ffc0cd9d10c..630372e13ed 100644 --- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -1,3 +1,7 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + // Test that impl trait does not allow creating recursive types that are // otherwise forbidden. diff --git a/tests/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr b/tests/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr index d0249e74f39..307899297bc 100644 --- a/tests/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr +++ b/tests/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/assoc-ty-wf-used-to-get-assoc-ty.rs:24:31 | +LL | let x: u8 = 3; + | - binding `x` declared here LL | let _: &'static u8 = test(&x, &&3); | -----^^------ | | | diff --git a/tests/ui/imports/import-prefix-macro-1.stderr b/tests/ui/imports/import-prefix-macro-1.stderr index 8868ee3aeaa..a6a5b1393da 100644 --- a/tests/ui/imports/import-prefix-macro-1.stderr +++ b/tests/ui/imports/import-prefix-macro-1.stderr @@ -2,7 +2,7 @@ error: expected one of `::`, `;`, or `as`, found `{` --> $DIR/import-prefix-macro-1.rs:11:27 | LL | ($p: path) => (use $p {S, Z}); - | ^^^^^^ expected one of `::`, `;`, or `as` + | ^ expected one of `::`, `;`, or `as` ... LL | import! { a::b::c } | ------------------- in this macro invocation diff --git a/tests/ui/inline-const/const-expr-lifetime-err.stderr b/tests/ui/inline-const/const-expr-lifetime-err.stderr index a23f7c9a796..443fcf89c4e 100644 --- a/tests/ui/inline-const/const-expr-lifetime-err.stderr +++ b/tests/ui/inline-const/const-expr-lifetime-err.stderr @@ -4,6 +4,7 @@ error[E0597]: `y` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let y = (); + | - binding `y` declared here LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW }); | ------------------^^- | | | diff --git a/tests/ui/io-checks/inaccessbile-temp-dir.rs b/tests/ui/io-checks/inaccessbile-temp-dir.rs new file mode 100644 index 00000000000..9c0aa013572 --- /dev/null +++ b/tests/ui/io-checks/inaccessbile-temp-dir.rs @@ -0,0 +1,39 @@ +// Issue #66530: We would ICE if someone compiled with `-o /dev/null`, +// because we would try to generate auxiliary files in `/dev/` (which +// at least the OS X file system rejects). +// +// An attempt to `-o` into a directory we cannot write into should indeed +// be an error; but not an ICE. +// +// However, some folks run tests as root, which can write `/dev/` and end +// up clobbering `/dev/null`. Instead we'll use a non-existent path, which +// also used to ICE, but even root can't magically write there. + +// compile-flags: -Z temps-dir=/does-not-exist/output + +// The error-pattern check occurs *before* normalization, and the error patterns +// are wildly different between build environments. So this is a cop-out (and we +// rely on the checking of the normalized stderr output as our actual +// "verification" of the diagnostic). + +// error-pattern: error + +// On Mac OS X, we get an error like the below +// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/" + +// On Linux, we get an error like the below +// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/" + +// ignore-windows - this is a unix-specific test +// ignore-emscripten - the file-system issues do not replicate here +// ignore-wasm - the file-system issues do not replicate here +// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu + +#![crate_type = "lib"] +#![cfg_attr(not(feature = "std"), no_std)] +pub mod task { + pub mod __internal { + use crate::task::Waker; + } + pub use core::task::Waker; +} diff --git a/tests/ui/io-checks/inaccessbile-temp-dir.stderr b/tests/ui/io-checks/inaccessbile-temp-dir.stderr new file mode 100644 index 00000000000..2fc5f93ef79 --- /dev/null +++ b/tests/ui/io-checks/inaccessbile-temp-dir.stderr @@ -0,0 +1,4 @@ +error: failed to find or create the directory specified by `--temps-dir` + +error: aborting due to previous error + diff --git a/tests/ui/non-ice-error-on-worker-io-fail.rs b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs index 134e7d420e3..134e7d420e3 100644 --- a/tests/ui/non-ice-error-on-worker-io-fail.rs +++ b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs diff --git a/tests/ui/non-ice-error-on-worker-io-fail.stderr b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr index edadecf273a..edadecf273a 100644 --- a/tests/ui/non-ice-error-on-worker-io-fail.stderr +++ b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr diff --git a/tests/ui/issues/issue-40288.stderr b/tests/ui/issues/issue-40288.stderr index fb4ecab362d..db5d064379a 100644 --- a/tests/ui/issues/issue-40288.stderr +++ b/tests/ui/issues/issue-40288.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `*refr` because it is borrowed --> $DIR/issue-40288.rs:16:5 | LL | save_ref(&*refr, &mut out); - | ------ borrow of `*refr` occurs here + | ------ `*refr` is borrowed here ... LL | *refr = 3; - | ^^^^^^^^^ assignment to borrowed `*refr` occurs here + | ^^^^^^^^^ `*refr` is assigned to here but it was already borrowed ... LL | println!("{:?}", out[0]); | ------ borrow later used here diff --git a/tests/ui/issues/issue-45697-1.stderr b/tests/ui/issues/issue-45697-1.stderr index 30c69f19658..474313398e2 100644 --- a/tests/ui/issues/issue-45697-1.stderr +++ b/tests/ui/issues/issue-45697-1.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `*y.pointer` because it was mutably borrowed --> $DIR/issue-45697-1.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `y` occurs here + | ------ `y` is borrowed here LL | *y.pointer += 1; | ^^^^^^^^^^^^^^^ use of borrowed `y` ... @@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*y.pointer` because it is borrowed --> $DIR/issue-45697-1.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `*y.pointer` occurs here + | ------ `*y.pointer` is borrowed here LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here + | ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed ... LL | *z.pointer += 1; | --------------- borrow later used here diff --git a/tests/ui/issues/issue-45697.stderr b/tests/ui/issues/issue-45697.stderr index 26749d36f0b..7986fd5c9df 100644 --- a/tests/ui/issues/issue-45697.stderr +++ b/tests/ui/issues/issue-45697.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `*y.pointer` because it was mutably borrowed --> $DIR/issue-45697.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `y` occurs here + | ------ `y` is borrowed here LL | *y.pointer += 1; | ^^^^^^^^^^^^^^^ use of borrowed `y` ... @@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*y.pointer` because it is borrowed --> $DIR/issue-45697.rs:20:9 | LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `*y.pointer` occurs here + | ------ `*y.pointer` is borrowed here LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here + | ^^^^^^^^^^^^^^^ `*y.pointer` is assigned to here but it was already borrowed ... LL | *z.pointer += 1; | --------------- borrow later used here diff --git a/tests/ui/issues/issue-46471-1.stderr b/tests/ui/issues/issue-46471-1.stderr index b09f31729a5..2ae6e709d5a 100644 --- a/tests/ui/issues/issue-46471-1.stderr +++ b/tests/ui/issues/issue-46471-1.stderr @@ -1,11 +1,10 @@ error[E0597]: `z` does not live long enough --> $DIR/issue-46471-1.rs:4:9 | +LL | let mut z = 0; + | ----- binding `z` declared here LL | &mut z - | ^^^^^^ - | | - | borrowed value does not live long enough - | borrow later used here + | ^^^^^^ borrowed value does not live long enough LL | }; | - `z` dropped here while still borrowed diff --git a/tests/ui/issues/issue-52126-assign-op-invariance.stderr b/tests/ui/issues/issue-52126-assign-op-invariance.stderr index d4506757762..2d3b48832c5 100644 --- a/tests/ui/issues/issue-52126-assign-op-invariance.stderr +++ b/tests/ui/issues/issue-52126-assign-op-invariance.stderr @@ -1,6 +1,8 @@ error[E0597]: `line` does not live long enough --> $DIR/issue-52126-assign-op-invariance.rs:34:28 | +LL | for line in vec!["123456789".to_string(), "12345678".to_string()] { + | ---- binding `line` declared here LL | let v: Vec<&str> = line.split_whitespace().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr index 5dc8c2b607e..aee73380f15 100644 --- a/tests/ui/issues/issue-7364.stderr +++ b/tests/ui/issues/issue-7364.stderr @@ -5,6 +5,7 @@ LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0)); | ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `RefCell<isize>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Unique<RefCell<isize>>` to implement `Sync` = note: required because it appears within the type `Box<RefCell<isize>>` = note: shared static variables must have a type that implements `Sync` diff --git a/tests/ui/let-else/accidental-if.rs b/tests/ui/let-else/accidental-if.rs new file mode 100644 index 00000000000..3fba630435c --- /dev/null +++ b/tests/ui/let-else/accidental-if.rs @@ -0,0 +1,6 @@ +fn main() { + let x = Some(123); + if let Some(y) = x else { //~ ERROR this `if` expression is missing a block + return; + }; +} diff --git a/tests/ui/let-else/accidental-if.stderr b/tests/ui/let-else/accidental-if.stderr new file mode 100644 index 00000000000..5474a67aac4 --- /dev/null +++ b/tests/ui/let-else/accidental-if.stderr @@ -0,0 +1,19 @@ +error: this `if` expression is missing a block after the condition + --> $DIR/accidental-if.rs:3:5 + | +LL | if let Some(y) = x else { + | ^^ + | +help: add a block here + --> $DIR/accidental-if.rs:3:23 + | +LL | if let Some(y) = x else { + | ^ +help: remove the `if` if you meant to write a `let...else` statement + --> $DIR/accidental-if.rs:3:5 + | +LL | if let Some(y) = x else { + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed new file mode 100644 index 00000000000..aa3bce2945b --- /dev/null +++ b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.fixed @@ -0,0 +1,45 @@ +// run-rustfix + +trait Greeter0 { + fn greet(&self); +} + +trait Greeter1 { + fn greet(&self); +} + +type BoxedGreeter<'a> = (Box<dyn Greeter0 + 'a>, Box<dyn Greeter1 + 'a>); +//~^ HELP to declare that the trait object captures data from argument `self`, you can add a lifetime parameter `'a` in the type alias + +struct FixedGreeter<'a>(pub &'a str); + +impl Greeter0 for FixedGreeter<'_> { + fn greet(&self) { + println!("0 {}", self.0) + } +} + +impl Greeter1 for FixedGreeter<'_> { + fn greet(&self) { + println!("1 {}", self.0) + } +} + +struct Greetings(pub Vec<String>); + +impl Greetings { + pub fn get(&self, i: usize) -> BoxedGreeter { + (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i]))) + //~^ ERROR lifetime may not live long enough + } +} + +fn main() { + let mut g = Greetings {0 : vec!()}; + g.0.push("a".to_string()); + g.0.push("b".to_string()); + g.get(0).0.greet(); + g.get(0).1.greet(); + g.get(1).0.greet(); + g.get(1).1.greet(); +} diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs new file mode 100644 index 00000000000..20c88ec6981 --- /dev/null +++ b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs @@ -0,0 +1,45 @@ +// run-rustfix + +trait Greeter0 { + fn greet(&self); +} + +trait Greeter1 { + fn greet(&self); +} + +type BoxedGreeter = (Box<dyn Greeter0>, Box<dyn Greeter1>); +//~^ HELP to declare that the trait object captures data from argument `self`, you can add a lifetime parameter `'a` in the type alias + +struct FixedGreeter<'a>(pub &'a str); + +impl Greeter0 for FixedGreeter<'_> { + fn greet(&self) { + println!("0 {}", self.0) + } +} + +impl Greeter1 for FixedGreeter<'_> { + fn greet(&self) { + println!("1 {}", self.0) + } +} + +struct Greetings(pub Vec<String>); + +impl Greetings { + pub fn get(&self, i: usize) -> BoxedGreeter { + (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i]))) + //~^ ERROR lifetime may not live long enough + } +} + +fn main() { + let mut g = Greetings {0 : vec!()}; + g.0.push("a".to_string()); + g.0.push("b".to_string()); + g.get(0).0.greet(); + g.get(0).1.greet(); + g.get(1).0.greet(); + g.get(1).1.greet(); +} diff --git a/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr new file mode 100644 index 00000000000..808d8bb9058 --- /dev/null +++ b/tests/ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs:32:9 + | +LL | pub fn get(&self, i: usize) -> BoxedGreeter { + | - let's call the lifetime of this reference `'1` +LL | (Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i]))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | +help: to declare that the trait object captures data from argument `self`, you can add a lifetime parameter `'a` in the type alias + | +LL | type BoxedGreeter<'a> = (Box<dyn Greeter0 + 'a>, Box<dyn Greeter1 + 'a>); + | ++++ ++++ ++++ + +error: aborting due to previous error + diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index 99e1e7217b4..3602de8dd95 100644 --- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -1,6 +1,8 @@ error[E0597]: `foo` does not live long enough --> $DIR/issue-90600-expected-return-static-indirect.rs:7:32 | +LL | fn inner(mut foo: &[u8]) { + | ------- binding `foo` declared here LL | let refcell = RefCell::new(&mut foo); | ^^^^^^^^ borrowed value does not live long enough LL | diff --git a/tests/ui/lint/must_not_suspend/dedup.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/dedup.drop_tracking.stderr new file mode 100644 index 00000000000..262657da5fe --- /dev/null +++ b/tests/ui/lint/must_not_suspend/dedup.drop_tracking.stderr @@ -0,0 +1,21 @@ +error: `No` held across a suspend point, but should not be + --> $DIR/dedup.rs:19:9 + | +LL | let no = No {}; + | ^^ +LL | wheeee(&no).await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/dedup.rs:19:9 + | +LL | let no = No {}; + | ^^ +note: the lint level is defined here + --> $DIR/dedup.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/must_not_suspend/dedup.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/dedup.drop_tracking_mir.stderr new file mode 100644 index 00000000000..262657da5fe --- /dev/null +++ b/tests/ui/lint/must_not_suspend/dedup.drop_tracking_mir.stderr @@ -0,0 +1,21 @@ +error: `No` held across a suspend point, but should not be + --> $DIR/dedup.rs:19:9 + | +LL | let no = No {}; + | ^^ +LL | wheeee(&no).await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/dedup.rs:19:9 + | +LL | let no = No {}; + | ^^ +note: the lint level is defined here + --> $DIR/dedup.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/must_not_suspend/dedup.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/dedup.no_drop_tracking.stderr new file mode 100644 index 00000000000..7ed43d25719 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/dedup.no_drop_tracking.stderr @@ -0,0 +1,33 @@ +error: `No` held across a suspend point, but should not be + --> $DIR/dedup.rs:19:9 + | +LL | let no = No {}; + | ^^ +LL | wheeee(&no).await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/dedup.rs:19:9 + | +LL | let no = No {}; + | ^^ +note: the lint level is defined here + --> $DIR/dedup.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: `No` held across a suspend point, but should not be + --> $DIR/dedup.rs:20:13 + | +LL | wheeee(&no).await; + | ^^ ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/dedup.rs:20:13 + | +LL | wheeee(&no).await; + | ^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/must_not_suspend/dedup.rs b/tests/ui/lint/must_not_suspend/dedup.rs index 81a08579bb7..96bdb7715b1 100644 --- a/tests/ui/lint/must_not_suspend/dedup.rs +++ b/tests/ui/lint/must_not_suspend/dedup.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 #![feature(must_not_suspend)] #![deny(must_not_suspend)] @@ -13,7 +16,9 @@ async fn wheeee<T>(t: T) { } async fn yes() { - wheeee(&No {}).await; //~ ERROR `No` held across + let no = No {}; //~ ERROR `No` held across + wheeee(&no).await; //[no_drop_tracking]~ ERROR `No` held across + drop(no); } fn main() { diff --git a/tests/ui/lint/must_not_suspend/dedup.stderr b/tests/ui/lint/must_not_suspend/dedup.stderr index f8978ba57f1..18880f5a757 100644 --- a/tests/ui/lint/must_not_suspend/dedup.stderr +++ b/tests/ui/lint/must_not_suspend/dedup.stderr @@ -1,16 +1,16 @@ error: `No` held across a suspend point, but should not be - --> $DIR/dedup.rs:16:13 + --> $DIR/dedup.rs:19:13 | LL | wheeee(&No {}).await; | ^^^^^ ------ the value is held across this suspend point | help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/dedup.rs:16:13 + --> $DIR/dedup.rs:19:13 | LL | wheeee(&No {}).await; | ^^^^^ note: the lint level is defined here - --> $DIR/dedup.rs:3:9 + --> $DIR/dedup.rs:6:9 | LL | #![deny(must_not_suspend)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/must_not_suspend/ref.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/ref.drop_tracking.stderr index abf76711bf0..e3628ca5e49 100644 --- a/tests/ui/lint/must_not_suspend/ref.drop_tracking.stderr +++ b/tests/ui/lint/must_not_suspend/ref.drop_tracking.stderr @@ -1,5 +1,5 @@ error: reference to `Umm` held across a suspend point, but should not be - --> $DIR/ref.rs:21:13 + --> $DIR/ref.rs:22:13 | LL | let guard = &mut self.u; | ^^^^^ @@ -8,17 +8,17 @@ LL | other().await; | ------ the value is held across this suspend point | note: You gotta use Umm's, ya know? - --> $DIR/ref.rs:21:13 + --> $DIR/ref.rs:22:13 | LL | let guard = &mut self.u; | ^^^^^ help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/ref.rs:21:13 + --> $DIR/ref.rs:22:13 | LL | let guard = &mut self.u; | ^^^^^ note: the lint level is defined here - --> $DIR/ref.rs:6:9 + --> $DIR/ref.rs:7:9 | LL | #![deny(must_not_suspend)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/must_not_suspend/ref.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/ref.drop_tracking_mir.stderr new file mode 100644 index 00000000000..e3628ca5e49 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/ref.drop_tracking_mir.stderr @@ -0,0 +1,27 @@ +error: reference to `Umm` held across a suspend point, but should not be + --> $DIR/ref.rs:22:13 + | +LL | let guard = &mut self.u; + | ^^^^^ +LL | +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/ref.rs:22:13 + | +LL | let guard = &mut self.u; + | ^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/ref.rs:22:13 + | +LL | let guard = &mut self.u; + | ^^^^^ +note: the lint level is defined here + --> $DIR/ref.rs:7:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/must_not_suspend/ref.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/ref.no_drop_tracking.stderr index 41ac09ea72a..e9bfa08b5dd 100644 --- a/tests/ui/lint/must_not_suspend/ref.no_drop_tracking.stderr +++ b/tests/ui/lint/must_not_suspend/ref.no_drop_tracking.stderr @@ -1,5 +1,5 @@ error: `Umm` held across a suspend point, but should not be - --> $DIR/ref.rs:21:26 + --> $DIR/ref.rs:22:26 | LL | let guard = &mut self.u; | ^^^^^^ @@ -8,17 +8,17 @@ LL | other().await; | ------ the value is held across this suspend point | note: You gotta use Umm's, ya know? - --> $DIR/ref.rs:21:26 + --> $DIR/ref.rs:22:26 | LL | let guard = &mut self.u; | ^^^^^^ help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/ref.rs:21:26 + --> $DIR/ref.rs:22:26 | LL | let guard = &mut self.u; | ^^^^^^ note: the lint level is defined here - --> $DIR/ref.rs:6:9 + --> $DIR/ref.rs:7:9 | LL | #![deny(must_not_suspend)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/must_not_suspend/ref.rs b/tests/ui/lint/must_not_suspend/ref.rs index f6b23746fef..d05dcb83ac5 100644 --- a/tests/ui/lint/must_not_suspend/ref.rs +++ b/tests/ui/lint/must_not_suspend/ref.rs @@ -1,7 +1,8 @@ // edition:2018 -// revisions: no_drop_tracking drop_tracking -// [drop_tracking] compile-flags: -Zdrop-tracking=yes -// [no_drop_tracking] compile-flags: -Zdrop-tracking=no +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir + #![feature(must_not_suspend)] #![deny(must_not_suspend)] @@ -22,6 +23,7 @@ impl Bar { other().await; + let _g = &*guard; *guard = Umm { i: 2 } } } diff --git a/tests/ui/lint/must_not_suspend/trait.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/trait.drop_tracking.stderr new file mode 100644 index 00000000000..6e62a228a43 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/trait.drop_tracking.stderr @@ -0,0 +1,37 @@ +error: implementer of `Wow` held across a suspend point, but should not be + --> $DIR/trait.rs:24:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +... +LL | other().await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:24:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +note: the lint level is defined here + --> $DIR/trait.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: boxed `Wow` trait object held across a suspend point, but should not be + --> $DIR/trait.rs:25:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ +LL | +LL | other().await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:25:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/must_not_suspend/trait.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/trait.drop_tracking_mir.stderr new file mode 100644 index 00000000000..6e62a228a43 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/trait.drop_tracking_mir.stderr @@ -0,0 +1,37 @@ +error: implementer of `Wow` held across a suspend point, but should not be + --> $DIR/trait.rs:24:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +... +LL | other().await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:24:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +note: the lint level is defined here + --> $DIR/trait.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: boxed `Wow` trait object held across a suspend point, but should not be + --> $DIR/trait.rs:25:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ +LL | +LL | other().await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:25:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/must_not_suspend/trait.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/trait.no_drop_tracking.stderr new file mode 100644 index 00000000000..6e62a228a43 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/trait.no_drop_tracking.stderr @@ -0,0 +1,37 @@ +error: implementer of `Wow` held across a suspend point, but should not be + --> $DIR/trait.rs:24:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +... +LL | other().await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:24:9 + | +LL | let _guard1 = r#impl(); + | ^^^^^^^ +note: the lint level is defined here + --> $DIR/trait.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: boxed `Wow` trait object held across a suspend point, but should not be + --> $DIR/trait.rs:25:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ +LL | +LL | other().await; + | ------ the value is held across this suspend point + | +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/trait.rs:25:9 + | +LL | let _guard2 = r#dyn(); + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/must_not_suspend/trait.rs b/tests/ui/lint/must_not_suspend/trait.rs index 6c911cb4b0f..cc3ae298dbb 100644 --- a/tests/ui/lint/must_not_suspend/trait.rs +++ b/tests/ui/lint/must_not_suspend/trait.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 #![feature(must_not_suspend)] #![deny(must_not_suspend)] @@ -22,6 +25,9 @@ pub async fn uhoh() { let _guard2 = r#dyn(); //~ ERROR boxed `Wow` trait object held across other().await; + + drop(_guard1); + drop(_guard2); } fn main() { diff --git a/tests/ui/lint/must_not_suspend/trait.stderr b/tests/ui/lint/must_not_suspend/trait.stderr index d64d25aae52..6e62a228a43 100644 --- a/tests/ui/lint/must_not_suspend/trait.stderr +++ b/tests/ui/lint/must_not_suspend/trait.stderr @@ -1,5 +1,5 @@ error: implementer of `Wow` held across a suspend point, but should not be - --> $DIR/trait.rs:21:9 + --> $DIR/trait.rs:24:9 | LL | let _guard1 = r#impl(); | ^^^^^^^ @@ -8,18 +8,18 @@ LL | other().await; | ------ the value is held across this suspend point | help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/trait.rs:21:9 + --> $DIR/trait.rs:24:9 | LL | let _guard1 = r#impl(); | ^^^^^^^ note: the lint level is defined here - --> $DIR/trait.rs:3:9 + --> $DIR/trait.rs:6:9 | LL | #![deny(must_not_suspend)] | ^^^^^^^^^^^^^^^^ error: boxed `Wow` trait object held across a suspend point, but should not be - --> $DIR/trait.rs:22:9 + --> $DIR/trait.rs:25:9 | LL | let _guard2 = r#dyn(); | ^^^^^^^ @@ -28,7 +28,7 @@ LL | other().await; | ------ the value is held across this suspend point | help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/trait.rs:22:9 + --> $DIR/trait.rs:25:9 | LL | let _guard2 = r#dyn(); | ^^^^^^^ diff --git a/tests/ui/lint/must_not_suspend/unit.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/unit.drop_tracking.stderr new file mode 100644 index 00000000000..f89b3e341fd --- /dev/null +++ b/tests/ui/lint/must_not_suspend/unit.drop_tracking.stderr @@ -0,0 +1,26 @@ +error: `Umm` held across a suspend point, but should not be + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +note: the lint level is defined here + --> $DIR/unit.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/must_not_suspend/unit.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/unit.drop_tracking_mir.stderr new file mode 100644 index 00000000000..f89b3e341fd --- /dev/null +++ b/tests/ui/lint/must_not_suspend/unit.drop_tracking_mir.stderr @@ -0,0 +1,26 @@ +error: `Umm` held across a suspend point, but should not be + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +note: the lint level is defined here + --> $DIR/unit.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/must_not_suspend/unit.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/unit.no_drop_tracking.stderr new file mode 100644 index 00000000000..f89b3e341fd --- /dev/null +++ b/tests/ui/lint/must_not_suspend/unit.no_drop_tracking.stderr @@ -0,0 +1,26 @@ +error: `Umm` held across a suspend point, but should not be + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/unit.rs:22:9 + | +LL | let _guard = bar(); + | ^^^^^^ +note: the lint level is defined here + --> $DIR/unit.rs:6:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/must_not_suspend/unit.rs b/tests/ui/lint/must_not_suspend/unit.rs index d3a19f70432..fbc51b36681 100644 --- a/tests/ui/lint/must_not_suspend/unit.rs +++ b/tests/ui/lint/must_not_suspend/unit.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 #![feature(must_not_suspend)] #![deny(must_not_suspend)] @@ -7,7 +10,6 @@ struct Umm { i: i64 } - fn bar() -> Umm { Umm { i: 1 @@ -19,6 +21,7 @@ async fn other() {} pub async fn uhoh() { let _guard = bar(); //~ ERROR `Umm` held across other().await; + drop(_guard); } fn main() { diff --git a/tests/ui/lint/must_not_suspend/unit.stderr b/tests/ui/lint/must_not_suspend/unit.stderr index c967dbac56c..50ca292c2f6 100644 --- a/tests/ui/lint/must_not_suspend/unit.stderr +++ b/tests/ui/lint/must_not_suspend/unit.stderr @@ -1,5 +1,5 @@ error: `Umm` held across a suspend point, but should not be - --> $DIR/unit.rs:20:9 + --> $DIR/unit.rs:23:9 | LL | let _guard = bar(); | ^^^^^^ @@ -7,17 +7,17 @@ LL | other().await; | ------ the value is held across this suspend point | note: You gotta use Umm's, ya know? - --> $DIR/unit.rs:20:9 + --> $DIR/unit.rs:23:9 | LL | let _guard = bar(); | ^^^^^^ help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/unit.rs:20:9 + --> $DIR/unit.rs:23:9 | LL | let _guard = bar(); | ^^^^^^ note: the lint level is defined here - --> $DIR/unit.rs:3:9 + --> $DIR/unit.rs:6:9 | LL | #![deny(must_not_suspend)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/must_not_suspend/warn.drop_tracking.stderr b/tests/ui/lint/must_not_suspend/warn.drop_tracking.stderr new file mode 100644 index 00000000000..7a422891ab1 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/warn.drop_tracking.stderr @@ -0,0 +1,26 @@ +warning: `Umm` held across a suspend point, but should not be + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +note: the lint level is defined here + --> $DIR/warn.rs:7:9 + | +LL | #![warn(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/must_not_suspend/warn.drop_tracking_mir.stderr b/tests/ui/lint/must_not_suspend/warn.drop_tracking_mir.stderr new file mode 100644 index 00000000000..7a422891ab1 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/warn.drop_tracking_mir.stderr @@ -0,0 +1,26 @@ +warning: `Umm` held across a suspend point, but should not be + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +note: the lint level is defined here + --> $DIR/warn.rs:7:9 + | +LL | #![warn(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/must_not_suspend/warn.no_drop_tracking.stderr b/tests/ui/lint/must_not_suspend/warn.no_drop_tracking.stderr new file mode 100644 index 00000000000..7a422891ab1 --- /dev/null +++ b/tests/ui/lint/must_not_suspend/warn.no_drop_tracking.stderr @@ -0,0 +1,26 @@ +warning: `Umm` held across a suspend point, but should not be + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +LL | other().await; + | ------ the value is held across this suspend point + | +note: You gotta use Umm's, ya know? + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/warn.rs:24:9 + | +LL | let _guard = bar(); + | ^^^^^^ +note: the lint level is defined here + --> $DIR/warn.rs:7:9 + | +LL | #![warn(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/must_not_suspend/warn.rs b/tests/ui/lint/must_not_suspend/warn.rs index 7fdea66a235..5a4863169ea 100644 --- a/tests/ui/lint/must_not_suspend/warn.rs +++ b/tests/ui/lint/must_not_suspend/warn.rs @@ -1,3 +1,6 @@ +// revisions: no_drop_tracking drop_tracking drop_tracking_mir +// [drop_tracking] compile-flags: -Zdrop-tracking +// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir // edition:2018 // run-pass #![feature(must_not_suspend)] @@ -20,6 +23,7 @@ async fn other() {} pub async fn uhoh() { let _guard = bar(); //~ WARNING `Umm` held across other().await; + drop(_guard); } fn main() { diff --git a/tests/ui/lint/must_not_suspend/warn.stderr b/tests/ui/lint/must_not_suspend/warn.stderr index fe551c6521d..7a422891ab1 100644 --- a/tests/ui/lint/must_not_suspend/warn.stderr +++ b/tests/ui/lint/must_not_suspend/warn.stderr @@ -1,5 +1,5 @@ warning: `Umm` held across a suspend point, but should not be - --> $DIR/warn.rs:21:9 + --> $DIR/warn.rs:24:9 | LL | let _guard = bar(); | ^^^^^^ @@ -7,17 +7,17 @@ LL | other().await; | ------ the value is held across this suspend point | note: You gotta use Umm's, ya know? - --> $DIR/warn.rs:21:9 + --> $DIR/warn.rs:24:9 | LL | let _guard = bar(); | ^^^^^^ help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point - --> $DIR/warn.rs:21:9 + --> $DIR/warn.rs:24:9 | LL | let _guard = bar(); | ^^^^^^ note: the lint level is defined here - --> $DIR/warn.rs:4:9 + --> $DIR/warn.rs:7:9 | LL | #![warn(must_not_suspend)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/format-args-temporaries-in-write.stderr b/tests/ui/macros/format-args-temporaries-in-write.stderr index 287cd7d6704..520b2ce5052 100644 --- a/tests/ui/macros/format-args-temporaries-in-write.stderr +++ b/tests/ui/macros/format-args-temporaries-in-write.stderr @@ -1,6 +1,8 @@ error[E0597]: `mutex` does not live long enough --> $DIR/format-args-temporaries-in-write.rs:41:27 | +LL | let mutex = Mutex; + | ----- binding `mutex` declared here LL | write!(Out, "{}", mutex.lock()) /* no semicolon */ | ^^^^^^^^^^^^ | | @@ -16,6 +18,8 @@ LL | }; error[E0597]: `mutex` does not live long enough --> $DIR/format-args-temporaries-in-write.rs:47:29 | +LL | let mutex = Mutex; + | ----- binding `mutex` declared here LL | writeln!(Out, "{}", mutex.lock()) /* no semicolon */ | ^^^^^^^^^^^^ | | diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index 90f858f80e6..ad97f7a4a75 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -25,8 +25,8 @@ fn arbitrary_consuming_method_for_demonstration_purposes() { { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem as usize\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -41,8 +41,8 @@ fn addr_of() { if ::core::intrinsics::unlikely(!&*__local_bind0) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: &elem\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -57,8 +57,8 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem == 1\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -70,8 +70,8 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem >= 1\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -83,8 +83,8 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem > 0\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -96,8 +96,8 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem < 3\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -109,8 +109,8 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem <= 3\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -122,8 +122,8 @@ fn binary() { if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: elem != 3\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; @@ -138,8 +138,8 @@ fn unary() { if ::core::intrinsics::unlikely(!**__local_bind0) { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + ::std::rt::panic_fmt(format_args!("Assertion failed: *elem\nWith captures:\n elem = {0:?}\n", + __capture0)) } } }; diff --git a/tests/ui/match/issue-74050-end-span.stderr b/tests/ui/match/issue-74050-end-span.stderr index 59c091e44eb..0b3425f2b1a 100644 --- a/tests/ui/match/issue-74050-end-span.stderr +++ b/tests/ui/match/issue-74050-end-span.stderr @@ -4,6 +4,7 @@ error[E0597]: `arg` does not live long enough LL | let _arg = match args.next() { | ---- borrow later stored here LL | Some(arg) => { + | --- binding `arg` declared here LL | match arg.to_str() { | ^^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs new file mode 100644 index 00000000000..5e2f10cefe9 --- /dev/null +++ b/tests/ui/mir/mir_codegen_ssa.rs @@ -0,0 +1,19 @@ +// build-pass +// compile-flags: --crate-type=lib +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn f(a: u32) -> u32 { + mir!( + let x: u32; + { + // Previously code generation failed with ICE "use of .. before def ..." because the + // definition of x was incorrectly identified as dominating the use of x located in the + // same statement: + x = x + a; + RET = x; + Return() + } + ) +} diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr index 7f69e5dcfb7..91d237b1d1a 100644 --- a/tests/ui/moves/move-fn-self-receiver.stderr +++ b/tests/ui/moves/move-fn-self-receiver.stderr @@ -75,6 +75,8 @@ LL | fn use_pin_box_self(self: Pin<Box<Self>>) {} error[E0505]: cannot move out of `mut_foo` because it is borrowed --> $DIR/move-fn-self-receiver.rs:50:5 | +LL | let mut mut_foo = Foo; + | ----------- binding `mut_foo` declared here LL | let ret = mut_foo.use_mut_self(); | ---------------------- borrow of `mut_foo` occurs here LL | mut_foo; diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed new file mode 100644 index 00000000000..0b9a3bae961 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed @@ -0,0 +1,11 @@ +// run-rustfix +use std::pin::Pin; + +fn foo(_: &mut ()) {} + +fn main() { + let mut uwu = (); + let mut r = Pin::new(&mut uwu); + foo(r.as_mut().get_mut()); + foo(r.get_mut()); //~ ERROR use of moved value +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs new file mode 100644 index 00000000000..0e952b06ee1 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs @@ -0,0 +1,11 @@ +// run-rustfix +use std::pin::Pin; + +fn foo(_: &mut ()) {} + +fn main() { + let mut uwu = (); + let mut r = Pin::new(&mut uwu); + foo(r.get_mut()); + foo(r.get_mut()); //~ ERROR use of moved value +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr new file mode 100644 index 00000000000..7e513b73c21 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `r` + --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9 + | +LL | let mut r = Pin::new(&mut uwu); + | ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait +LL | foo(r.get_mut()); + | --------- `r` moved due to this method call +LL | foo(r.get_mut()); + | ^ value used here after move + | +note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider reborrowing the `Pin` instead of moving it + | +LL | foo(r.as_mut().get_mut()); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/mut/mut-pattern-internal-mutability.stderr b/tests/ui/mut/mut-pattern-internal-mutability.stderr index 6583546aa5c..5f2074edb12 100644 --- a/tests/ui/mut/mut-pattern-internal-mutability.stderr +++ b/tests/ui/mut/mut-pattern-internal-mutability.stderr @@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*foo` because it is borrowed --> $DIR/mut-pattern-internal-mutability.rs:13:5 | LL | let &mut ref x = foo; - | ----- borrow of `*foo` occurs here + | ----- `*foo` is borrowed here LL | *foo += 1; - | ^^^^^^^^^ assignment to borrowed `*foo` occurs here + | ^^^^^^^^^ `*foo` is assigned to here but it was already borrowed LL | drop(x); | - borrow later used here diff --git a/tests/ui/nll/borrowed-local-error.stderr b/tests/ui/nll/borrowed-local-error.stderr index d629caa4353..1cca4077d82 100644 --- a/tests/ui/nll/borrowed-local-error.stderr +++ b/tests/ui/nll/borrowed-local-error.stderr @@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough LL | let x = gimme({ | ----- borrow later used by call LL | let v = (22,); + | - binding `v` declared here LL | &v | ^^ borrowed value does not live long enough LL | diff --git a/tests/ui/nll/borrowed-match-issue-45045.stderr b/tests/ui/nll/borrowed-match-issue-45045.stderr index 9d4682667dd..33e3eb79796 100644 --- a/tests/ui/nll/borrowed-match-issue-45045.stderr +++ b/tests/ui/nll/borrowed-match-issue-45045.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowed-match-issue-45045.rs:12:11 | LL | let f = &mut e; - | ------ borrow of `e` occurs here + | ------ `e` is borrowed here LL | let g = f; LL | match e { | ^ use of borrowed `e` diff --git a/tests/ui/nll/capture-ref-in-struct.stderr b/tests/ui/nll/capture-ref-in-struct.stderr index cdfe7f6db82..84b7ecf2f7d 100644 --- a/tests/ui/nll/capture-ref-in-struct.stderr +++ b/tests/ui/nll/capture-ref-in-struct.stderr @@ -1,6 +1,9 @@ error[E0597]: `y` does not live long enough --> $DIR/capture-ref-in-struct.rs:18:16 | +LL | let y = 22; + | - binding `y` declared here +... LL | y: &y, | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/closure-access-spans.stderr b/tests/ui/nll/closure-access-spans.stderr index 0a09353b8ec..035dd5a5610 100644 --- a/tests/ui/nll/closure-access-spans.stderr +++ b/tests/ui/nll/closure-access-spans.stderr @@ -38,7 +38,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/closure-access-spans.rs:23:13 | LL | let r = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | move || x; | ^ use of borrowed `x` LL | r.use_ref(); @@ -47,6 +47,8 @@ LL | r.use_ref(); error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-access-spans.rs:29:5 | +LL | fn closure_move_capture_conflict(mut x: String) { + | ----- binding `x` declared here LL | let r = &x; | -- borrow of `x` occurs here LL | || x; diff --git a/tests/ui/nll/closure-borrow-spans.stderr b/tests/ui/nll/closure-borrow-spans.stderr index bada4e1b84b..cf0df5834cc 100644 --- a/tests/ui/nll/closure-borrow-spans.stderr +++ b/tests/ui/nll/closure-borrow-spans.stderr @@ -40,9 +40,9 @@ error[E0506]: cannot assign to `x` because it is borrowed LL | let f = || x; | -- - borrow occurs due to use in closure | | - | borrow of `x` occurs here + | `x` is borrowed here LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | f.use_ref(); | ----------- borrow later used here @@ -52,7 +52,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed LL | let f = || x = 0; | -- - borrow occurs due to use of `x` in closure | | - | borrow of `x` occurs here + | `x` is borrowed here LL | let y = x; | ^ use of borrowed `x` LL | f.use_ref(); @@ -100,9 +100,9 @@ error[E0506]: cannot assign to `x` because it is borrowed LL | let f = || x = 0; | -- - borrow occurs due to use in closure | | - | borrow of `x` occurs here + | `x` is borrowed here LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | f.use_ref(); | ----------- borrow later used here @@ -160,9 +160,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed LL | let f = || *x = 0; | -- -- borrow occurs due to use in closure | | - | borrow of `*x` occurs here + | `*x` is borrowed here LL | *x = 1; - | ^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^ `*x` is assigned to here but it was already borrowed LL | f.use_ref(); | ----------- borrow later used here diff --git a/tests/ui/nll/closure-requirements/escape-argument.stderr b/tests/ui/nll/closure-requirements/escape-argument.stderr index f67c312b946..5a8462d4dc5 100644 --- a/tests/ui/nll/closure-requirements/escape-argument.stderr +++ b/tests/ui/nll/closure-requirements/escape-argument.stderr @@ -21,6 +21,9 @@ LL | fn test() { error[E0597]: `y` does not live long enough --> $DIR/escape-argument.rs:27:25 | +LL | let y = 22; + | - binding `y` declared here +LL | let mut closure = expect_sig(|p, y| *p = y); LL | closure(&mut p, &y); | ^^ borrowed value does not live long enough LL | diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 7991abeb7a8..721cd45ded9 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -53,6 +53,8 @@ LL | fn case2() { error[E0597]: `a` does not live long enough --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26 | +LL | let a = 0; + | - binding `a` declared here LL | let cell = Cell::new(&a); | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/closure-use-spans.stderr b/tests/ui/nll/closure-use-spans.stderr index ad928f1bbc9..0e27e5f5f7c 100644 --- a/tests/ui/nll/closure-use-spans.stderr +++ b/tests/ui/nll/closure-use-spans.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:5:5 | LL | let y = &x; - | -- borrow of `x` occurs here + | -- `x` is borrowed here LL | x = 0; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | || *y; | -- borrow later captured here by closure @@ -12,9 +12,9 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:11:5 | LL | let y = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | x = 0; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | || *y = 1; | -- borrow later captured here by closure @@ -22,9 +22,9 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:17:5 | LL | let y = &x; - | -- borrow of `x` occurs here + | -- `x` is borrowed here LL | x = 0; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | move || *y; | -- borrow later captured here by closure diff --git a/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr index 65be3b37e0e..862c925b468 100644 --- a/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr +++ b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr @@ -1,6 +1,8 @@ error[E0597]: `s` does not live long enough --> $DIR/do-not-ignore-lifetime-bounds-in-copy-proj.rs:9:18 | +LL | let s = 2; + | - binding `s` declared here LL | let a = (Foo(&s),); | ^^ borrowed value does not live long enough LL | drop(a.0); diff --git a/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr index b811ba4fd0c..ebaf6d1244d 100644 --- a/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr +++ b/tests/ui/nll/do-not-ignore-lifetime-bounds-in-copy.stderr @@ -1,6 +1,8 @@ error[E0597]: `s` does not live long enough --> $DIR/do-not-ignore-lifetime-bounds-in-copy.rs:8:17 | +LL | let s = 2; + | - binding `s` declared here LL | let a = Foo(&s); | ^^ borrowed value does not live long enough LL | drop(a); diff --git a/tests/ui/nll/dont-print-desugared.stderr b/tests/ui/nll/dont-print-desugared.stderr index fad6121cbca..289b246e663 100644 --- a/tests/ui/nll/dont-print-desugared.stderr +++ b/tests/ui/nll/dont-print-desugared.stderr @@ -10,6 +10,7 @@ error[E0597]: `y` does not live long enough LL | for ref mut d in v { | - a temporary with access to the borrow is created here ... LL | let y = (); + | - binding `y` declared here LL | *d = D(&y); | ^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/nll/drop-no-may-dangle.stderr b/tests/ui/nll/drop-no-may-dangle.stderr index cb280880950..0ddb7adbb38 100644 --- a/tests/ui/nll/drop-no-may-dangle.stderr +++ b/tests/ui/nll/drop-no-may-dangle.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `v[_]` because it is borrowed --> $DIR/drop-no-may-dangle.rs:18:9 | LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] }; - | ----- borrow of `v[_]` occurs here + | ----- `v[_]` is borrowed here ... LL | v[0] += 1; - | ^^^^^^^^^ assignment to borrowed `v[_]` occurs here + | ^^^^^^^^^ `v[_]` is assigned to here but it was already borrowed ... LL | } | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle` @@ -14,10 +14,10 @@ error[E0506]: cannot assign to `v[_]` because it is borrowed --> $DIR/drop-no-may-dangle.rs:21:5 | LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] }; - | ----- borrow of `v[_]` occurs here + | ----- `v[_]` is borrowed here ... LL | v[0] += 1; - | ^^^^^^^^^ assignment to borrowed `v[_]` occurs here + | ^^^^^^^^^ `v[_]` is assigned to here but it was already borrowed LL | } | - borrow might be used here, when `p` is dropped and runs the `Drop` code for type `WrapMayNotDangle` diff --git a/tests/ui/nll/guarantor-issue-46974.stderr b/tests/ui/nll/guarantor-issue-46974.stderr index 8854dd8d68c..7edc3dcc5cd 100644 --- a/tests/ui/nll/guarantor-issue-46974.stderr +++ b/tests/ui/nll/guarantor-issue-46974.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `*s` because it is borrowed --> $DIR/guarantor-issue-46974.rs:7:5 | LL | let t = &mut *s; // this borrow should last for the entire function - | ------- borrow of `*s` occurs here + | ------- `*s` is borrowed here LL | let x = &t.0; LL | *s = (2,); - | ^^^^^^^^^ assignment to borrowed `*s` occurs here + | ^^^^^^^^^ `*s` is assigned to here but it was already borrowed LL | *x | -- borrow later used here diff --git a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr index 45119018d4e..4a512560c87 100644 --- a/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr +++ b/tests/ui/nll/issue-27282-move-ref-mut-into-guard.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | - | move out of `foo` occurs here + | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -14,7 +14,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {}, | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | - | move out of `foo` occurs here + | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/tests/ui/nll/issue-27282-mutation-in-guard.stderr b/tests/ui/nll/issue-27282-mutation-in-guard.stderr index 1ba696593af..0b5d723172c 100644 --- a/tests/ui/nll/issue-27282-mutation-in-guard.stderr +++ b/tests/ui/nll/issue-27282-mutation-in-guard.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | - | move out of `foo` occurs here + | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -14,7 +14,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | - | move out of `foo` occurs here + | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/tests/ui/nll/issue-27868.stderr b/tests/ui/nll/issue-27868.stderr index e0b3b5494d0..204eda3d267 100644 --- a/tests/ui/nll/issue-27868.stderr +++ b/tests/ui/nll/issue-27868.stderr @@ -4,10 +4,10 @@ error[E0506]: cannot assign to `vecvec` because it is borrowed LL | vecvec[0] += { | ------ | | - | _____borrow of `vecvec` occurs here + | _____`vecvec` is borrowed here | | LL | | vecvec = vec![]; - | | ^^^^^^ assignment to borrowed `vecvec` occurs here + | | ^^^^^^ `vecvec` is assigned to here but it was already borrowed LL | | LL | | 0 LL | | }; diff --git a/tests/ui/nll/issue-46036.stderr b/tests/ui/nll/issue-46036.stderr index e6e95ee6136..f337e234550 100644 --- a/tests/ui/nll/issue-46036.stderr +++ b/tests/ui/nll/issue-46036.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/issue-46036.rs:8:24 | +LL | let a = 3; + | - binding `a` declared here LL | let foo = Foo { x: &a }; | ^^ | | diff --git a/tests/ui/nll/issue-48803.stderr b/tests/ui/nll/issue-48803.stderr index 2f94039c0c3..e24606e0b53 100644 --- a/tests/ui/nll/issue-48803.stderr +++ b/tests/ui/nll/issue-48803.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/issue-48803.rs:10:5 | LL | let y = &x; - | -- borrow of `x` occurs here + | -- `x` is borrowed here ... LL | x = "modified"; - | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here + | ^^^^^^^^^^^^^^ `x` is assigned to here but it was already borrowed LL | LL | println!("{}", w); // prints "modified" | - borrow later used here diff --git a/tests/ui/nll/issue-52534-2.stderr b/tests/ui/nll/issue-52534-2.stderr index ac385e056b9..35d39bb6e90 100644 --- a/tests/ui/nll/issue-52534-2.stderr +++ b/tests/ui/nll/issue-52534-2.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/issue-52534-2.rs:6:13 | +LL | let x = 32; + | - binding `x` declared here LL | y = &x | ^^ borrowed value does not live long enough LL | diff --git a/tests/ui/nll/issue-52663-trait-object.stderr b/tests/ui/nll/issue-52663-trait-object.stderr index 5cedea6e665..338f6484132 100644 --- a/tests/ui/nll/issue-52663-trait-object.stderr +++ b/tests/ui/nll/issue-52663-trait-object.stderr @@ -1,6 +1,8 @@ error[E0597]: `tmp0` does not live long enough --> $DIR/issue-52663-trait-object.rs:12:20 | +LL | let tmp0 = 3; + | ---- binding `tmp0` declared here LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | Box::new(tmp1) as Box<dyn Foo + '_> diff --git a/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr b/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr index d8f43cbc92a..4a32c777a86 100644 --- a/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr +++ b/tests/ui/nll/issue-54382-use-span-of-tail-of-block.stderr @@ -1,6 +1,9 @@ error[E0597]: `_thing1` does not live long enough --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29 | +LL | let mut _thing1 = D(Box::new("thing1")); + | ----------- binding `_thing1` declared here +... LL | D("other").next(&_thing1) | ----------------^^^^^^^^- | | | diff --git a/tests/ui/nll/issue-54556-niconii.stderr b/tests/ui/nll/issue-54556-niconii.stderr index a8e1edc5497..d41d462f2bc 100644 --- a/tests/ui/nll/issue-54556-niconii.stderr +++ b/tests/ui/nll/issue-54556-niconii.stderr @@ -1,6 +1,9 @@ error[E0597]: `counter` does not live long enough --> $DIR/issue-54556-niconii.rs:22:20 | +LL | let counter = Mutex; + | ------- binding `counter` declared here +LL | LL | if let Ok(_) = counter.lock() { } | ^^^^^^^^^^^^^^ | | diff --git a/tests/ui/nll/issue-54556-stephaneyfx.stderr b/tests/ui/nll/issue-54556-stephaneyfx.stderr index 036a7a0abfd..f9e82cb003f 100644 --- a/tests/ui/nll/issue-54556-stephaneyfx.stderr +++ b/tests/ui/nll/issue-54556-stephaneyfx.stderr @@ -1,6 +1,8 @@ error[E0597]: `stmt` does not live long enough --> $DIR/issue-54556-stephaneyfx.rs:27:21 | +LL | let stmt = Statement; + | ---- binding `stmt` declared here LL | let rows = Rows(&stmt); | ^^^^^ borrowed value does not live long enough LL | rows.map(|row| row).next() diff --git a/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr b/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr index 92f5ffdf388..4eae9fdcde0 100644 --- a/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr +++ b/tests/ui/nll/issue-54556-temps-in-tail-diagnostic.stderr @@ -1,6 +1,9 @@ error[E0597]: `_thing1` does not live long enough --> $DIR/issue-54556-temps-in-tail-diagnostic.rs:5:11 | +LL | let mut _thing1 = D(Box::new("thing1")); + | ----------- binding `_thing1` declared here +LL | // D("other").next(&_thing1).end() LL | D(&_thing1).end() | --^^^^^^^^- | | | diff --git a/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr b/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr index 25226e29673..a2a7a848654 100644 --- a/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr +++ b/tests/ui/nll/issue-54556-used-vs-unused-tails.stderr @@ -2,11 +2,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:10:55 | LL | { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | @@ -17,11 +18,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:13:55 | LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | @@ -32,11 +34,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:16:55 | LL | { { let mut _t1 = D(Box::new("t1")); D(&_t1).end() }; } // suggest `;` - | --^^^^- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | @@ -47,11 +50,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:19:55 | LL | let _ = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | @@ -62,11 +66,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:22:55 | LL | let _u = { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } ; // suggest `;` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | @@ -77,11 +82,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:25:55 | LL | let _x = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped @@ -94,11 +100,12 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:30:55 | LL | _y = { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } ; // `let x = ...; x` - | --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | | | - | | | `_t1` dropped here while still borrowed - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped @@ -111,12 +118,13 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:37:55 | LL | fn f_local_ref() { let mut _t1 = D(Box::new("t1")); D(&_t1).unit() } // suggest `;` - | --^^^^- - - | | | | - | | | `_t1` dropped here while still borrowed - | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | @@ -127,12 +135,13 @@ error[E0597]: `_t1` does not live long enough --> $DIR/issue-54556-used-vs-unused-tails.rs:40:55 | LL | fn f() -> String { let mut _t1 = D(Box::new("t1")); D(&_t1).end() } // `let x = ...; x` - | --^^^^- - - | | | | - | | | `_t1` dropped here while still borrowed - | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` - | | borrowed value does not live long enough - | a temporary with access to the borrow is created here ... + | ------- --^^^^- - + | | | | | + | | | | `_t1` dropped here while still borrowed + | | | | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | | | borrowed value does not live long enough + | | a temporary with access to the borrow is created here ... + | binding `_t1` declared here | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped diff --git a/tests/ui/nll/issue-54556-wrap-it-up.stderr b/tests/ui/nll/issue-54556-wrap-it-up.stderr index 9f27fac15a7..adc419ae515 100644 --- a/tests/ui/nll/issue-54556-wrap-it-up.stderr +++ b/tests/ui/nll/issue-54556-wrap-it-up.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/issue-54556-wrap-it-up.rs:27:5 | LL | let wrap = Wrap { p: &mut x }; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here ... LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | } | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` diff --git a/tests/ui/nll/issue-55511.stderr b/tests/ui/nll/issue-55511.stderr index bf3e58e8cdb..ecb9ef0aef9 100644 --- a/tests/ui/nll/issue-55511.stderr +++ b/tests/ui/nll/issue-55511.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/issue-55511.rs:13:28 | +LL | let a = 22; + | - binding `a` declared here LL | let b = Some(Cell::new(&a)); | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/issue-57989.stderr b/tests/ui/nll/issue-57989.stderr index 31f40d8252e..d5effd6f346 100644 --- a/tests/ui/nll/issue-57989.stderr +++ b/tests/ui/nll/issue-57989.stderr @@ -13,9 +13,9 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-57989.rs:5:5 | LL | let g = &x; - | -- borrow of `*x` occurs here + | -- `*x` is borrowed here LL | *x = 0; - | ^^^^^^ assignment to borrowed `*x` occurs here + | ^^^^^^ `*x` is assigned to here but it was already borrowed LL | LL | g; | - borrow later used here diff --git a/tests/ui/nll/issue-68550.stderr b/tests/ui/nll/issue-68550.stderr index e234ebb04e1..851e3628748 100644 --- a/tests/ui/nll/issue-68550.stderr +++ b/tests/ui/nll/issue-68550.stderr @@ -2,7 +2,9 @@ error[E0597]: `x` does not live long enough --> $DIR/issue-68550.rs:12:20 | LL | fn run<'a, A>(x: A) - | -- lifetime `'a` defined here + | -- - binding `x` declared here + | | + | lifetime `'a` defined here ... LL | let _: &'a A = &x; | ----- ^^ borrowed value does not live long enough diff --git a/tests/ui/nll/issue-69114-static-mut-ty.stderr b/tests/ui/nll/issue-69114-static-mut-ty.stderr index 5e55cb502ca..1b41230d7ba 100644 --- a/tests/ui/nll/issue-69114-static-mut-ty.stderr +++ b/tests/ui/nll/issue-69114-static-mut-ty.stderr @@ -1,6 +1,9 @@ error[E0597]: `n` does not live long enough --> $DIR/issue-69114-static-mut-ty.rs:19:15 | +LL | let n = 42; + | - binding `n` declared here +LL | unsafe { LL | BAR = &n; | ------^^ | | | @@ -13,6 +16,9 @@ LL | } error[E0597]: `n` does not live long enough --> $DIR/issue-69114-static-mut-ty.rs:27:22 | +LL | let n = 42; + | - binding `n` declared here +LL | unsafe { LL | BAR_ELIDED = &n; | -------------^^ | | | diff --git a/tests/ui/nll/issue-69114-static-ty.stderr b/tests/ui/nll/issue-69114-static-ty.stderr index 0815e74b553..9215e850f7d 100644 --- a/tests/ui/nll/issue-69114-static-ty.stderr +++ b/tests/ui/nll/issue-69114-static-ty.stderr @@ -1,6 +1,8 @@ error[E0597]: `n` does not live long enough --> $DIR/issue-69114-static-ty.rs:7:9 | +LL | let n = 42; + | - binding `n` declared here LL | FOO(&n); | ----^^- | | | diff --git a/tests/ui/nll/loan_ends_mid_block_pair.stderr b/tests/ui/nll/loan_ends_mid_block_pair.stderr index eb8442b31d7..58e378ab021 100644 --- a/tests/ui/nll/loan_ends_mid_block_pair.stderr +++ b/tests/ui/nll/loan_ends_mid_block_pair.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `data.0` because it is borrowed --> $DIR/loan_ends_mid_block_pair.rs:12:5 | LL | let c = &mut data.0; - | ----------- borrow of `data.0` occurs here + | ----------- `data.0` is borrowed here LL | capitalize(c); LL | data.0 = 'e'; - | ^^^^^^^^^^^^ assignment to borrowed `data.0` occurs here + | ^^^^^^^^^^^^ `data.0` is assigned to here but it was already borrowed ... LL | capitalize(c); | - borrow later used here diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr index f5c10f3ddea..a6b3328b5a2 100644 --- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr @@ -1,6 +1,8 @@ error[E0597]: `local` does not live long enough --> $DIR/local-outlives-static-via-hrtb.rs:24:28 | +LL | let local = 0; + | ----- binding `local` declared here LL | assert_static_via_hrtb(&local); | -----------------------^^^^^^- | | | @@ -19,6 +21,9 @@ LL | fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {} error[E0597]: `local` does not live long enough --> $DIR/local-outlives-static-via-hrtb.rs:25:45 | +LL | let local = 0; + | ----- binding `local` declared here +LL | assert_static_via_hrtb(&local); LL | assert_static_via_hrtb_with_assoc_type(&&local); | ----------------------------------------^^^^^^- | | | diff --git a/tests/ui/nll/match-cfg-fake-edges2.stderr b/tests/ui/nll/match-cfg-fake-edges2.stderr index c6d15a936d8..36f2cd0b85d 100644 --- a/tests/ui/nll/match-cfg-fake-edges2.stderr +++ b/tests/ui/nll/match-cfg-fake-edges2.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `y.1` because it was mutably borrowed --> $DIR/match-cfg-fake-edges2.rs:8:5 | LL | let r = &mut y.1; - | -------- borrow of `y.1` occurs here + | -------- `y.1` is borrowed here ... LL | match y { | ^^^^^^^ use of borrowed `y.1` diff --git a/tests/ui/nll/match-guards-always-borrow.stderr b/tests/ui/nll/match-guards-always-borrow.stderr index fa01d3a6fd1..afd853c403e 100644 --- a/tests/ui/nll/match-guards-always-borrow.stderr +++ b/tests/ui/nll/match-guards-always-borrow.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | - | move out of `foo` occurs here + | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -14,7 +14,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | - | move out of `foo` occurs here + | `foo` is moved here | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/tests/ui/nll/match-guards-partially-borrow.stderr b/tests/ui/nll/match-guards-partially-borrow.stderr index 60b8dee71a8..7bdcbcb9c6e 100644 --- a/tests/ui/nll/match-guards-partially-borrow.stderr +++ b/tests/ui/nll/match-guards-partially-borrow.stderr @@ -74,9 +74,9 @@ error[E0506]: cannot assign to `t` because it is borrowed --> $DIR/match-guards-partially-borrow.rs:225:13 | LL | s if { - | - borrow of `t` occurs here + | - `t` is borrowed here LL | t = !t; - | ^^^^^^ assignment to borrowed `t` occurs here + | ^^^^^^ `t` is assigned to here but it was already borrowed LL | false LL | } => (), // What value should `s` have in the arm? | - borrow later used here @@ -85,9 +85,9 @@ error[E0506]: cannot assign to `t` because it is borrowed --> $DIR/match-guards-partially-borrow.rs:235:13 | LL | s if let Some(()) = { - | - borrow of `t` occurs here + | - `t` is borrowed here LL | t = !t; - | ^^^^^^ assignment to borrowed `t` occurs here + | ^^^^^^ `t` is assigned to here but it was already borrowed LL | None LL | } => (), // What value should `s` have in the arm? | - borrow later used here diff --git a/tests/ui/nll/match-on-borrowed.stderr b/tests/ui/nll/match-on-borrowed.stderr index 32666529f3f..9273484565a 100644 --- a/tests/ui/nll/match-on-borrowed.stderr +++ b/tests/ui/nll/match-on-borrowed.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/match-on-borrowed.rs:47:11 | LL | E::V(ref mut x, _) => x, - | --------- borrow of `e.0` occurs here + | --------- `e.0` is borrowed here ... LL | match e { // Don't know that E uses a tag for its discriminant | ^ use of borrowed `e.0` @@ -14,7 +14,7 @@ error[E0503]: cannot use `*f` because it was mutably borrowed --> $DIR/match-on-borrowed.rs:61:11 | LL | E::V(ref mut x, _) => x, - | --------- borrow of `f.0` occurs here + | --------- `f.0` is borrowed here ... LL | match f { // Don't know that E uses a tag for its discriminant | ^ use of borrowed `f.0` @@ -26,7 +26,7 @@ error[E0503]: cannot use `t` because it was mutably borrowed --> $DIR/match-on-borrowed.rs:81:5 | LL | let x = &mut t; - | ------ borrow of `t` occurs here + | ------ `t` is borrowed here LL | match t { | ^^^^^^^ use of borrowed `t` ... diff --git a/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr b/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr index 80e29780746..55646b9dca9 100644 --- a/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr +++ b/tests/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:17:5 | LL | let wrap = Wrap { p: &mut x }; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here ... LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | // FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones LL | } | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` diff --git a/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr b/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr index 14074472eaf..c89f94a7894 100644 --- a/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr +++ b/tests/ui/nll/maybe-initialized-drop-with-fragment.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/maybe-initialized-drop-with-fragment.rs:19:5 | LL | let wrap = Wrap { p: &mut x }; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here ... LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | } | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` diff --git a/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr b/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr index 91c0afc1dba..90db13bc578 100644 --- a/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr +++ b/tests/ui/nll/maybe-initialized-drop-with-uninitialized-fragments.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/maybe-initialized-drop-with-uninitialized-fragments.rs:20:5 | LL | let wrap = Wrap { p: &mut x }; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here ... LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | // FIXME ^ This currently errors and it should not. LL | } | - borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>` diff --git a/tests/ui/nll/maybe-initialized-drop.stderr b/tests/ui/nll/maybe-initialized-drop.stderr index 9825ba4611b..15a53a09af8 100644 --- a/tests/ui/nll/maybe-initialized-drop.stderr +++ b/tests/ui/nll/maybe-initialized-drop.stderr @@ -2,9 +2,9 @@ error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/maybe-initialized-drop.rs:14:5 | LL | let wrap = Wrap { p: &mut x }; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | x = 1; - | ^^^^^ assignment to borrowed `x` occurs here + | ^^^^^ `x` is assigned to here but it was already borrowed LL | } | - borrow might be used here, when `wrap` is dropped and runs the `Drop` code for type `Wrap` diff --git a/tests/ui/nll/polonius/polonius-smoke-test.stderr b/tests/ui/nll/polonius/polonius-smoke-test.stderr index fa1a6a9c957..534813b2d9f 100644 --- a/tests/ui/nll/polonius/polonius-smoke-test.stderr +++ b/tests/ui/nll/polonius/polonius-smoke-test.stderr @@ -8,7 +8,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/polonius-smoke-test.rs:12:13 | LL | let y = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | let z = x; | ^ use of borrowed `x` LL | let w = y; @@ -18,7 +18,9 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/polonius-smoke-test.rs:18:13 | LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 { - | - let's call the lifetime of this reference `'1` + | - - let's call the lifetime of this reference `'1` + | | + | binding `x` declared here LL | let y = &mut *x; | ------- borrow of `*x` occurs here LL | let z = x; @@ -29,6 +31,8 @@ LL | y error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/polonius-smoke-test.rs:42:5 | +LL | let s = &mut 1; + | - binding `s` declared here LL | let r = &mut *s; | ------- borrow of `*s` occurs here LL | let tmp = foo(&r); diff --git a/tests/ui/nll/promoted-bounds.stderr b/tests/ui/nll/promoted-bounds.stderr index df347f4e7f0..d111256b845 100644 --- a/tests/ui/nll/promoted-bounds.stderr +++ b/tests/ui/nll/promoted-bounds.stderr @@ -4,6 +4,7 @@ error[E0597]: `l` does not live long enough LL | let ptr = { | --- borrow later stored here LL | let l = 3; + | - binding `l` declared here LL | let b = &l; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/reference-carried-through-struct-field.stderr b/tests/ui/nll/reference-carried-through-struct-field.stderr index 56d878e4303..5672b9cd7e9 100644 --- a/tests/ui/nll/reference-carried-through-struct-field.stderr +++ b/tests/ui/nll/reference-carried-through-struct-field.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/reference-carried-through-struct-field.rs:6:5 | LL | let wrapper = Wrap { w: &mut x }; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | x += 1; | ^^^^^^ use of borrowed `x` LL | *wrapper.w += 1; diff --git a/tests/ui/nll/relate_tys/var-appears-twice.stderr b/tests/ui/nll/relate_tys/var-appears-twice.stderr index d032ce6f213..ff6ea598ff4 100644 --- a/tests/ui/nll/relate_tys/var-appears-twice.stderr +++ b/tests/ui/nll/relate_tys/var-appears-twice.stderr @@ -1,6 +1,9 @@ error[E0597]: `b` does not live long enough --> $DIR/var-appears-twice.rs:20:38 | +LL | let b = 44; + | - binding `b` declared here +... LL | let x: DoubleCell<_> = make_cell(&b); | ------------- ^^ borrowed value does not live long enough | | diff --git a/tests/ui/nll/user-annotations/adt-brace-enums.stderr b/tests/ui/nll/user-annotations/adt-brace-enums.stderr index 253e3825110..9e94fd5a782 100644 --- a/tests/ui/nll/user-annotations/adt-brace-enums.stderr +++ b/tests/ui/nll/user-annotations/adt-brace-enums.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-brace-enums.rs:25:48 | +LL | let c = 66; + | - binding `c` declared here LL | SomeEnum::SomeVariant::<&'static u32> { t: &c }; | ^^ | | @@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; + | - binding `c` declared here LL | SomeEnum::SomeVariant::<&'a u32> { t: &c }; | ^^ | | diff --git a/tests/ui/nll/user-annotations/adt-brace-structs.stderr b/tests/ui/nll/user-annotations/adt-brace-structs.stderr index 8b9d1705df6..cbb7f6a55a9 100644 --- a/tests/ui/nll/user-annotations/adt-brace-structs.stderr +++ b/tests/ui/nll/user-annotations/adt-brace-structs.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-brace-structs.rs:23:37 | +LL | let c = 66; + | - binding `c` declared here LL | SomeStruct::<&'static u32> { t: &c }; | ^^ | | @@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; + | - binding `c` declared here LL | SomeStruct::<&'a u32> { t: &c }; | ^^ | | diff --git a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr index 3326fa521fc..bca85a90d19 100644 --- a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr +++ b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-nullary-enums.rs:33:41 | +LL | let c = 66; + | - binding `c` declared here LL | / combine( LL | | SomeEnum::SomeVariant(Cell::new(&c)), | | ^^ borrowed value does not live long enough @@ -15,7 +17,9 @@ error[E0597]: `c` does not live long enough | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here -... +LL | let c = 66; + | - binding `c` declared here +LL | combine( LL | SomeEnum::SomeVariant(Cell::new(&c)), | ----------^^- | | | diff --git a/tests/ui/nll/user-annotations/adt-tuple-enums.stderr b/tests/ui/nll/user-annotations/adt-tuple-enums.stderr index 2fa7042631d..d2d85ec2b9b 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-enums.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-enums.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-tuple-enums.rs:28:43 | +LL | let c = 66; + | - binding `c` declared here LL | SomeEnum::SomeVariant::<&'static u32>(&c); | ^^ | | @@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; + | - binding `c` declared here LL | SomeEnum::SomeVariant::<&'a u32>(&c); | ^^ | | diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr index 9664fb9f548..b7bc2a10b70 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -1,6 +1,9 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-tuple-struct-calls.rs:27:7 | +LL | let c = 66; + | - binding `c` declared here +LL | let f = SomeStruct::<&'static u32>; LL | f(&c); | --^^- | | | @@ -14,7 +17,9 @@ error[E0597]: `c` does not live long enough | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here -... +LL | let c = 66; + | - binding `c` declared here +LL | let f = SomeStruct::<&'a u32>; LL | f(&c); | --^^- | | | diff --git a/tests/ui/nll/user-annotations/adt-tuple-struct.stderr b/tests/ui/nll/user-annotations/adt-tuple-struct.stderr index 76b5252258c..97d39da265f 100644 --- a/tests/ui/nll/user-annotations/adt-tuple-struct.stderr +++ b/tests/ui/nll/user-annotations/adt-tuple-struct.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/adt-tuple-struct.rs:23:32 | +LL | let c = 66; + | - binding `c` declared here LL | SomeStruct::<&'static u32>(&c); | ^^ | | @@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; + | - binding `c` declared here LL | SomeStruct::<&'a u32>(&c); | ^^ | | diff --git a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr index 4599d04e7e2..3b9363c41f2 100644 --- a/tests/ui/nll/user-annotations/cast_static_lifetime.stderr +++ b/tests/ui/nll/user-annotations/cast_static_lifetime.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/cast_static_lifetime.rs:5:19 | +LL | let x = 22_u32; + | - binding `x` declared here LL | let y: &u32 = (&x) as &'static u32; | ^^^^---------------- | | diff --git a/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr b/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr index 12065a85aa4..f164255ef30 100644 --- a/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr +++ b/tests/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/constant-in-expr-inherent-2.rs:23:9 | +LL | let x = (); + | - binding `x` declared here LL | FUN(&x); | ----^^- | | | @@ -13,6 +15,9 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/constant-in-expr-inherent-2.rs:24:23 | +LL | let x = (); + | - binding `x` declared here +LL | FUN(&x); LL | A::ASSOCIATED_FUN(&x); | ------------------^^- | | | @@ -25,6 +30,9 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/constant-in-expr-inherent-2.rs:25:28 | +LL | let x = (); + | - binding `x` declared here +... LL | B::ALSO_ASSOCIATED_FUN(&x); | -----------------------^^- | | | @@ -37,6 +45,9 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/constant-in-expr-inherent-2.rs:26:31 | +LL | let x = (); + | - binding `x` declared here +... LL | <_>::TRAIT_ASSOCIATED_FUN(&x); | --------------------------^^- | | | diff --git a/tests/ui/nll/user-annotations/fns.stderr b/tests/ui/nll/user-annotations/fns.stderr index e0640da39e2..8b53e138d9b 100644 --- a/tests/ui/nll/user-annotations/fns.stderr +++ b/tests/ui/nll/user-annotations/fns.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/fns.rs:23:29 | +LL | let c = 66; + | - binding `c` declared here LL | some_fn::<&'static u32>(&c); | ------------------------^^- | | | @@ -15,6 +17,7 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here LL | let c = 66; + | - binding `c` declared here LL | some_fn::<&'a u32>(&c); | -------------------^^- | | | diff --git a/tests/ui/nll/user-annotations/method-call.stderr b/tests/ui/nll/user-annotations/method-call.stderr index 10447e45a6d..3803cbf776b 100644 --- a/tests/ui/nll/user-annotations/method-call.stderr +++ b/tests/ui/nll/user-annotations/method-call.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/method-call.rs:36:34 | +LL | let c = 66; + | - binding `c` declared here LL | a.method::<&'static u32>(b, &c); | -----------------------------^^- | | | @@ -15,6 +17,8 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... +LL | let c = 66; + | - binding `c` declared here LL | a.method::<&'a u32>(b, &c); | ------------------------^^- | | | diff --git a/tests/ui/nll/user-annotations/method-ufcs-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-1.stderr index 962ddfd2bd1..c7c08c948ab 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-1.stderr @@ -1,6 +1,9 @@ error[E0597]: `a` does not live long enough --> $DIR/method-ufcs-1.rs:30:7 | +LL | let a = 22; + | - binding `a` declared here +... LL | x(&a, b, c); | --^^------- | | | @@ -14,6 +17,8 @@ error[E0597]: `a` does not live long enough | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here +LL | let a = 22; + | - binding `a` declared here ... LL | <&'a u32 as Bazoom<_>>::method(&a, b, c); | -------------------------------^^------- diff --git a/tests/ui/nll/user-annotations/method-ufcs-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-2.stderr index 63d59905e1c..b7861a3bd06 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-2.stderr @@ -1,6 +1,9 @@ error[E0597]: `a` does not live long enough --> $DIR/method-ufcs-2.rs:30:7 | +LL | let a = 22; + | - binding `a` declared here +... LL | x(&a, b, c); | --^^------- | | | @@ -14,7 +17,10 @@ error[E0597]: `b` does not live long enough | LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here -... +LL | let a = 22; +LL | let b = 44; + | - binding `b` declared here +LL | let c = 66; LL | <_ as Bazoom<&'a u32>>::method(a, &b, c); | ----------------------------------^^---- | | | diff --git a/tests/ui/nll/user-annotations/method-ufcs-3.stderr b/tests/ui/nll/user-annotations/method-ufcs-3.stderr index e7851833e93..8cb995a03ce 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-3.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-3.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/method-ufcs-3.rs:36:53 | +LL | let c = 66; + | - binding `c` declared here LL | <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); | ------------------------------------------------^^- | | | @@ -15,6 +17,8 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) { | -- lifetime `'a` defined here ... +LL | let c = 66; + | - binding `c` declared here LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); | -------------------------------------------^^- | | | diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr index 94861babd6f..fb26b8d09e1 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-1.stderr @@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let v = 22; + | - binding `v` declared here LL | let x = A::<'a>::new(&v, 22); | -------------^^----- | | | diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr index 06f20d9b235..03b97447e1a 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-2.stderr @@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let v = 22; + | - binding `v` declared here LL | let x = A::<'a>::new::<&'a u32>(&v, &v); | ------------------------^^----- | | | @@ -19,6 +20,7 @@ error[E0597]: `v` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let v = 22; + | - binding `v` declared here LL | let x = A::<'a>::new::<&'a u32>(&v, &v); | ----------------------------^^- | | | diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr index 4ad61dc81c4..69dd1d1aaae 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-3.stderr @@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let v = 22; + | - binding `v` declared here LL | let x = <A<'a>>::new(&v, 22); | -------------^^----- | | | diff --git a/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr index 0f83e99cdfb..66d82bb49dc 100644 --- a/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr +++ b/tests/ui/nll/user-annotations/method-ufcs-inherent-4.stderr @@ -4,6 +4,7 @@ error[E0597]: `v` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let v = 22; + | - binding `v` declared here LL | let x = <A<'a>>::new::<&'a u32>(&v, &v); | ------------------------^^----- | | | @@ -19,6 +20,7 @@ error[E0597]: `v` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let v = 22; + | - binding `v` declared here LL | let x = <A<'a>>::new::<&'a u32>(&v, &v); | ----------------------------^^- | | | diff --git a/tests/ui/nll/user-annotations/normalization.stderr b/tests/ui/nll/user-annotations/normalization.stderr index 975cb4b66d9..acc3a1800f4 100644 --- a/tests/ui/nll/user-annotations/normalization.stderr +++ b/tests/ui/nll/user-annotations/normalization.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/normalization.rs:10:31 | +LL | let a = 22; + | - binding `a` declared here LL | let _: <() as Foo>::Out = &a; | ---------------- ^^ borrowed value does not live long enough | | @@ -12,6 +14,8 @@ LL | } error[E0597]: `a` does not live long enough --> $DIR/normalization.rs:13:40 | +LL | let a = 22; + | - binding `a` declared here LL | let _: <&'static () as Foo>::Out = &a; | ------------------------- ^^ borrowed value does not live long enough | | diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr index a97e7a9fd46..3e7969e1179 100644 --- a/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr +++ b/tests/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr @@ -1,6 +1,8 @@ error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_brace_enum_variant.rs:7:33 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo::Bar { field: &y }; | ^^ borrowed value does not live long enough LL | @@ -12,6 +14,8 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_brace_enum_variant.rs:14:33 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo::Bar { field: &y }; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr index 408d7c2a5e2..89a1e9545e8 100644 --- a/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr +++ b/tests/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr @@ -1,6 +1,8 @@ error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_brace_struct.rs:5:28 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo { field: &y }; | ^^ borrowed value does not live long enough LL | @@ -12,6 +14,8 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_brace_struct.rs:12:28 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo { field: &y }; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr index 920c906f63a..8efeecc7709 100644 --- a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr +++ b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr @@ -1,6 +1,8 @@ error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_tuple_enum_variant.rs:7:24 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo::Bar(&y); | ^^ borrowed value does not live long enough LL | @@ -12,6 +14,8 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_tuple_enum_variant.rs:14:24 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo::Bar(&y); | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr index 3f01638d847..d7f1dac88a6 100644 --- a/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr +++ b/tests/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr @@ -1,6 +1,8 @@ error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_tuple_struct.rs:5:19 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo(&y); | ^^ borrowed value does not live long enough LL | @@ -12,6 +14,8 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/pattern_substs_on_tuple_struct.rs:12:19 | +LL | let y = 22; + | - binding `y` declared here LL | let foo = Foo(&y); | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/nll/user-annotations/patterns.stderr b/tests/ui/nll/user-annotations/patterns.stderr index de6f8f80fe2..8bb714f1d0c 100644 --- a/tests/ui/nll/user-annotations/patterns.stderr +++ b/tests/ui/nll/user-annotations/patterns.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:6:9 | +LL | let x = 22; + | - binding `x` declared here LL | let y: &'static u32; | ------------ type annotation requires that `x` is borrowed for `'static` LL | y = &x; @@ -11,6 +13,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:14:9 | +LL | let x = 22; + | - binding `x` declared here LL | let (y, z): (&'static u32, &'static u32); | ---------------------------- type annotation requires that `x` is borrowed for `'static` LL | y = &x; @@ -21,6 +25,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:20:13 | +LL | let x = 22; + | - binding `x` declared here LL | let y = &x; | ^^ borrowed value does not live long enough LL | let ref z: &'static u32 = y; @@ -32,6 +38,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:39:9 | +LL | let x = 22; + | - binding `x` declared here LL | let Single { value: y }: Single<&'static u32>; | -------------------- type annotation requires that `x` is borrowed for `'static` LL | y = &x; @@ -42,6 +50,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:51:10 | +LL | let x = 22; + | - binding `x` declared here LL | let Single2 { value: mut _y }: Single2<StaticU32>; | ------------------ type annotation requires that `x` is borrowed for `'static` LL | _y = &x; @@ -52,6 +62,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:56:27 | +LL | let x = 22; + | - binding `x` declared here LL | let y: &'static u32 = &x; | ------------ ^^ borrowed value does not live long enough | | @@ -62,6 +74,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:61:27 | +LL | let x = 22; + | - binding `x` declared here LL | let _: &'static u32 = &x; | ------------ ^^ borrowed value does not live long enough | | @@ -100,6 +114,8 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:75:40 | +LL | let x = 22; + | - binding `x` declared here LL | let (_, _): (&'static u32, u32) = (&x, 44); | ------------------- ^^ borrowed value does not live long enough | | @@ -110,6 +126,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:80:40 | +LL | let x = 22; + | - binding `x` declared here LL | let (y, _): (&'static u32, u32) = (&x, 44); | ------------------- ^^ borrowed value does not live long enough | | @@ -120,6 +138,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:85:69 | +LL | let x = 22; + | - binding `x` declared here LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; | -------------------- ^^ borrowed value does not live long enough | | @@ -130,6 +150,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:90:69 | +LL | let x = 22; + | - binding `x` declared here LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; | -------------------- ^^ borrowed value does not live long enough | | @@ -140,6 +162,8 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:98:17 | +LL | let x = 22; + | - binding `x` declared here LL | let Double { value1: _, value2: _ }: Double<&'static u32> = Double { | -------------------- type annotation requires that `x` is borrowed for `'static` LL | value1: &x, diff --git a/tests/ui/nll/user-annotations/promoted-annotation.stderr b/tests/ui/nll/user-annotations/promoted-annotation.stderr index cb99a6a369d..132a00ba415 100644 --- a/tests/ui/nll/user-annotations/promoted-annotation.stderr +++ b/tests/ui/nll/user-annotations/promoted-annotation.stderr @@ -4,6 +4,7 @@ error[E0597]: `x` does not live long enough LL | fn foo<'a>() { | -- lifetime `'a` defined here LL | let x = 0; + | - binding `x` declared here LL | let f = &drop::<&'a i32>; | ---------------- assignment requires that `x` is borrowed for `'a` LL | f(&x); diff --git a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr index ccbf3c1d927..766877f8835 100644 --- a/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr +++ b/tests/ui/nll/user-annotations/type_ascription_static_lifetime.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/type_ascription_static_lifetime.rs:6:33 | +LL | let x = 22_u32; + | - binding `x` declared here LL | let y: &u32 = type_ascribe!(&x, &'static u32); | --------------^^--------------- | | | diff --git a/tests/ui/parser/anon-enums.rs b/tests/ui/parser/anon-enums.rs new file mode 100644 index 00000000000..56b8a3d43be --- /dev/null +++ b/tests/ui/parser/anon-enums.rs @@ -0,0 +1,17 @@ +fn foo(x: bool | i32) -> i32 | f64 { +//~^ ERROR anonymous enums are not supported +//~| ERROR anonymous enums are not supported + match x { + x: i32 => x, //~ ERROR expected + true => 42., + false => 0.333, + } +} + +fn main() { + match foo(true) { + 42: i32 => (), //~ ERROR expected + _: f64 => (), //~ ERROR expected + x: i32 => (), //~ ERROR expected + } +} diff --git a/tests/ui/parser/anon-enums.stderr b/tests/ui/parser/anon-enums.stderr new file mode 100644 index 00000000000..84158225660 --- /dev/null +++ b/tests/ui/parser/anon-enums.stderr @@ -0,0 +1,68 @@ +error: anonymous enums are not supported + --> $DIR/anon-enums.rs:1:16 + | +LL | fn foo(x: bool | i32) -> i32 | f64 { + | ---- ^ --- + | + = help: create a named `enum` and use it here instead: + enum Name { + Variant1(bool), + Variant2(i32), + } + +error: anonymous enums are not supported + --> $DIR/anon-enums.rs:1:30 + | +LL | fn foo(x: bool | i32) -> i32 | f64 { + | --- ^ --- + | + = help: create a named `enum` and use it here instead: + enum Name { + Variant1(i32), + Variant2(f64), + } + +error: expected one of `@` or `|`, found `:` + --> $DIR/anon-enums.rs:5:10 + | +LL | x: i32 => x, + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `@` or `|` + | +help: maybe write a path separator here + | +LL | x::i32 => x, + | ~~ + +error: expected one of `...`, `..=`, `..`, or `|`, found `:` + --> $DIR/anon-enums.rs:13:11 + | +LL | 42: i32 => (), + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `...`, `..=`, `..`, or `|` + +error: expected `|`, found `:` + --> $DIR/anon-enums.rs:14:10 + | +LL | _: f64 => (), + | ^ --- specifying the type of a pattern isn't supported + | | + | expected `|` + +error: expected one of `@` or `|`, found `:` + --> $DIR/anon-enums.rs:15:10 + | +LL | x: i32 => (), + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `@` or `|` + | +help: maybe write a path separator here + | +LL | x::i32 => (), + | ~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/parser/bastion-of-the-turbofish.rs b/tests/ui/parser/bastion-of-the-turbofish.rs index e12857008a5..7ceea676d3a 100644 --- a/tests/ui/parser/bastion-of-the-turbofish.rs +++ b/tests/ui/parser/bastion-of-the-turbofish.rs @@ -34,7 +34,7 @@ // See https://github.com/rust-lang/rust/pull/53562 // and https://github.com/rust-lang/rfcs/pull/2527 -// and https://twitter.com/garblefart/status/1393236602856611843 +// and https://web.archive.org/web/20211010063452/https://twitter.com/garblefart/status/1393236602856611843 // for context. fn main() { diff --git a/tests/ui/parser/deli-ident-issue-1.rs b/tests/ui/parser/deli-ident-issue-1.rs new file mode 100644 index 00000000000..54485262a0c --- /dev/null +++ b/tests/ui/parser/deli-ident-issue-1.rs @@ -0,0 +1,24 @@ +#![feature(let_chains)] +trait Demo {} + +impl dyn Demo { + pub fn report(&self) -> u32 { + let sum = |a: u32, + b: u32, + c: u32| { + a + b + c + }; + sum(1, 2, 3) + } + + fn check(&self, val: Option<u32>, num: Option<u32>) { + if let Some(b) = val + && let Some(c) = num { + && b == c { + //~^ ERROR expected struct + //~| ERROR mismatched types + } + } +} + +fn main() { } //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/deli-ident-issue-1.stderr b/tests/ui/parser/deli-ident-issue-1.stderr new file mode 100644 index 00000000000..1119edb199f --- /dev/null +++ b/tests/ui/parser/deli-ident-issue-1.stderr @@ -0,0 +1,37 @@ +error: this file contains an unclosed delimiter + --> $DIR/deli-ident-issue-1.rs:24:66 + | +LL | impl dyn Demo { + | - unclosed delimiter +... +LL | && let Some(c) = num { + | - this delimiter might not be properly closed... +... +LL | } + | - ...as it matches this but it has different indentation +... +LL | fn main() { } + | ^ + +error[E0574]: expected struct, variant or union type, found local variable `c` + --> $DIR/deli-ident-issue-1.rs:17:17 + | +LL | && b == c { + | ^ not a struct, variant or union type + +error[E0308]: mismatched types + --> $DIR/deli-ident-issue-1.rs:17:9 + | +LL | fn check(&self, val: Option<u32>, num: Option<u32>) { + | - expected `()` because of default return type +... +LL | / && b == c { +LL | | +LL | | +LL | | } + | |_________^ expected `()`, found `bool` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0574. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/deli-ident-issue-2.rs b/tests/ui/parser/deli-ident-issue-2.rs new file mode 100644 index 00000000000..5394760df70 --- /dev/null +++ b/tests/ui/parser/deli-ident-issue-2.rs @@ -0,0 +1,7 @@ +fn main() { + if 1 < 2 { + let _a = vec!]; //~ ERROR mismatched closing delimiter + } +} //~ ERROR unexpected closing delimiter + +fn main() {} diff --git a/tests/ui/parser/deli-ident-issue-2.stderr b/tests/ui/parser/deli-ident-issue-2.stderr new file mode 100644 index 00000000000..c8f59c9d32b --- /dev/null +++ b/tests/ui/parser/deli-ident-issue-2.stderr @@ -0,0 +1,19 @@ +error: unexpected closing delimiter: `}` + --> $DIR/deli-ident-issue-2.rs:5:1 + | +LL | let _a = vec!]; + | - missing open `[` for this delimiter +LL | } +LL | } + | ^ unexpected closing delimiter + +error: mismatched closing delimiter: `]` + --> $DIR/deli-ident-issue-2.rs:2:14 + | +LL | if 1 < 2 { + | ^ unclosed delimiter +LL | let _a = vec!]; + | ^ mismatched closing delimiter + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/fake-anon-enums-in-macros.rs b/tests/ui/parser/fake-anon-enums-in-macros.rs new file mode 100644 index 00000000000..38fe8dee238 --- /dev/null +++ b/tests/ui/parser/fake-anon-enums-in-macros.rs @@ -0,0 +1,20 @@ +// build-pass +macro_rules! check_ty { + ($Z:ty) => { compile_error!("triggered"); }; + ($X:ty | $Y:ty) => { $X }; +} + +macro_rules! check { + ($Z:ty) => { compile_error!("triggered"); }; + ($X:ty | $Y:ty) => { }; +} + +check! { i32 | u8 } + +fn foo(x: check_ty! { i32 | u8 }) -> check_ty! { i32 | u8 } { + x +} +fn main() { + let x: check_ty! { i32 | u8 } = 42; + let _: check_ty! { i32 | u8 } = foo(x); +} diff --git a/tests/ui/parser/issue-68987-unmatch-issue-1.rs b/tests/ui/parser/issue-68987-unmatch-issue-1.rs new file mode 100644 index 00000000000..30e7ef46736 --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue-1.rs @@ -0,0 +1,12 @@ +// This file has unexpected closing delimiter, + +fn func(o: Option<u32>) { + match o { + Some(_x) => {} // Extra '}' + let _ = if true {}; + } + None => {} + } +} //~ ERROR unexpected closing delimiter + +fn main() {} diff --git a/tests/ui/parser/issue-68987-unmatch-issue-1.stderr b/tests/ui/parser/issue-68987-unmatch-issue-1.stderr new file mode 100644 index 00000000000..2d873b46193 --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue-1.stderr @@ -0,0 +1,16 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-68987-unmatch-issue-1.rs:10:1 + | +LL | match o { + | - this delimiter might not be properly closed... +LL | Some(_x) => {} // Extra '}' + | -- block is empty, you might have not meant to close it +LL | let _ = if true {}; +LL | } + | - ...as it matches this but it has different indentation +... +LL | } + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.rs b/tests/ui/parser/issue-68987-unmatch-issue-2.rs new file mode 100644 index 00000000000..89aaa68ba40 --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue-2.rs @@ -0,0 +1,14 @@ +// FIXME: this case need more work to fix +// currently the TokenTree matching ')' with '{', which is not user friendly for diagnostics +async fn obstest() -> Result<> { + let obs_connect = || -> Result<(), MyError) { //~ ERROR mismatched closing delimiter + async { + } + } + + if let Ok(version, scene_list) = obs_connect() { + + } else { + + } +} //~ ERROR unexpected closing delimiter diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.stderr b/tests/ui/parser/issue-68987-unmatch-issue-2.stderr new file mode 100644 index 00000000000..2c08d41a15f --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue-2.stderr @@ -0,0 +1,19 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-68987-unmatch-issue-2.rs:14:1 + | +LL | let obs_connect = || -> Result<(), MyError) { + | - missing open `(` for this delimiter +... +LL | } + | ^ unexpected closing delimiter + +error: mismatched closing delimiter: `)` + --> $DIR/issue-68987-unmatch-issue-2.rs:3:32 + | +LL | async fn obstest() -> Result<> { + | ^ unclosed delimiter +LL | let obs_connect = || -> Result<(), MyError) { + | ^ mismatched closing delimiter + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.rs b/tests/ui/parser/issue-68987-unmatch-issue-3.rs new file mode 100644 index 00000000000..e98df8d7c3c --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue-3.rs @@ -0,0 +1,8 @@ +// the `{` is closed with `)`, there is a missing `(` +fn f(i: u32, j: u32) { + let res = String::new(); + let mut cnt = i; + while cnt < j { + write!&mut res, " "); //~ ERROR mismatched closing delimiter + } +} //~ ERROR unexpected closing delimiter diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.stderr b/tests/ui/parser/issue-68987-unmatch-issue-3.stderr new file mode 100644 index 00000000000..a3fc46a1e88 --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue-3.stderr @@ -0,0 +1,19 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-68987-unmatch-issue-3.rs:8:1 + | +LL | write!&mut res, " "); + | - missing open `(` for this delimiter +LL | } +LL | } + | ^ unexpected closing delimiter + +error: mismatched closing delimiter: `)` + --> $DIR/issue-68987-unmatch-issue-3.rs:5:19 + | +LL | while cnt < j { + | ^ unclosed delimiter +LL | write!&mut res, " "); + | ^ mismatched closing delimiter + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issue-68987-unmatch-issue.rs b/tests/ui/parser/issue-68987-unmatch-issue.rs new file mode 100644 index 00000000000..5a3620bf24b --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue.rs @@ -0,0 +1,12 @@ +// This file has unexpected closing delimiter, + +fn func(o: Option<u32>) { + match o { + Some(_x) => // Missing '{' + let _ = if true {}; + } + None => {} + } +} //~ ERROR unexpected closing delimiter + +fn main() {} diff --git a/tests/ui/parser/issue-68987-unmatch-issue.stderr b/tests/ui/parser/issue-68987-unmatch-issue.stderr new file mode 100644 index 00000000000..cabd133242f --- /dev/null +++ b/tests/ui/parser/issue-68987-unmatch-issue.stderr @@ -0,0 +1,16 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-68987-unmatch-issue.rs:10:1 + | +LL | match o { + | - this delimiter might not be properly closed... +LL | Some(_x) => // Missing '{' +LL | let _ = if true {}; + | -- block is empty, you might have not meant to close it +LL | } + | - ...as it matches this but it has different indentation +... +LL | } + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/tests/ui/parser/issue-81827.stderr b/tests/ui/parser/issue-81827.stderr index 069de339194..867244b72e8 100644 --- a/tests/ui/parser/issue-81827.stderr +++ b/tests/ui/parser/issue-81827.stderr @@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter --> $DIR/issue-81827.rs:11:27 | LL | fn r()->i{0|{#[cfg(r(0{]0 - | - - ^ - | | | + | - - - ^ + | | | | + | | | missing open `[` for this delimiter | | unclosed delimiter | unclosed delimiter @@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter --> $DIR/issue-81827.rs:11:27 | LL | fn r()->i{0|{#[cfg(r(0{]0 - | - - ^ - | | | + | - - - ^ + | | | | + | | | missing open `[` for this delimiter | | unclosed delimiter | unclosed delimiter diff --git a/tests/ui/parser/issues/issue-44406.stderr b/tests/ui/parser/issues/issue-44406.stderr index 1f0c1ea4c2f..de02ea85b27 100644 --- a/tests/ui/parser/issues/issue-44406.stderr +++ b/tests/ui/parser/issues/issue-44406.stderr @@ -21,8 +21,8 @@ LL | foo!(true); = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) help: if `bar` is a struct, use braces as delimiters | -LL | bar { } - | ~ +LL | bar { baz: $rest } + | ~ ~ help: if `bar` is a function, use the arguments directly | LL - bar(baz: $rest) diff --git a/tests/ui/parser/issues/issue-62973.stderr b/tests/ui/parser/issues/issue-62973.stderr index 4737bc71860..3cb6d75a675 100644 --- a/tests/ui/parser/issues/issue-62973.stderr +++ b/tests/ui/parser/issues/issue-62973.stderr @@ -2,8 +2,10 @@ error: this file contains an unclosed delimiter --> $DIR/issue-62973.rs:8:2 | LL | fn p() { match s { v, E { [) {) } - | - - unclosed delimiter - | | + | - - - - missing open `(` for this delimiter + | | | | + | | | missing open `(` for this delimiter + | | unclosed delimiter | unclosed delimiter LL | LL | @@ -13,8 +15,10 @@ error: this file contains an unclosed delimiter --> $DIR/issue-62973.rs:8:2 | LL | fn p() { match s { v, E { [) {) } - | - - unclosed delimiter - | | + | - - - - missing open `(` for this delimiter + | | | | + | | | missing open `(` for this delimiter + | | unclosed delimiter | unclosed delimiter LL | LL | diff --git a/tests/ui/parser/issues/issue-63116.stderr b/tests/ui/parser/issues/issue-63116.stderr index cfdd99d1434..a1f8a77ffa7 100644 --- a/tests/ui/parser/issues/issue-63116.stderr +++ b/tests/ui/parser/issues/issue-63116.stderr @@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter --> $DIR/issue-63116.rs:3:18 | LL | impl W <s(f;Y(;] - | - ^ - | | + | - - ^ + | | | + | | missing open `[` for this delimiter | unclosed delimiter error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;` diff --git a/tests/ui/parser/issues/issue-69259.rs b/tests/ui/parser/issues/issue-69259.rs new file mode 100644 index 00000000000..01fc2c08546 --- /dev/null +++ b/tests/ui/parser/issues/issue-69259.rs @@ -0,0 +1,3 @@ +fn main() {} + +fn f) {} //~ ERROR unexpected closing delimiter diff --git a/tests/ui/parser/issues/issue-69259.stderr b/tests/ui/parser/issues/issue-69259.stderr new file mode 100644 index 00000000000..604b7de3319 --- /dev/null +++ b/tests/ui/parser/issues/issue-69259.stderr @@ -0,0 +1,8 @@ +error: unexpected closing delimiter: `)` + --> $DIR/issue-69259.rs:3:5 + | +LL | fn f) {} + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-70583-block-is-empty-1.stderr b/tests/ui/parser/issues/issue-70583-block-is-empty-1.stderr index 39bf113ef83..46cbb056d1d 100644 --- a/tests/ui/parser/issues/issue-70583-block-is-empty-1.stderr +++ b/tests/ui/parser/issues/issue-70583-block-is-empty-1.stderr @@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}` --> $DIR/issue-70583-block-is-empty-1.rs:20:1 | LL | fn struct_generic(x: Vec<i32>) { - | - this opening brace... + | - this delimiter might not be properly closed... ... LL | } - | - ...matches this closing brace + | - ...as it matches this but it has different indentation LL | } | ^ unexpected closing delimiter diff --git a/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr b/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr index 5d37b216427..9ae94c70186 100644 --- a/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr +++ b/tests/ui/parser/issues/issue-70583-block-is-empty-2.stderr @@ -1,8 +1,12 @@ error: unexpected closing delimiter: `}` --> $DIR/issue-70583-block-is-empty-2.rs:14:1 | +LL | match self { + | - this delimiter might not be properly closed... LL | ErrorHandled::Reported => {}} - | -- block is empty, you might have not meant to close it + | --- ...as it matches this but it has different indentation + | | + | block is empty, you might have not meant to close it ... LL | } | ^ unexpected closing delimiter diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs index 0b7b67496d6..e1ea38f2795 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs @@ -68,7 +68,6 @@ fn main() { Foo:Bar::Baz => {} //~^ ERROR: expected one of //~| HELP: maybe write a path separator here - //~| ERROR: failed to resolve: `Bar` is a variant, not a module } match myfoo { Foo::Bar => {} diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr index 2050a16beb3..63b072ac4cd 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr @@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:17:12 | LL | Foo:Bar => {} - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | Foo::Bar => {} + | ~~ error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:23:17 | LL | qux::Foo:Bar => {} - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of 8 possible tokens - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | qux::Foo::Bar => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:29:12 | LL | qux:Foo::Baz => {} - | ^ + | ^-------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | qux::Foo::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:35:12 | LL | qux: Foo::Baz if true => {} - | ^ + | ^ -------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | qux::Foo::Baz if true => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:40:15 | LL | if let Foo:Bar = f() { - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | if let Foo::Bar = f() { + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:48:16 | LL | ref qux: Foo::Baz => {} - | ^ + | ^ -------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | ref qux::Foo::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:57:16 | LL | mut qux: Foo::Baz => {} - | ^ + | ^ -------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | mut qux::Foo::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` --> $DIR/issue-87086-colon-path-sep.rs:68:12 | LL | Foo:Bar::Baz => {} - | ^ + | ^-------- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` + | +help: maybe write a path separator here + | +LL | Foo::Bar::Baz => {} + | ~~ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:75:12 + --> $DIR/issue-87086-colon-path-sep.rs:74:12 | LL | Foo:Bar => {} - | ^ + | ^--- specifying the type of a pattern isn't supported | | | expected one of `@` or `|` - | help: maybe write a path separator here: `::` - -error[E0433]: failed to resolve: `Bar` is a variant, not a module - --> $DIR/issue-87086-colon-path-sep.rs:68:13 | -LL | Foo:Bar::Baz => {} - | ^^^ `Bar` is a variant, not a module +help: maybe write a path separator here + | +LL | Foo::Bar => {} + | ~~ -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr b/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr index 967a3e6fdc1..689ce1eb6b7 100644 --- a/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr +++ b/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr @@ -2,10 +2,10 @@ error: unexpected closing delimiter: `}` --> $DIR/macro-mismatched-delim-paren-brace.rs:5:1 | LL | fn main() { - | - this opening brace... + | - this delimiter might not be properly closed... ... LL | } - | - ...matches this closing brace + | - ...as it matches this but it has different indentation LL | } | ^ unexpected closing delimiter diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index cc04ac05204..c41cda18743 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -5,6 +5,8 @@ fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds +fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds + fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{` //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 99c4515459d..ccce3a8053e 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -13,17 +13,29 @@ LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {} help: remove the parentheses | LL - fn foo2(_: &dyn (Drop + AsRef<str>)) {} -LL + fn foo2(_: &dyn Drop + AsRef<str>) {} +LL + fn foo2(_: &dyn Drop + AsRef<str>) {} + | + +error: incorrect braces around trait bounds + --> $DIR/trait-object-delimiters.rs:8:25 + | +LL | fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} + | ^ ^ + | +help: remove the parentheses + | +LL - fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} +LL + fn foo2_no_space(_: &dyn Drop + AsRef<str>) {} | error: expected parameter name, found `{` - --> $DIR/trait-object-delimiters.rs:8:17 + --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | ^ expected parameter name error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` - --> $DIR/trait-object-delimiters.rs:8:17 + --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | -^ expected one of 10 possible tokens @@ -31,13 +43,13 @@ LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | help: missing `,` error: expected identifier, found `<` - --> $DIR/trait-object-delimiters.rs:12:17 + --> $DIR/trait-object-delimiters.rs:14:17 | LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {} | ^ expected identifier error: invalid `dyn` keyword - --> $DIR/trait-object-delimiters.rs:14:25 + --> $DIR/trait-object-delimiters.rs:16:25 | LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} | ^^^ help: remove this keyword @@ -56,13 +68,13 @@ LL | fn foo1(_: &dyn Drop + AsRef<str>) {} = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0224]: at least one trait is required for an object type - --> $DIR/trait-object-delimiters.rs:8:13 + --> $DIR/trait-object-delimiters.rs:10:13 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | ^^^ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/trait-object-delimiters.rs:14:29 + --> $DIR/trait-object-delimiters.rs:16:29 | LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} | ---- ^^^^^^^^^^ additional non-auto trait @@ -72,7 +84,7 @@ LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0224, E0225. For more information about an error, try `rustc --explain E0224`. diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index c8b45fd24d9..29cd6c45c34 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed LL | Some(ref _y @ _z) => {} | ------^^^-- | | | - | | value moved into `_z` here - | value borrowed, by `_y`, here + | | value is moved into `_z` here + | value is borrowed by `_y` here error: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14 @@ -28,8 +28,8 @@ error: cannot move out of value because it is borrowed LL | Some(ref mut _y @ _z) => {} | ----------^^^-- | | | - | | value moved into `_z` here - | value borrowed, by `_y`, here + | | value is moved into `_z` here + | value is mutably borrowed by `_y` here error: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14 diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index f27df32ccfa..2c123b01e17 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ box b = Box::new(NC); | -----^^^^^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:34:9 @@ -13,8 +13,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ box ref mut b = Box::new(nc()); | -----^^^^^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:36:9 @@ -22,8 +22,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:38:9 @@ -31,8 +31,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:42:9 @@ -40,8 +40,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:48:9 @@ -49,8 +49,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | let ref mut a @ box ref b = Box::new(NC); | ---------^^^^^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:62:9 @@ -58,8 +58,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ box ref b => { | ---------^^^^^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:54:11 @@ -67,8 +67,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | fn f5(ref mut a @ box ref b: Box<NC>) { | ---------^^^^^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error[E0382]: borrow of moved value --> $DIR/borrowck-pat-at-and-box.rs:31:9 diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index 770bb89530c..4f7fbc9e04b 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ b = U; | -----^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9 @@ -13,9 +13,9 @@ error: cannot move out of value because it is borrowed LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ | | | | - | | | value moved into `e` here - | | value moved into `c` here - | value borrowed, by `a`, here + | | | value is moved into `e` here + | | value is moved into `c` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18 @@ -23,8 +23,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^----- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33 @@ -32,8 +32,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^- | | | - | | value moved into `e` here - | value borrowed, by `d`, here + | | value is moved into `e` here + | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 @@ -41,9 +41,9 @@ error: cannot move out of value because it is borrowed LL | let ref mut a @ [b, mut c] = [U, U]; | ---------^^^^-^^-----^ | | | | - | | | value moved into `c` here - | | value moved into `b` here - | value borrowed, by `a`, here + | | | value is moved into `c` here + | | value is moved into `b` here + | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 @@ -51,8 +51,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ b = u(); | -----^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9 @@ -60,9 +60,9 @@ error: cannot move out of value because it is borrowed LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ | | | | - | | | value moved into `e` here - | | value moved into `c` here - | value borrowed, by `a`, here + | | | value is moved into `e` here + | | value is moved into `c` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18 @@ -70,8 +70,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^----- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33 @@ -79,8 +79,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^- | | | - | | value moved into `e` here - | value borrowed, by `d`, here + | | value is moved into `e` here + | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9 @@ -88,9 +88,9 @@ error: cannot move out of value because it is borrowed LL | let ref mut a @ [b, mut c] = [u(), u()]; | ---------^^^^-^^-----^ | | | | - | | | value moved into `c` here - | | value moved into `b` here - | value borrowed, by `a`, here + | | | value is moved into `c` here + | | value is moved into `b` here + | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9 @@ -98,8 +98,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9 @@ -107,9 +107,9 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ | | | | - | | | value moved into `e` here - | | value moved into `c` here - | value borrowed, by `a`, here + | | | value is moved into `e` here + | | value is moved into `c` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23 @@ -117,8 +117,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38 @@ -126,8 +126,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- | | | - | | value moved into `e` here - | value borrowed, by `d`, here + | | value is moved into `e` here + | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9 @@ -135,9 +135,9 @@ error: cannot move out of value because it is borrowed LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ | | | | - | | | value moved into `c` here - | | value moved into `b` here - | value borrowed, by `a`, here + | | | value is moved into `c` here + | | value is moved into `b` here + | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9 @@ -145,8 +145,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 @@ -154,9 +154,9 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ | | | | - | | | value moved into `e` here - | | value moved into `c` here - | value borrowed, by `a`, here + | | | value is moved into `e` here + | | value is moved into `c` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 @@ -164,8 +164,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 @@ -173,8 +173,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- | | | - | | value moved into `e` here - | value borrowed, by `d`, here + | | value is moved into `e` here + | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9 @@ -182,9 +182,9 @@ error: cannot move out of value because it is borrowed LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ | | | | - | | | value moved into `c` here - | | value moved into `b` here - | value borrowed, by `a`, here + | | | value is moved into `c` here + | | value is moved into `b` here + | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11 @@ -192,8 +192,8 @@ error: cannot move out of value because it is borrowed LL | fn f1(ref a @ b: U) {} | -----^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11 @@ -201,9 +201,9 @@ error: cannot move out of value because it is borrowed LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ | | | | - | | | value moved into `e` here - | | value moved into `c` here - | value borrowed, by `a`, here + | | | value is moved into `e` here + | | value is moved into `c` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20 @@ -211,8 +211,8 @@ error: cannot move out of value because it is borrowed LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^----- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35 @@ -220,8 +220,8 @@ error: cannot move out of value because it is borrowed LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^- | | | - | | value moved into `e` here - | value borrowed, by `d`, here + | | value is moved into `e` here + | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 @@ -229,9 +229,9 @@ error: cannot move out of value because it is borrowed LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} | ---------^^^^-^^-----^ | | | | - | | | value moved into `c` here - | | value moved into `b` here - | value borrowed, by `a`, here + | | | value is moved into `c` here + | | value is moved into `b` here + | value is mutably borrowed by `a` here error[E0382]: borrow of partially moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 8546b4bb477..f51b5041858 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -4,8 +4,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut z @ &mut Some(ref a) => { | ---------^^^^^^^^^^^^^-----^ | | | - | | immutable borrow, by `a`, occurs here - | mutable borrow, by `z`, occurs here + | | value is borrowed by `a` here + | value is mutably borrowed by `z` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9 @@ -13,9 +13,9 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | ---------^^^^-----------------^ | | | | - | | | another mutable borrow, by `c`, occurs here - | | also borrowed as immutable, by `b`, here - | first mutable borrow, by `a`, occurs here + | | | value is mutably borrowed by `c` here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22 @@ -23,8 +23,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | -----^^^--------- | | | - | | mutable borrow, by `c`, occurs here - | immutable borrow, by `b`, occurs here + | | value is mutably borrowed by `c` here + | value is borrowed by `b` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9 @@ -32,8 +32,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ ref mut b = U; | -----^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9 @@ -41,8 +41,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | let ref mut a @ ref b = U; | ---------^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9 @@ -50,9 +50,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ | | | | - | | | mutable borrow, by `c`, occurs here - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | | value is mutably borrowed by `c` here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9 @@ -60,9 +60,9 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ | | | | - | | | immutable borrow, by `c`, occurs here - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | | value is borrowed by `c` here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9 @@ -70,8 +70,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | let ref mut a @ ref b = u(); | ---------^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9 @@ -79,8 +79,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ ref mut b = u(); | -----^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9 @@ -88,8 +88,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | let ref mut a @ ref b = U; | ---------^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9 @@ -97,8 +97,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ ref mut b = U; | -----^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9 @@ -106,8 +106,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^-----^ | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33 @@ -115,8 +115,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^^-----^ | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9 @@ -124,8 +124,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^---------^ | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33 @@ -133,8 +133,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^^---------^ | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9 @@ -142,8 +142,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^---------^ | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33 @@ -151,8 +151,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^^---------^ | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9 @@ -160,8 +160,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^-----^ | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33 @@ -169,8 +169,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^^-----^ | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9 @@ -178,8 +178,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^---------^ | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33 @@ -187,8 +187,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^^---------^ | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9 @@ -196,8 +196,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^-----^ | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33 @@ -205,8 +205,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^^-----^ | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 @@ -214,9 +214,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ | | | | - | | | mutable borrow, by `c`, occurs here - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | | value is mutably borrowed by `c` here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 @@ -224,9 +224,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ | | | | - | | | mutable borrow, by `c`, occurs here - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | | value is mutably borrowed by `c` here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 @@ -234,9 +234,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ | | | | - | | | mutable borrow, by `c`, occurs here - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | | value is mutably borrowed by `c` here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9 @@ -244,9 +244,9 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ | | | | - | | | immutable borrow, by `c`, occurs here - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | | value is borrowed by `c` here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11 @@ -254,8 +254,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | fn f1(ref a @ ref mut b: U) {} | -----^^^--------- | | | - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11 @@ -263,8 +263,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable LL | fn f2(ref mut a @ ref b: U) {} | ---------^^^----- | | | - | | immutable borrow, by `b`, occurs here - | mutable borrow, by `a`, occurs here + | | value is borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11 @@ -272,8 +272,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | -----^^^^^^^^^^^----------------^^^^^^^^ | | | - | | mutable borrow, by `mid`, occurs here - | immutable borrow, by `a`, occurs here + | | value is mutably borrowed by `mid` here + | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22 @@ -281,9 +281,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | -----^^^------------- | | | | - | | | also moved into `c` here - | | mutable borrow, by `b`, occurs here - | immutable borrow, by `a`, occurs here + | | | value is moved into `c` here + | | value is mutably borrowed by `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30 @@ -291,8 +291,8 @@ error: cannot move out of value because it is borrowed LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | ---------^^^- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is mutably borrowed by `b` here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31 diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index ad4ce7952ca..a0cb04a064e 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -4,8 +4,8 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ref mut b = U; | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 @@ -13,8 +13,8 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ref mut b = U; | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9 @@ -22,8 +22,8 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ref mut b = U; | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9 @@ -31,8 +31,8 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ref mut b = U; | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9 @@ -40,8 +40,8 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ref mut b = U; | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9 @@ -49,18 +49,18 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ( | ^-------- | | - | _________first mutable borrow, by `a`, occurs here + | _________value is mutably borrowed by `a` here | | LL | | LL | | ref mut b, - | | --------- another mutable borrow, by `b`, occurs here + | | --------- value is mutably borrowed by `b` here LL | | [ LL | | ref mut c, - | | --------- another mutable borrow, by `c`, occurs here + | | --------- value is mutably borrowed by `c` here LL | | ref mut d, - | | --------- another mutable borrow, by `d`, occurs here + | | --------- value is mutably borrowed by `d` here LL | | ref e, - | | ----- also borrowed as immutable, by `e`, here + | | ----- value is borrowed by `e` here LL | | ] LL | | ) = (U, [U, U, U]); | |_____^ @@ -71,18 +71,18 @@ error: cannot borrow value as mutable more than once at a time LL | let ref mut a @ ( | ^-------- | | - | _________first mutable borrow, by `a`, occurs here + | _________value is mutably borrowed by `a` here | | LL | | LL | | ref mut b, - | | --------- another mutable borrow, by `b`, occurs here + | | --------- value is mutably borrowed by `b` here LL | | [ LL | | ref mut c, - | | --------- another mutable borrow, by `c`, occurs here + | | --------- value is mutably borrowed by `c` here LL | | ref mut d, - | | --------- another mutable borrow, by `d`, occurs here + | | --------- value is mutably borrowed by `d` here LL | | ref e, - | | ----- also borrowed as immutable, by `e`, here + | | ----- value is borrowed by `e` here LL | | ] LL | | ) = (u(), [u(), u(), u()]); | |_________^ @@ -157,8 +157,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37 @@ -166,8 +166,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 @@ -175,8 +175,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 @@ -184,8 +184,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9 @@ -193,8 +193,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37 @@ -202,8 +202,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9 @@ -211,8 +211,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37 @@ -220,8 +220,8 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11 @@ -229,8 +229,8 @@ error: cannot borrow value as mutable more than once at a time LL | fn f1(ref mut a @ ref mut b: U) {} | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11 @@ -238,8 +238,8 @@ error: cannot borrow value as mutable more than once at a time LL | fn f2(ref mut a @ ref mut b: U) {} | ---------^^^--------- | | | - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9 @@ -247,13 +247,13 @@ error: cannot borrow value as mutable more than once at a time LL | ref mut a @ [ | ^-------- | | - | _________first mutable borrow, by `a`, occurs here + | _________value is mutably borrowed by `a` here | | LL | | LL | | [ref b @ .., _], - | | ---------- also borrowed as immutable, by `b`, here + | | ---------- value is borrowed by `b` here LL | | [_, ref mut mid @ ..], - | | ---------------- another mutable borrow, by `mid`, occurs here + | | ---------------- value is mutably borrowed by `mid` here LL | | .., LL | | [..], LL | | ] : [[U; 4]; 5] @@ -265,9 +265,9 @@ error: cannot borrow value as mutable more than once at a time LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^------------- | | | | - | | | also moved into `c` here - | | another mutable borrow, by `b`, occurs here - | first mutable borrow, by `a`, occurs here + | | | value is moved into `c` here + | | value is mutably borrowed by `b` here + | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34 @@ -275,8 +275,8 @@ error: cannot move out of value because it is borrowed LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^- | | | - | | value moved into `c` here - | value borrowed, by `b`, here + | | value is moved into `c` here + | value is mutably borrowed by `b` here error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 638bdd6db76..73ebbf48118 100644 --- a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed LL | let ref a @ b = NotCopy; | -----^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:29:9 @@ -13,8 +13,8 @@ error: cannot move out of value because it is borrowed LL | let ref mut a @ b = NotCopy; | ---------^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:34:12 @@ -22,8 +22,8 @@ error: cannot move out of value because it is borrowed LL | Ok(ref a @ b) | Err(b @ ref a) => { | -----^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error: borrow of moved value --> $DIR/default-binding-modes-both-sides-independent.rs:34:29 @@ -46,8 +46,8 @@ error: cannot move out of value because it is borrowed LL | ref a @ b => { | -----^^^- | | | - | | value moved into `b` here - | value borrowed, by `a`, here + | | value is moved into `b` here + | value is borrowed by `a` here error[E0382]: borrow of moved value --> $DIR/default-binding-modes-both-sides-independent.rs:29:9 diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index 1b93267b397..c7c7c074f7c 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed --> $DIR/borrowck-move-ref-pattern.rs:8:24 | +LL | let mut arr = [U, U, U, U, U]; + | ------- binding `arr` declared here LL | let hold_all = &arr; | ---- borrow of `arr` occurs here LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; diff --git a/tests/ui/proc-macro/allowed-signatures.rs b/tests/ui/proc-macro/allowed-signatures.rs new file mode 100644 index 00000000000..86850876112 --- /dev/null +++ b/tests/ui/proc-macro/allowed-signatures.rs @@ -0,0 +1,26 @@ +// check-pass +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![allow(private_in_public)] +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn foo<T>(t: T) -> TokenStream { + TokenStream::new() +} + +trait Project { + type Assoc; +} + +impl Project for () { + type Assoc = TokenStream; +} + +#[proc_macro] +pub fn uwu(_input: <() as Project>::Assoc) -> <() as Project>::Assoc { + TokenStream::new() +} diff --git a/tests/ui/proc-macro/proc-macro-abi.rs b/tests/ui/proc-macro/proc-macro-abi.rs new file mode 100644 index 00000000000..873660a5b3a --- /dev/null +++ b/tests/ui/proc-macro/proc-macro-abi.rs @@ -0,0 +1,31 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![allow(warnings)] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub extern "C" fn abi(a: TokenStream) -> TokenStream { + //~^ ERROR proc macro functions may not be `extern "C"` + a +} + +#[proc_macro] +pub extern "system" fn abi2(a: TokenStream) -> TokenStream { + //~^ ERROR proc macro functions may not be `extern "system"` + a +} + +#[proc_macro] +pub extern fn abi3(a: TokenStream) -> TokenStream { + //~^ ERROR proc macro functions may not be `extern "C"` + a +} + +#[proc_macro] +pub extern "Rust" fn abi4(a: TokenStream) -> TokenStream { + a +} diff --git a/tests/ui/proc-macro/proc-macro-abi.stderr b/tests/ui/proc-macro/proc-macro-abi.stderr new file mode 100644 index 00000000000..9a781be0996 --- /dev/null +++ b/tests/ui/proc-macro/proc-macro-abi.stderr @@ -0,0 +1,20 @@ +error: proc macro functions may not be `extern "C"` + --> $DIR/proc-macro-abi.rs:11:1 + | +LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: proc macro functions may not be `extern "system"` + --> $DIR/proc-macro-abi.rs:17:1 + | +LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: proc macro functions may not be `extern "C"` + --> $DIR/proc-macro-abi.rs:23:1 + | +LL | pub extern fn abi3(a: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.rs b/tests/ui/proc-macro/signature-proc-macro-attribute.rs new file mode 100644 index 00000000000..51abc8e7d3e --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-attribute.rs @@ -0,0 +1,32 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn bad_input(input: String) -> TokenStream { + //~^ ERROR mismatched attribute proc macro signature + ::proc_macro::TokenStream::new() +} + +#[proc_macro_attribute] +pub fn bad_output(input: TokenStream) -> String { + //~^ ERROR mismatched attribute proc macro signature + //~| ERROR mismatched attribute proc macro signature + String::from("blah") +} + +#[proc_macro_attribute] +pub fn bad_everything(input: String) -> String { + //~^ ERROR mismatched attribute proc macro signature + //~| ERROR mismatched attribute proc macro signature + input +} + +#[proc_macro_attribute] +pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + //~^ ERROR mismatched attribute proc macro signature +} diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr new file mode 100644 index 00000000000..abf7a6f3ce9 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr @@ -0,0 +1,42 @@ +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:10:1 + | +LL | pub fn bad_input(input: String) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:16:42 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:16:1 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:23:41 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:23:1 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream` + +error: mismatched attribute proc macro signature + --> $DIR/signature-proc-macro-attribute.rs:30:49 + | +LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + | ^^^^^^^^^ found unexpected argument + +error: aborting due to 6 previous errors + diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.rs b/tests/ui/proc-macro/signature-proc-macro-derive.rs new file mode 100644 index 00000000000..f2fd824b675 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-derive.rs @@ -0,0 +1,31 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(Blah)] +pub fn bad_input(input: String) -> TokenStream { + //~^ ERROR mismatched derive proc macro signature + TokenStream::new() +} + +#[proc_macro_derive(Bleh)] +pub fn bad_output(input: TokenStream) -> String { + //~^ ERROR mismatched derive proc macro signature + String::from("blah") +} + +#[proc_macro_derive(Bluh)] +pub fn bad_everything(input: String) -> String { + //~^ ERROR mismatched derive proc macro signature + //~| ERROR mismatched derive proc macro signature + input +} + +#[proc_macro_derive(Blih)] +pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + //~^ ERROR mismatched derive proc macro signature +} diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.stderr b/tests/ui/proc-macro/signature-proc-macro-derive.stderr new file mode 100644 index 00000000000..a358ae27703 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro-derive.stderr @@ -0,0 +1,40 @@ +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:10:25 + | +LL | pub fn bad_input(input: String) -> TokenStream { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:16:42 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:22:41 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:22:30 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature-proc-macro-derive.rs:29:33 + | +LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments + +error: aborting due to 5 previous errors + diff --git a/tests/ui/proc-macro/signature-proc-macro.rs b/tests/ui/proc-macro/signature-proc-macro.rs new file mode 100644 index 00000000000..54770aacd1a --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro.rs @@ -0,0 +1,31 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn bad_input(input: String) -> TokenStream { + //~^ ERROR mismatched function-like proc macro signature + ::proc_macro::TokenStream::new() +} + +#[proc_macro] +pub fn bad_output(input: TokenStream) -> String { + //~^ ERROR mismatched function-like proc macro signature + String::from("blah") +} + +#[proc_macro] +pub fn bad_everything(input: String) -> String { + //~^ ERROR mismatched function-like proc macro signature + //~| ERROR mismatched function-like proc macro signature + input +} + +#[proc_macro] +pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + //~^ ERROR mismatched function-like proc macro signature +} diff --git a/tests/ui/proc-macro/signature-proc-macro.stderr b/tests/ui/proc-macro/signature-proc-macro.stderr new file mode 100644 index 00000000000..4b14a54e675 --- /dev/null +++ b/tests/ui/proc-macro/signature-proc-macro.stderr @@ -0,0 +1,40 @@ +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:10:25 + | +LL | pub fn bad_input(input: String) -> TokenStream { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:16:42 + | +LL | pub fn bad_output(input: TokenStream) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:22:41 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:22:30 + | +LL | pub fn bad_everything(input: String) -> String { + | ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream` + | + = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched function-like proc macro signature + --> $DIR/signature-proc-macro.rs:29:33 + | +LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments + +error: aborting due to 5 previous errors + diff --git a/tests/ui/proc-macro/signature.rs b/tests/ui/proc-macro/signature.rs index 2302238253e..11187aa31bd 100644 --- a/tests/ui/proc-macro/signature.rs +++ b/tests/ui/proc-macro/signature.rs @@ -8,6 +8,10 @@ extern crate proc_macro; #[proc_macro_derive(A)] pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { - //~^ ERROR: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn + //~^ ERROR: mismatched derive proc macro signature + //~| mismatched derive proc macro signature + //~| mismatched derive proc macro signature + //~| proc macro functions may not be `extern + //~| proc macro functions may not be `unsafe loop {} } diff --git a/tests/ui/proc-macro/signature.stderr b/tests/ui/proc-macro/signature.stderr index 79f2001da00..3dbe3f22a0d 100644 --- a/tests/ui/proc-macro/signature.stderr +++ b/tests/ui/proc-macro/signature.stderr @@ -1,20 +1,36 @@ -error[E0277]: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn(i32, u32) -> u32 {foo}` +error: proc macro functions may not be `extern "C"` --> $DIR/signature.rs:10:1 | -LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { -LL | | -LL | | loop {} -LL | | } - | | ^ - | | | - | |_call the function in a closure: `|| unsafe { /* code */ }` - | required by a bound introduced by this call +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: proc macro functions may not be `unsafe` + --> $DIR/signature.rs:10:1 + | +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: mismatched derive proc macro signature + --> $DIR/signature.rs:10:49 + | +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^ found u32, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature.rs:10:33 + | +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^ found i32, expected type `proc_macro::TokenStream` + | + = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream` + +error: mismatched derive proc macro signature + --> $DIR/signature.rs:10:38 | - = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}` - = note: unsafe function cannot be called generically without an unsafe block -note: required by a bound in `ProcMacro::custom_derive` - --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL +LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { + | ^^^^^^ found unexpected argument -error: aborting due to previous error +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/regions/do-not-suggest-adding-bound-to-opaque-type.stderr b/tests/ui/regions/do-not-suggest-adding-bound-to-opaque-type.stderr index 6ea238f302f..d76a83b0258 100644 --- a/tests/ui/regions/do-not-suggest-adding-bound-to-opaque-type.stderr +++ b/tests/ui/regions/do-not-suggest-adding-bound-to-opaque-type.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/do-not-suggest-adding-bound-to-opaque-type.rs:9:7 | +LL | let x = (); + | - binding `x` declared here LL | S(&x) | --^^- | | | diff --git a/tests/ui/regions/higher-ranked-implied.rs b/tests/ui/regions/higher-ranked-implied.rs new file mode 100644 index 00000000000..103884c5031 --- /dev/null +++ b/tests/ui/regions/higher-ranked-implied.rs @@ -0,0 +1,14 @@ +// FIXME: This test should pass as the first two fields add implied bounds that +// `'a` is equal to `'b` while the last one should simply use that fact. With +// the current implementation this errors. We have to be careful as implied bounds +// are only sound if they're also correctly checked. + +struct Inv<T>(*mut T); // `T` is invariant. +type A = for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'a ()>); +type B = for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'b ()>); + +fn main() { + let x: A = |_, _, _| (); + let y: B = x; //~ ERROR mismatched types + let _: A = y; //~ ERROR mismatched types +} diff --git a/tests/ui/regions/higher-ranked-implied.stderr b/tests/ui/regions/higher-ranked-implied.stderr new file mode 100644 index 00000000000..9d80eacd7c3 --- /dev/null +++ b/tests/ui/regions/higher-ranked-implied.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/higher-ranked-implied.rs:12:16 + | +LL | let y: B = x; + | ^ one type is more general than the other + | + = note: expected fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'b ()>)` + found fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'a ()>)` + +error[E0308]: mismatched types + --> $DIR/higher-ranked-implied.rs:13:16 + | +LL | let _: A = y; + | ^ one type is more general than the other + | + = note: expected fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'a ()>)` + found fn pointer `for<'a, 'b> fn(Inv<&'a &'b ()>, Inv<&'b &'a ()>, Inv<&'b ()>)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/regions/regions-addr-of-arg.stderr b/tests/ui/regions/regions-addr-of-arg.stderr index e77289287e5..99060a9c7f5 100644 --- a/tests/ui/regions/regions-addr-of-arg.stderr +++ b/tests/ui/regions/regions-addr-of-arg.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/regions-addr-of-arg.rs:5:30 | +LL | fn foo(a: isize) { + | - binding `a` declared here LL | let _p: &'static isize = &a; | -------------- ^^ borrowed value does not live long enough | | diff --git a/tests/ui/regions/regions-free-region-ordering-caller1.stderr b/tests/ui/regions/regions-free-region-ordering-caller1.stderr index 8ef7e22536b..c83cfc1c987 100644 --- a/tests/ui/regions/regions-free-region-ordering-caller1.stderr +++ b/tests/ui/regions/regions-free-region-ordering-caller1.stderr @@ -18,6 +18,8 @@ error[E0597]: `y` does not live long enough LL | fn call1<'a>(x: &'a usize) { | -- lifetime `'a` defined here ... +LL | let y: usize = 3; + | - binding `y` declared here LL | let z: &'a & usize = &(&y); | ----------- ^^^^ borrowed value does not live long enough | | diff --git a/tests/ui/regions/regions-infer-proc-static-upvar.stderr b/tests/ui/regions/regions-infer-proc-static-upvar.stderr index 803d0d74491..c8a33bbc522 100644 --- a/tests/ui/regions/regions-infer-proc-static-upvar.stderr +++ b/tests/ui/regions/regions-infer-proc-static-upvar.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/regions-infer-proc-static-upvar.rs:10:13 | +LL | let x = 3; + | - binding `x` declared here LL | let y = &x; | ^^ borrowed value does not live long enough LL | / foo(move|| { diff --git a/tests/ui/regions/regions-nested-fns.stderr b/tests/ui/regions/regions-nested-fns.stderr index bb2740310f6..ee43f9fa572 100644 --- a/tests/ui/regions/regions-nested-fns.stderr +++ b/tests/ui/regions/regions-nested-fns.stderr @@ -13,6 +13,8 @@ LL | ay = z; error[E0597]: `y` does not live long enough --> $DIR/regions-nested-fns.rs:5:18 | +LL | let y = 3; + | - binding `y` declared here LL | let mut ay = &y; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr index f77d94a24b8..18aec29ad0b 100644 --- a/tests/ui/regions/regions-pattern-typing-issue-19552.stderr +++ b/tests/ui/regions/regions-pattern-typing-issue-19552.stderr @@ -1,6 +1,8 @@ error[E0597]: `line` does not live long enough --> $DIR/regions-pattern-typing-issue-19552.rs:5:14 | +LL | let line = String::new(); + | ---- binding `line` declared here LL | match [&*line] { | ^^^^ borrowed value does not live long enough LL | [ word ] => { assert_static(word); } diff --git a/tests/ui/regions/regions-pattern-typing-issue-19997.stderr b/tests/ui/regions/regions-pattern-typing-issue-19997.stderr index ae60e3c0d5d..0abe77a8697 100644 --- a/tests/ui/regions/regions-pattern-typing-issue-19997.stderr +++ b/tests/ui/regions/regions-pattern-typing-issue-19997.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `a1` because it is borrowed --> $DIR/regions-pattern-typing-issue-19997.rs:7:13 | LL | match (&a1,) { - | --- borrow of `a1` occurs here + | --- `a1` is borrowed here LL | (&ref b0,) => { LL | a1 = &f; - | ^^^^^^^ assignment to borrowed `a1` occurs here + | ^^^^^^^ `a1` is assigned to here but it was already borrowed LL | drop(b0); | -- borrow later used here diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/reify-intrinsic.stderr index f78f1d822bf..310b6c224e0 100644 --- a/tests/ui/reify-intrinsic.stderr +++ b/tests/ui/reify-intrinsic.stderr @@ -23,9 +23,7 @@ LL | std::intrinsics::unlikely, | = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}` found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}` - = note: different `fn` items always have unique types, even if their signatures are the same - = help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `likely as extern "rust-intrinsic" fn(bool) -> bool` + = note: different fn items have unique types, even if their signatures are the same error: aborting due to 3 previous errors diff --git a/tests/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr b/tests/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr index de730ce1030..ad84ebe3a50 100644 --- a/tests/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/borrowck-non-exhaustive.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-non-exhaustive.rs:12:11 | LL | let y = &mut x; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | match x { | ^ use of borrowed `x` ... diff --git a/tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr b/tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr index 498a112fa9b..f34ccecdd45 100644 --- a/tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr +++ b/tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr @@ -37,6 +37,11 @@ help: add a block here | LL | if let Some(n) = opt else { | ^ +help: remove the `if` if you meant to write a `let...else` statement + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5 + | +LL | if let Some(n) = opt else { + | ^^ error: this `if` expression is missing a block after the condition --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5 diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr index cf5815df56e..07f6dc906c6 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr @@ -5,12 +5,15 @@ LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here ... LL | let foo: fn() = foo; - | ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers - | | + | ---- ^^^ + | | | + | | cannot coerce functions with `#[target_feature]` to safe function pointers + | | help: consider casting to a fn pointer: `foo as fn()` | expected due to this | = note: expected fn pointer `fn()` found fn item `fn() {foo}` + = note: fn items are distinct from fn pointers = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers error: aborting due to previous error diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr index cf5815df56e..07f6dc906c6 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr @@ -5,12 +5,15 @@ LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here ... LL | let foo: fn() = foo; - | ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers - | | + | ---- ^^^ + | | | + | | cannot coerce functions with `#[target_feature]` to safe function pointers + | | help: consider casting to a fn pointer: `foo as fn()` | expected due to this | = note: expected fn pointer `fn()` found fn item `fn() {foo}` + = note: fn items are distinct from fn pointers = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers error: aborting due to previous error diff --git a/tests/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr b/tests/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr index 5f93ad6e027..1c26eb8803d 100644 --- a/tests/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr +++ b/tests/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr @@ -1,6 +1,9 @@ error[E0597]: `s` does not live long enough --> $DIR/lifetime-update.rs:20:17 | +LL | let s = String::from("hello"); + | - binding `s` declared here +... LL | lt_str: &s, | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs b/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs index 0b3de0df2b8..d2254acb33f 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs +++ b/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs @@ -365,4 +365,24 @@ mod unions { } } +// https://github.com/rust-lang/rust/issues/106870 +mod multiple_predicates_with_same_span { + macro_rules! m { + ($($name:ident)+) => { + struct Inline<'a, $($name: 'a,)+>(&'a ($($name,)+)); + //~^ ERROR: outlives requirements can be inferred + struct FullWhere<'a, $($name,)+>(&'a ($($name,)+)) where $($name: 'a,)+; + //~^ ERROR: outlives requirements can be inferred + struct PartialWhere<'a, $($name,)+>(&'a ($($name,)+)) where (): Sized, $($name: 'a,)+; + //~^ ERROR: outlives requirements can be inferred + struct Interleaved<'a, $($name,)+>(&'a ($($name,)+)) + where + (): Sized, + $($name: 'a, $name: 'a, )+ //~ ERROR: outlives requirements can be inferred + $($name: 'a, $name: 'a, )+; + } + } + m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15); +} + fn main() {} diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr b/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr index 251d74094ca..f5ec287d291 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr +++ b/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr @@ -819,5 +819,61 @@ LL - union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: LL + union BeeWhereAyTeeYooWhereOutlivesAyIsDebugBee<'a, 'b, T, U> where U: Debug, { | -error: aborting due to 68 previous errors +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:372:38 + | +LL | struct Inline<'a, $($name: 'a,)+>(&'a ($($name,)+)); + | ^^^^ help: remove these bounds +... +LL | m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15); + | --------------------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:374:64 + | +LL | struct FullWhere<'a, $($name,)+>(&'a ($($name,)+)) where $($name: 'a,)+; + | ^^^^^^^^^^^^^^^^^^ help: remove these bounds +... +LL | m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15); + | --------------------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:376:86 + | +LL | struct PartialWhere<'a, $($name,)+>(&'a ($($name,)+)) where (): Sized, $($name: 'a,)+; + | ^^^^^^^^^ help: remove these bounds +... +LL | m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15); + | --------------------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives-multispan.rs:381:19 + | +LL | $($name: 'a, $name: 'a, )+ + | ^^^^^^^^^ ^^^^^^^^^ +LL | $($name: 'a, $name: 'a, )+; + | ^^^^^^^^^ ^^^^^^^^^ +... +LL | m!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15); + | --------------------------------------------------------- + | | + | in this macro invocation + | in this macro invocation + | in this macro invocation + | in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove these bounds + | +LL ~ $(, , )+ +LL ~ $(, , )+; + | + +error: aborting due to 72 previous errors diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed b/tests/ui/rust-2018/edition-lint-infer-outlives.fixed index 13645244da0..868bdf2e068 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed +++ b/tests/ui/rust-2018/edition-lint-infer-outlives.fixed @@ -791,5 +791,14 @@ struct StaticRef<T: 'static> { field: &'static T } +struct TrailingCommaInWhereClause<'a, T, U> +where + T: 'a, + + //~^ ERROR outlives requirements can be inferred +{ + tee: T, + yoo: &'a U +} fn main() {} diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.rs b/tests/ui/rust-2018/edition-lint-infer-outlives.rs index d9486ba66f8..75783764ad6 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives.rs +++ b/tests/ui/rust-2018/edition-lint-infer-outlives.rs @@ -791,5 +791,14 @@ struct StaticRef<T: 'static> { field: &'static T } +struct TrailingCommaInWhereClause<'a, T, U> +where + T: 'a, + U: 'a, + //~^ ERROR outlives requirements can be inferred +{ + tee: T, + yoo: &'a U +} fn main() {} diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr b/tests/ui/rust-2018/edition-lint-infer-outlives.stderr index faa9f21e38b..e655fb4842c 100644 --- a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr +++ b/tests/ui/rust-2018/edition-lint-infer-outlives.stderr @@ -1,8 +1,8 @@ error: outlives requirements can be inferred - --> $DIR/edition-lint-infer-outlives.rs:26:31 + --> $DIR/edition-lint-infer-outlives.rs:797:5 | -LL | struct TeeOutlivesAy<'a, T: 'a> { - | ^^^^ help: remove this bound +LL | U: 'a, + | ^^^^^^ help: remove this bound | note: the lint level is defined here --> $DIR/edition-lint-infer-outlives.rs:4:9 @@ -11,6 +11,12 @@ LL | #![deny(explicit_outlives_requirements)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: outlives requirements can be inferred + --> $DIR/edition-lint-infer-outlives.rs:26:31 + | +LL | struct TeeOutlivesAy<'a, T: 'a> { + | ^^^^ help: remove this bound + +error: outlives requirements can be inferred --> $DIR/edition-lint-infer-outlives.rs:31:40 | LL | struct TeeOutlivesAyIsDebug<'a, T: 'a + Debug> { @@ -916,5 +922,5 @@ error: outlives requirements can be inferred LL | union BeeWhereOutlivesAyTeeWhereDebug<'a, 'b, T> where 'b: 'a, T: Debug { | ^^^^^^^^ help: remove this bound -error: aborting due to 152 previous errors +error: aborting due to 153 previous errors diff --git a/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs b/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs index 65fec3becac..91aacedfc57 100644 --- a/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs +++ b/tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs @@ -3,6 +3,7 @@ #![feature(rustc_attrs)] use std::{ + cell::Cell, ops::{Deref, CoerceUnsized, DispatchFromDyn}, marker::Unsize, }; @@ -20,6 +21,20 @@ impl<T: ?Sized> Deref for Ptr<T> { impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {} impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {} + +struct CellPtr<'a, T: ?Sized>(Cell<&'a T>); + +impl<'a, T: ?Sized> Deref for CellPtr<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + self.0.get() + } +} + +impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<CellPtr<'a, U>> for CellPtr<'a, T> {} +impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<CellPtr<'a, U>> for CellPtr<'a, T> {} + struct Wrapper<T: ?Sized>(T); impl<T: ?Sized> Deref for Wrapper<T> { @@ -42,6 +57,7 @@ trait Trait { fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32; + fn cell(self: CellPtr<Self>) -> i32; } impl Trait for i32 { @@ -54,6 +70,9 @@ impl Trait for i32 { fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 { ***self } + fn cell(self: CellPtr<Self>) -> i32 { + *self + } } fn main() { @@ -65,4 +84,7 @@ fn main() { let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>; assert_eq!(wpw.wrapper_ptr_wrapper(), 7); + + let c = CellPtr(Cell::new(&8)) as CellPtr<dyn Trait>; + assert_eq!(c.cell(), 8); } diff --git a/tests/ui/self/issue-61882-2.stderr b/tests/ui/self/issue-61882-2.stderr index 0b8e134c966..6faa4477d8c 100644 --- a/tests/ui/self/issue-61882-2.stderr +++ b/tests/ui/self/issue-61882-2.stderr @@ -1,6 +1,8 @@ error[E0597]: `x` does not live long enough --> $DIR/issue-61882-2.rs:6:14 | +LL | let x = 0; + | - binding `x` declared here LL | Self(&x); | ^^ | | diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 48b42bc7825..9711dad8078 100644 --- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -47,6 +47,9 @@ LL | foo(f); error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 | +LL | let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| { + | ----- binding `f` declared here +... LL | f(Box::new(|a| { | - ^^^ move out of `f` occurs here | | diff --git a/tests/ui/span/borrowck-let-suggestion-suffixes.rs b/tests/ui/span/borrowck-let-suggestion-suffixes.rs index 18abfb5c3fb..ad556f281df 100644 --- a/tests/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/tests/ui/span/borrowck-let-suggestion-suffixes.rs @@ -8,6 +8,7 @@ fn f() { { let young = ['y']; // statement 3 + //~^ NOTE binding `young` declared here v2.push(&young[0]); // statement 4 //~^ ERROR `young[_]` does not live long enough diff --git a/tests/ui/span/borrowck-let-suggestion-suffixes.stderr b/tests/ui/span/borrowck-let-suggestion-suffixes.stderr index 2dc29a78d20..545b235a552 100644 --- a/tests/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/tests/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -1,6 +1,9 @@ error[E0597]: `young[_]` does not live long enough - --> $DIR/borrowck-let-suggestion-suffixes.rs:12:17 + --> $DIR/borrowck-let-suggestion-suffixes.rs:13:17 | +LL | let young = ['y']; // statement 3 + | ----- binding `young` declared here +... LL | v2.push(&young[0]); // statement 4 | ^^^^^^^^^ borrowed value does not live long enough ... @@ -11,7 +14,7 @@ LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:19:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:20:14 | LL | v3.push(&id('x')); // statement 6 | ^^^^^^^ - temporary value is freed at the end of this statement @@ -28,7 +31,7 @@ LL ~ v3.push(&binding); // statement 6 | error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:29:18 + --> $DIR/borrowck-let-suggestion-suffixes.rs:30:18 | LL | v4.push(&id('y')); | ^^^^^^^ - temporary value is freed at the end of this statement @@ -41,7 +44,7 @@ LL | v4.use_ref(); = note: consider using a `let` binding to create a longer lived value error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:40:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:41:14 | LL | v5.push(&id('z')); | ^^^^^^^ - temporary value is freed at the end of this statement diff --git a/tests/ui/span/destructor-restrictions.stderr b/tests/ui/span/destructor-restrictions.stderr index 53c9404620f..281248626c8 100644 --- a/tests/ui/span/destructor-restrictions.stderr +++ b/tests/ui/span/destructor-restrictions.stderr @@ -1,6 +1,8 @@ error[E0597]: `*a` does not live long enough --> $DIR/destructor-restrictions.rs:8:10 | +LL | let a = Box::new(RefCell::new(4)); + | - binding `a` declared here LL | *a.borrow() + 1 | ^^^^^^^^^^ | | diff --git a/tests/ui/span/dropck-object-cycle.stderr b/tests/ui/span/dropck-object-cycle.stderr index 229d17e1cf9..097fb6219f1 100644 --- a/tests/ui/span/dropck-object-cycle.stderr +++ b/tests/ui/span/dropck-object-cycle.stderr @@ -1,6 +1,8 @@ error[E0597]: `*m` does not live long enough --> $DIR/dropck-object-cycle.rs:27:31 | +LL | let m : Box<dyn Trait+'static> = make_val(); + | - binding `m` declared here LL | assert_eq!(object_invoke1(&*m), (4,5)); | ^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/dropck_arr_cycle_checked.stderr b/tests/ui/span/dropck_arr_cycle_checked.stderr index 068c779ae52..23ebc8d598c 100644 --- a/tests/ui/span/dropck_arr_cycle_checked.stderr +++ b/tests/ui/span/dropck_arr_cycle_checked.stderr @@ -1,6 +1,9 @@ error[E0597]: `b2` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:93:24 | +LL | let (b1, b2, b3); + | -- binding `b2` declared here +... LL | b1.a[0].v.set(Some(&b2)); | ^^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `b3` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:95:24 | +LL | let (b1, b2, b3); + | -- binding `b3` declared here +... LL | b1.a[1].v.set(Some(&b3)); | ^^^ borrowed value does not live long enough ... @@ -29,6 +35,9 @@ LL | } error[E0597]: `b1` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:99:24 | +LL | let (b1, b2, b3); + | -- binding `b1` declared here +... LL | b3.a[0].v.set(Some(&b1)); | ^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/dropck_direct_cycle_with_drop.stderr b/tests/ui/span/dropck_direct_cycle_with_drop.stderr index 07ae138ac71..1e75e3b2fa1 100644 --- a/tests/ui/span/dropck_direct_cycle_with_drop.stderr +++ b/tests/ui/span/dropck_direct_cycle_with_drop.stderr @@ -1,6 +1,8 @@ error[E0597]: `d2` does not live long enough --> $DIR/dropck_direct_cycle_with_drop.rs:36:19 | +LL | let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2"))); + | -- binding `d2` declared here LL | d1.p.set(Some(&d2)); | ^^^ borrowed value does not live long enough ... @@ -15,6 +17,9 @@ LL | } error[E0597]: `d1` does not live long enough --> $DIR/dropck_direct_cycle_with_drop.rs:38:19 | +LL | let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2"))); + | -- binding `d1` declared here +... LL | d2.p.set(Some(&d1)); | ^^^ borrowed value does not live long enough LL | diff --git a/tests/ui/span/dropck_misc_variants.stderr b/tests/ui/span/dropck_misc_variants.stderr index 76e90574cef..24a2c9089f5 100644 --- a/tests/ui/span/dropck_misc_variants.stderr +++ b/tests/ui/span/dropck_misc_variants.stderr @@ -1,6 +1,9 @@ error[E0597]: `bomb` does not live long enough --> $DIR/dropck_misc_variants.rs:23:36 | +LL | let (_w, bomb); + | ---- binding `bomb` declared here +LL | bomb = vec![""]; LL | _w = Wrap::<&[&str]>(NoisyDrop(&bomb)); | ^^^^^ borrowed value does not live long enough LL | } @@ -14,6 +17,9 @@ LL | } error[E0597]: `v` does not live long enough --> $DIR/dropck_misc_variants.rs:31:27 | +LL | let (_w,v); + | - binding `v` declared here +... LL | let u = NoisyDrop(&v); | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/dropck_vec_cycle_checked.stderr b/tests/ui/span/dropck_vec_cycle_checked.stderr index 7ff991c0c37..5817439c0d8 100644 --- a/tests/ui/span/dropck_vec_cycle_checked.stderr +++ b/tests/ui/span/dropck_vec_cycle_checked.stderr @@ -1,6 +1,9 @@ error[E0597]: `c2` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:98:24 | +LL | let (mut c1, mut c2, mut c3); + | ------ binding `c2` declared here +... LL | c1.v[0].v.set(Some(&c2)); | ^^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `c3` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:100:24 | +LL | let (mut c1, mut c2, mut c3); + | ------ binding `c3` declared here +... LL | c1.v[1].v.set(Some(&c3)); | ^^^ borrowed value does not live long enough ... @@ -29,6 +35,9 @@ LL | } error[E0597]: `c1` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:104:24 | +LL | let (mut c1, mut c2, mut c3); + | ------ binding `c1` declared here +... LL | c3.v[0].v.set(Some(&c1)); | ^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/issue-23338-locals-die-before-temps-of-body.stderr b/tests/ui/span/issue-23338-locals-die-before-temps-of-body.stderr index 3c2022748f0..e1a377203e2 100644 --- a/tests/ui/span/issue-23338-locals-die-before-temps-of-body.stderr +++ b/tests/ui/span/issue-23338-locals-die-before-temps-of-body.stderr @@ -1,6 +1,8 @@ error[E0597]: `y` does not live long enough --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:10:5 | +LL | let y = x; + | - binding `y` declared here LL | y.borrow().clone() | ^^^^^^^^^^ | | @@ -22,6 +24,8 @@ LL | let x = y.borrow().clone(); x error[E0597]: `y` does not live long enough --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:17:9 | +LL | let y = x; + | - binding `y` declared here LL | y.borrow().clone() | ^^^^^^^^^^ | | diff --git a/tests/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr b/tests/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr index 809e60a8c8a..c3b6d7580b4 100644 --- a/tests/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr +++ b/tests/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr @@ -1,6 +1,9 @@ error[E0597]: `d1` does not live long enough --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:28:18 | +LL | let (_d, d1); + | -- binding `d1` declared here +... LL | _d = D_Child(&d1); | ^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/issue-24805-dropck-trait-has-items.stderr b/tests/ui/span/issue-24805-dropck-trait-has-items.stderr index 2e217066915..e52c57d9ab1 100644 --- a/tests/ui/span/issue-24805-dropck-trait-has-items.stderr +++ b/tests/ui/span/issue-24805-dropck-trait-has-items.stderr @@ -1,6 +1,9 @@ error[E0597]: `d1` does not live long enough --> $DIR/issue-24805-dropck-trait-has-items.rs:37:26 | +LL | let (_d, d1); + | -- binding `d1` declared here +LL | d1 = D_HasSelfMethod(1); LL | _d = D_HasSelfMethod(&d1); | ^^^ borrowed value does not live long enough LL | } @@ -14,6 +17,9 @@ LL | } error[E0597]: `d1` does not live long enough --> $DIR/issue-24805-dropck-trait-has-items.rs:43:33 | +LL | let (_d, d1); + | -- binding `d1` declared here +LL | d1 = D_HasMethodWithSelfArg(1); LL | _d = D_HasMethodWithSelfArg(&d1); | ^^^ borrowed value does not live long enough LL | } @@ -27,6 +33,9 @@ LL | } error[E0597]: `d1` does not live long enough --> $DIR/issue-24805-dropck-trait-has-items.rs:49:20 | +LL | let (_d, d1); + | -- binding `d1` declared here +LL | d1 = D_HasType(1); LL | _d = D_HasType(&d1); | ^^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/issue-24895-copy-clone-dropck.stderr b/tests/ui/span/issue-24895-copy-clone-dropck.stderr index 18a3dc9e6de..83db4d509d4 100644 --- a/tests/ui/span/issue-24895-copy-clone-dropck.stderr +++ b/tests/ui/span/issue-24895-copy-clone-dropck.stderr @@ -1,6 +1,9 @@ error[E0597]: `d1` does not live long enough --> $DIR/issue-24895-copy-clone-dropck.rs:27:14 | +LL | let (d2, d1); + | -- binding `d1` declared here +LL | d1 = D(34, "d1"); LL | d2 = D(S(&d1, "inner"), "d2"); | ^^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/issue-25199.stderr b/tests/ui/span/issue-25199.stderr index d70a4afc1bf..1e0276f0c36 100644 --- a/tests/ui/span/issue-25199.stderr +++ b/tests/ui/span/issue-25199.stderr @@ -1,6 +1,8 @@ error[E0597]: `container` does not live long enough --> $DIR/issue-25199.rs:70:27 | +LL | let container = Container::new(); + | --------- binding `container` declared here LL | let test = Test{test: &container}; | ^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/issue-26656.stderr b/tests/ui/span/issue-26656.stderr index 1e939c484fb..fea6e001238 100644 --- a/tests/ui/span/issue-26656.stderr +++ b/tests/ui/span/issue-26656.stderr @@ -1,6 +1,9 @@ error[E0597]: `ticking` does not live long enough --> $DIR/issue-26656.rs:40:35 | +LL | let (mut zook, ticking); + | ------- binding `ticking` declared here +... LL | zook.button = B::BigRedButton(&ticking); | ^^^^^^^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/issue-29106.stderr b/tests/ui/span/issue-29106.stderr index 71fbd60ee73..28ee7acd90e 100644 --- a/tests/ui/span/issue-29106.stderr +++ b/tests/ui/span/issue-29106.stderr @@ -1,6 +1,9 @@ error[E0597]: `x` does not live long enough --> $DIR/issue-29106.rs:16:26 | +LL | let (y, x); + | - binding `x` declared here +LL | x = "alive".to_string(); LL | y = Arc::new(Foo(&x)); | ^^ borrowed value does not live long enough LL | } @@ -14,6 +17,9 @@ LL | } error[E0597]: `x` does not live long enough --> $DIR/issue-29106.rs:23:25 | +LL | let (y, x); + | - binding `x` declared here +LL | x = "alive".to_string(); LL | y = Rc::new(Foo(&x)); | ^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/issue-36537.stderr b/tests/ui/span/issue-36537.stderr index 79a0ebaeb8d..6c330c1a094 100644 --- a/tests/ui/span/issue-36537.stderr +++ b/tests/ui/span/issue-36537.stderr @@ -1,6 +1,8 @@ error[E0597]: `a` does not live long enough --> $DIR/issue-36537.rs:5:13 | +LL | let a = 42; + | - binding `a` declared here LL | p = &a; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/issue-40157.stderr b/tests/ui/span/issue-40157.stderr index 57f80214a4f..a0afd33f7c7 100644 --- a/tests/ui/span/issue-40157.stderr +++ b/tests/ui/span/issue-40157.stderr @@ -2,11 +2,10 @@ error[E0597]: `foo` does not live long enough --> $DIR/issue-40157.rs:2:53 | LL | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} - | ------------------------^^^^^^^^^^-- - | | | | - | | | `foo` dropped here while still borrowed - | | borrowed value does not live long enough - | borrow later used here + | --- ^^^^^^^^^^ - `foo` dropped here while still borrowed + | | | + | | borrowed value does not live long enough + | binding `foo` declared here error: aborting due to previous error diff --git a/tests/ui/span/issue28498-reject-lifetime-param.stderr b/tests/ui/span/issue28498-reject-lifetime-param.stderr index 3119ddd03cc..94c450c7b1e 100644 --- a/tests/ui/span/issue28498-reject-lifetime-param.stderr +++ b/tests/ui/span/issue28498-reject-lifetime-param.stderr @@ -1,6 +1,9 @@ error[E0597]: `first_dropped` does not live long enough --> $DIR/issue28498-reject-lifetime-param.rs:32:19 | +LL | let (foo1, first_dropped); + | ------------- binding `first_dropped` declared here +... LL | foo1 = Foo(1, &first_dropped); | ^^^^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/issue28498-reject-passed-to-fn.stderr b/tests/ui/span/issue28498-reject-passed-to-fn.stderr index 60e8a648cd5..e133f75d57b 100644 --- a/tests/ui/span/issue28498-reject-passed-to-fn.stderr +++ b/tests/ui/span/issue28498-reject-passed-to-fn.stderr @@ -1,6 +1,9 @@ error[E0597]: `first_dropped` does not live long enough --> $DIR/issue28498-reject-passed-to-fn.rs:34:19 | +LL | let (foo1, first_dropped); + | ------------- binding `first_dropped` declared here +... LL | foo1 = Foo(1, &first_dropped, Box::new(callback)); | ^^^^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/issue28498-reject-trait-bound.stderr b/tests/ui/span/issue28498-reject-trait-bound.stderr index 22e4a8205b6..9ab3cdd1343 100644 --- a/tests/ui/span/issue28498-reject-trait-bound.stderr +++ b/tests/ui/span/issue28498-reject-trait-bound.stderr @@ -1,6 +1,9 @@ error[E0597]: `first_dropped` does not live long enough --> $DIR/issue28498-reject-trait-bound.rs:34:19 | +LL | let (foo1, first_dropped); + | ------------- binding `first_dropped` declared here +... LL | foo1 = Foo(1, &first_dropped); | ^^^^^^^^^^^^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/mut-ptr-cant-outlive-ref.stderr b/tests/ui/span/mut-ptr-cant-outlive-ref.stderr index 4d976a7bbfa..be56f9489c7 100644 --- a/tests/ui/span/mut-ptr-cant-outlive-ref.stderr +++ b/tests/ui/span/mut-ptr-cant-outlive-ref.stderr @@ -1,6 +1,8 @@ error[E0597]: `b` does not live long enough --> $DIR/mut-ptr-cant-outlive-ref.rs:8:15 | +LL | let b = m.borrow(); + | - binding `b` declared here LL | p = &*b; | ^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/range-2.stderr b/tests/ui/span/range-2.stderr index 8ca8156b083..d7084b00ba4 100644 --- a/tests/ui/span/range-2.stderr +++ b/tests/ui/span/range-2.stderr @@ -3,7 +3,9 @@ error[E0597]: `a` does not live long enough | LL | let r = { | - borrow later stored here -... +LL | let a = 42; + | - binding `a` declared here +LL | let b = 42; LL | &a..&b | ^^ borrowed value does not live long enough LL | }; @@ -14,7 +16,9 @@ error[E0597]: `b` does not live long enough | LL | let r = { | - borrow later stored here -... +LL | let a = 42; +LL | let b = 42; + | - binding `b` declared here LL | &a..&b | ^^ borrowed value does not live long enough LL | }; diff --git a/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr b/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr index 0b985de609c..fb3fad6ae90 100644 --- a/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr +++ b/tests/ui/span/regionck-unboxed-closure-lifetimes.stderr @@ -1,6 +1,8 @@ error[E0597]: `c` does not live long enough --> $DIR/regionck-unboxed-closure-lifetimes.rs:8:21 | +LL | let c = 1; + | - binding `c` declared here LL | let c_ref = &c; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/regions-close-over-type-parameter-2.stderr b/tests/ui/span/regions-close-over-type-parameter-2.stderr index 2e584d9a884..fed40a4fdd2 100644 --- a/tests/ui/span/regions-close-over-type-parameter-2.stderr +++ b/tests/ui/span/regions-close-over-type-parameter-2.stderr @@ -1,6 +1,8 @@ error[E0597]: `tmp0` does not live long enough --> $DIR/regions-close-over-type-parameter-2.rs:23:20 | +LL | let tmp0 = 3; + | ---- binding `tmp0` declared here LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | repeater3(tmp1) diff --git a/tests/ui/span/regions-escape-loop-via-variable.stderr b/tests/ui/span/regions-escape-loop-via-variable.stderr index 42df6685297..e5c7d8b26ab 100644 --- a/tests/ui/span/regions-escape-loop-via-variable.stderr +++ b/tests/ui/span/regions-escape-loop-via-variable.stderr @@ -2,7 +2,9 @@ error[E0597]: `x` does not live long enough --> $DIR/regions-escape-loop-via-variable.rs:11:13 | LL | let x = 1 + *p; - | -- borrow later used here + | - -- borrow later used here + | | + | binding `x` declared here LL | p = &x; | ^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/regions-escape-loop-via-vec.stderr b/tests/ui/span/regions-escape-loop-via-vec.stderr index 2b649307739..532ac3606c5 100644 --- a/tests/ui/span/regions-escape-loop-via-vec.stderr +++ b/tests/ui/span/regions-escape-loop-via-vec.stderr @@ -2,7 +2,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:5:11 | LL | let mut _y = vec![&mut x]; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | while x < 10 { | ^ use of borrowed `x` LL | let mut z = x; @@ -13,7 +13,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:6:21 | LL | let mut _y = vec![&mut x]; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here LL | while x < 10 { LL | let mut z = x; | ^ use of borrowed `x` @@ -23,11 +23,10 @@ LL | _y.push(&mut z); error[E0597]: `z` does not live long enough --> $DIR/regions-escape-loop-via-vec.rs:7:17 | +LL | let mut z = x; + | ----- binding `z` declared here LL | _y.push(&mut z); - | --------^^^^^^- - | | | - | | borrowed value does not live long enough - | borrow later used here + | ^^^^^^ borrowed value does not live long enough ... LL | } | - `z` dropped here while still borrowed @@ -36,7 +35,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:9:9 | LL | let mut _y = vec![&mut x]; - | ------ borrow of `x` occurs here + | ------ `x` is borrowed here ... LL | _y.push(&mut z); | --------------- borrow later used here diff --git a/tests/ui/span/regions-infer-borrow-scope-within-loop.stderr b/tests/ui/span/regions-infer-borrow-scope-within-loop.stderr index fd67c65c4e9..47931db84ca 100644 --- a/tests/ui/span/regions-infer-borrow-scope-within-loop.stderr +++ b/tests/ui/span/regions-infer-borrow-scope-within-loop.stderr @@ -1,6 +1,9 @@ error[E0597]: `*x` does not live long enough --> $DIR/regions-infer-borrow-scope-within-loop.rs:13:20 | +LL | let x = make_box(); + | - binding `x` declared here +... LL | y = borrow(&*x); | ^^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/send-is-not-static-ensures-scoping.stderr b/tests/ui/span/send-is-not-static-ensures-scoping.stderr index 65d10c1305b..bae0befcaca 100644 --- a/tests/ui/span/send-is-not-static-ensures-scoping.stderr +++ b/tests/ui/span/send-is-not-static-ensures-scoping.stderr @@ -4,6 +4,7 @@ error[E0597]: `x` does not live long enough LL | let bad = { | --- borrow later stored here LL | let x = 1; + | - binding `x` declared here LL | let y = &x; | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/send-is-not-static-std-sync-2.stderr b/tests/ui/span/send-is-not-static-std-sync-2.stderr index bcd07e11647..b0267fa6f43 100644 --- a/tests/ui/span/send-is-not-static-std-sync-2.stderr +++ b/tests/ui/span/send-is-not-static-std-sync-2.stderr @@ -4,6 +4,7 @@ error[E0597]: `x` does not live long enough LL | let lock = { | ---- borrow later stored here LL | let x = 1; + | - binding `x` declared here LL | Mutex::new(&x) | ^^ borrowed value does not live long enough LL | }; @@ -15,6 +16,7 @@ error[E0597]: `x` does not live long enough LL | let lock = { | ---- borrow later stored here LL | let x = 1; + | - binding `x` declared here LL | RwLock::new(&x) | ^^ borrowed value does not live long enough LL | }; @@ -25,7 +27,9 @@ error[E0597]: `x` does not live long enough | LL | let (_tx, rx) = { | --- borrow later used here -... +LL | let x = 1; + | - binding `x` declared here +LL | let (tx, rx) = mpsc::channel(); LL | let _ = tx.send(&x); | ^^ borrowed value does not live long enough LL | (tx, rx) diff --git a/tests/ui/span/send-is-not-static-std-sync.stderr b/tests/ui/span/send-is-not-static-std-sync.stderr index 5d493a3e4ee..7dfe94bca60 100644 --- a/tests/ui/span/send-is-not-static-std-sync.stderr +++ b/tests/ui/span/send-is-not-static-std-sync.stderr @@ -1,6 +1,9 @@ error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:13:10 | +LL | let y = Box::new(1); + | - binding `y` declared here +LL | let lock = Mutex::new(&x); LL | *lock.lock().unwrap() = &*y; | --- borrow of `*y` occurs here LL | drop(y); @@ -12,6 +15,8 @@ LL | *lock.lock().unwrap() = &z; error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:16:33 | +LL | let z = 2; + | - binding `z` declared here LL | *lock.lock().unwrap() = &z; | ^^ borrowed value does not live long enough LL | } @@ -23,6 +28,9 @@ LL | lock.use_ref(); // (Mutex is #[may_dangle] so its dtor does not use `z` error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:27:10 | +LL | let y = Box::new(1); + | - binding `y` declared here +LL | let lock = RwLock::new(&x); LL | *lock.write().unwrap() = &*y; | --- borrow of `*y` occurs here LL | drop(y); @@ -34,6 +42,8 @@ LL | *lock.write().unwrap() = &z; error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:30:34 | +LL | let z = 2; + | - binding `z` declared here LL | *lock.write().unwrap() = &z; | ^^ borrowed value does not live long enough LL | } @@ -45,6 +55,9 @@ LL | lock.use_ref(); // (RwLock is #[may_dangle] so its dtor does not use `z error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:43:10 | +LL | let y = Box::new(1); + | - binding `y` declared here +... LL | tx.send(&*y); | --- borrow of `*y` occurs here LL | drop(y); @@ -56,6 +69,8 @@ LL | tx.send(&z).unwrap(); error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:46:17 | +LL | let z = 2; + | - binding `z` declared here LL | tx.send(&z).unwrap(); | ^^ borrowed value does not live long enough LL | } diff --git a/tests/ui/span/vec-must-not-hide-type-from-dropck.stderr b/tests/ui/span/vec-must-not-hide-type-from-dropck.stderr index f87c32d1ad0..f2fefca414e 100644 --- a/tests/ui/span/vec-must-not-hide-type-from-dropck.stderr +++ b/tests/ui/span/vec-must-not-hide-type-from-dropck.stderr @@ -1,6 +1,9 @@ error[E0597]: `c2` does not live long enough --> $DIR/vec-must-not-hide-type-from-dropck.rs:117:24 | +LL | let (mut c1, mut c2); + | ------ binding `c2` declared here +... LL | c1.v[0].v.set(Some(&c2)); | ^^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `c1` does not live long enough --> $DIR/vec-must-not-hide-type-from-dropck.rs:119:24 | +LL | let (mut c1, mut c2); + | ------ binding `c1` declared here +... LL | c2.v[0].v.set(Some(&c1)); | ^^^ borrowed value does not live long enough LL | diff --git a/tests/ui/span/vec_refs_data_with_early_death.stderr b/tests/ui/span/vec_refs_data_with_early_death.stderr index 684e7845313..73f27144af4 100644 --- a/tests/ui/span/vec_refs_data_with_early_death.stderr +++ b/tests/ui/span/vec_refs_data_with_early_death.stderr @@ -1,6 +1,9 @@ error[E0597]: `x` does not live long enough --> $DIR/vec_refs_data_with_early_death.rs:17:12 | +LL | let x: i8 = 3; + | - binding `x` declared here +... LL | v.push(&x); | ^^ borrowed value does not live long enough ... @@ -15,6 +18,9 @@ LL | } error[E0597]: `y` does not live long enough --> $DIR/vec_refs_data_with_early_death.rs:19:12 | +LL | let y: i8 = 4; + | - binding `y` declared here +... LL | v.push(&y); | ^^ borrowed value does not live long enough ... diff --git a/tests/ui/span/wf-method-late-bound-regions.stderr b/tests/ui/span/wf-method-late-bound-regions.stderr index 6b0b008208f..64c2d0f1606 100644 --- a/tests/ui/span/wf-method-late-bound-regions.stderr +++ b/tests/ui/span/wf-method-late-bound-regions.stderr @@ -4,6 +4,7 @@ error[E0597]: `pointer` does not live long enough LL | let dangling = { | -------- borrow later stored here LL | let pointer = Box::new(42); + | ------- binding `pointer` declared here LL | f2.xmute(&pointer) | ^^^^^^^^ borrowed value does not live long enough LL | }; diff --git a/tests/ui/static/static-lifetime-bound.stderr b/tests/ui/static/static-lifetime-bound.stderr index ef07a89315f..e22411b13b7 100644 --- a/tests/ui/static/static-lifetime-bound.stderr +++ b/tests/ui/static/static-lifetime-bound.stderr @@ -9,6 +9,8 @@ LL | fn f<'a: 'static>(_: &'a i32) {} error[E0597]: `x` does not live long enough --> $DIR/static-lifetime-bound.rs:5:7 | +LL | let x = 0; + | - binding `x` declared here LL | f(&x); | --^^- | | | diff --git a/tests/ui/static/static-reference-to-fn-1.stderr b/tests/ui/static/static-reference-to-fn-1.stderr index 67b478bdb75..f68939d0ec8 100644 --- a/tests/ui/static/static-reference-to-fn-1.stderr +++ b/tests/ui/static/static-reference-to-fn-1.stderr @@ -2,10 +2,14 @@ error[E0308]: mismatched types --> $DIR/static-reference-to-fn-1.rs:17:15 | LL | func: &foo, - | ^^^^ expected fn pointer, found fn item + | ^^^^ + | | + | expected fn pointer, found fn item + | help: consider casting to a fn pointer: `&(foo as fn() -> Option<isize>)` | = note: expected reference `&fn() -> Option<isize>` found reference `&fn() -> Option<isize> {foo}` + = note: fn items are distinct from fn pointers error: aborting due to previous error diff --git a/tests/ui/stdlib-unit-tests/not-sync.stderr b/tests/ui/stdlib-unit-tests/not-sync.stderr index 1ee358ba836..4e34e10e377 100644 --- a/tests/ui/stdlib-unit-tests/not-sync.stderr +++ b/tests/ui/stdlib-unit-tests/not-sync.stderr @@ -5,6 +5,7 @@ LL | test::<Cell<i32>>(); | ^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `Cell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead note: required by a bound in `test` --> $DIR/not-sync.rs:5:12 | @@ -18,6 +19,7 @@ LL | test::<RefCell<i32>>(); | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely | = help: the trait `Sync` is not implemented for `RefCell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: required by a bound in `test` --> $DIR/not-sync.rs:5:12 | diff --git a/tests/ui/suggestions/assoc-const-without-self.rs b/tests/ui/suggestions/assoc-const-without-self.rs new file mode 100644 index 00000000000..95070ec601c --- /dev/null +++ b/tests/ui/suggestions/assoc-const-without-self.rs @@ -0,0 +1,11 @@ +struct Foo; + +impl Foo { + const A_CONST: usize = 1; + + fn foo() -> usize { + A_CONST //~ ERROR cannot find value `A_CONST` in this scope + } +} + +fn main() {} diff --git a/tests/ui/suggestions/assoc-const-without-self.stderr b/tests/ui/suggestions/assoc-const-without-self.stderr new file mode 100644 index 00000000000..88d72da70cb --- /dev/null +++ b/tests/ui/suggestions/assoc-const-without-self.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find value `A_CONST` in this scope + --> $DIR/assoc-const-without-self.rs:7:9 + | +LL | A_CONST + | ^^^^^^^ not found in this scope + | +help: consider using the associated constant + | +LL | Self::A_CONST + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/borrow-for-loop-head.stderr b/tests/ui/suggestions/borrow-for-loop-head.stderr index cbdb94877bd..0f179438a12 100644 --- a/tests/ui/suggestions/borrow-for-loop-head.stderr +++ b/tests/ui/suggestions/borrow-for-loop-head.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/borrow-for-loop-head.rs:4:18 | +LL | let a = vec![1, 2, 3]; + | - binding `a` declared here LL | for i in &a { | -- borrow of `a` occurs here LL | for j in a { diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs new file mode 100644 index 00000000000..3bf6b7bb9b1 --- /dev/null +++ b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.rs @@ -0,0 +1,28 @@ +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +pub struct Trader<'a> { + closure: Box<dyn Fn(&mut Trader) + 'a>, +} + +impl<'a> Trader<'a> { + pub fn new() -> Self { + Trader { + closure: Box::new(|_| {}), + } + } + pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) { + //foo + } +} + +fn main() { + let closure = |trader : Trader| { + println!("Woooosh!"); + }; + + let mut trader = Trader::new(); + trader.set_closure(closure); + //~^ ERROR type mismatch in closure arguments +} diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr new file mode 100644 index 00000000000..6820af1fd45 --- /dev/null +++ b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr @@ -0,0 +1,26 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/late-bound-in-borrow-closure-sugg.rs:26:24 + | +LL | let closure = |trader : Trader| { + | ----------------- found signature defined here +... +LL | trader.set_closure(closure); + | ----------- ^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _` + found closure signature `for<'a> fn(Trader<'a>) -> _` +note: required by a bound in `Trader::<'a>::set_closure` + --> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50 + | +LL | pub fn set_closure(&mut self, function: impl Fn(&mut Trader) + 'a) { + | ^^^^^^^^^^^^^^^ required by this bound in `Trader::<'a>::set_closure` +help: consider borrowing the argument + | +LL | let closure = |trader : &mut Trader| { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0631`. diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr index 1d3dff3be34..94acda73c4e 100644 --- a/tests/ui/suggestions/option-content-move2.stderr +++ b/tests/ui/suggestions/option-content-move2.stderr @@ -7,7 +7,7 @@ LL | func(|| { | -- captured by this `FnMut` closure LL | // Shouldn't suggest `move ||.as_ref()` here LL | move || { - | ^^^^^^^ move out of `var` occurs here + | ^^^^^^^ `var` is moved here LL | LL | var = Some(NotCopyable); | --- diff --git a/tests/ui/suggestions/ref-pattern-binding.stderr b/tests/ui/suggestions/ref-pattern-binding.stderr index 10447ba7089..7b194259349 100644 --- a/tests/ui/suggestions/ref-pattern-binding.stderr +++ b/tests/ui/suggestions/ref-pattern-binding.stderr @@ -19,8 +19,8 @@ error: cannot move out of value because it is borrowed LL | let ref _moved @ _from = String::from("foo"); | ----------^^^----- | | | - | | value moved into `_from` here - | value borrowed, by `_moved`, here + | | value is moved into `_from` here + | value is borrowed by `_moved` here error: cannot move out of value because it is borrowed --> $DIR/ref-pattern-binding.rs:15:9 @@ -28,8 +28,8 @@ error: cannot move out of value because it is borrowed LL | let ref _moved @ S { f } = S { f: String::from("foo") }; | ----------^^^^^^^-^^ | | | - | | value moved into `f` here - | value borrowed, by `_moved`, here + | | value is moved into `f` here + | value is borrowed by `_moved` here error: borrow of moved value --> $DIR/ref-pattern-binding.rs:18:9 diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index 3ad4ed24cf7..fe490a6000d 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17hcbad207c0eeb0b3bE) +error: symbol-name(_ZN5basic4main17he9f658e438f1cac0E) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::hcbad207c0eeb0b3b) +error: demangling(basic::main::he9f658e438f1cac0) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index 21bf21ee71c..29b42f48d80 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h2f2efcf580c9b1eeE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h13209029be24b923E) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h2f2efcf580c9b1ee) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h13209029be24b923) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/mutexguard-sync.rs b/tests/ui/sync/mutexguard-sync.rs index b5641838318..b5641838318 100644 --- a/tests/ui/mutexguard-sync.rs +++ b/tests/ui/sync/mutexguard-sync.rs diff --git a/tests/ui/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr index 3fbb2ddf183..4dc5571196c 100644 --- a/tests/ui/mutexguard-sync.stderr +++ b/tests/ui/sync/mutexguard-sync.stderr @@ -7,6 +7,7 @@ LL | test_sync(guard); | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `Cell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync` note: required by a bound in `test_sync` --> $DIR/mutexguard-sync.rs:5:17 diff --git a/tests/ui/sync/suggest-cell.rs b/tests/ui/sync/suggest-cell.rs new file mode 100644 index 00000000000..3284eae7be1 --- /dev/null +++ b/tests/ui/sync/suggest-cell.rs @@ -0,0 +1,31 @@ +fn require_sync<T: Sync>() {} +//~^ NOTE required by this bound in `require_sync` +//~| NOTE required by this bound in `require_sync` +//~| NOTE required by this bound in `require_sync` +//~| NOTE required by this bound in `require_sync` +//~| NOTE required by a bound in `require_sync` +//~| NOTE required by a bound in `require_sync` +//~| NOTE required by a bound in `require_sync` +//~| NOTE required by a bound in `require_sync` + +fn main() { + require_sync::<std::cell::Cell<()>>(); + //~^ ERROR `Cell<()>` cannot be shared between threads safely + //~| NOTE `Cell<()>` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` + + require_sync::<std::cell::Cell<u8>>(); + //~^ ERROR `Cell<u8>` cannot be shared between threads safely + //~| NOTE `Cell<u8>` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead + + require_sync::<std::cell::Cell<i32>>(); + //~^ ERROR `Cell<i32>` cannot be shared between threads safely + //~| NOTE `Cell<i32>` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead + + require_sync::<std::cell::Cell<bool>>(); + //~^ ERROR `Cell<bool>` cannot be shared between threads safely + //~| NOTE `Cell<bool>` cannot be shared between threads safely + //~| NOTE if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead +} diff --git a/tests/ui/sync/suggest-cell.stderr b/tests/ui/sync/suggest-cell.stderr new file mode 100644 index 00000000000..c232c1ccd53 --- /dev/null +++ b/tests/ui/sync/suggest-cell.stderr @@ -0,0 +1,59 @@ +error[E0277]: `Cell<()>` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:12:20 + | +LL | require_sync::<std::cell::Cell<()>>(); + | ^^^^^^^^^^^^^^^^^^^ `Cell<()>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell<()>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync<T: Sync>() {} + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `Cell<u8>` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:17:20 + | +LL | require_sync::<std::cell::Cell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^ `Cell<u8>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell<u8>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync<T: Sync>() {} + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `Cell<i32>` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:22:20 + | +LL | require_sync::<std::cell::Cell<i32>>(); + | ^^^^^^^^^^^^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell<i32>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync<T: Sync>() {} + | ^^^^ required by this bound in `require_sync` + +error[E0277]: `Cell<bool>` cannot be shared between threads safely + --> $DIR/suggest-cell.rs:27:20 + | +LL | require_sync::<std::cell::Cell<bool>>(); + | ^^^^^^^^^^^^^^^^^^^^^ `Cell<bool>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell<bool>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-cell.rs:1:20 + | +LL | fn require_sync<T: Sync>() {} + | ^^^^ required by this bound in `require_sync` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/sync/suggest-once-cell.rs b/tests/ui/sync/suggest-once-cell.rs new file mode 100644 index 00000000000..82fca45b1a4 --- /dev/null +++ b/tests/ui/sync/suggest-once-cell.rs @@ -0,0 +1,12 @@ +#![feature(once_cell)] + +fn require_sync<T: Sync>() {} +//~^ NOTE required by this bound in `require_sync` +//~| NOTE required by a bound in `require_sync` + +fn main() { + require_sync::<std::cell::OnceCell<()>>(); + //~^ ERROR `OnceCell<()>` cannot be shared between threads safely + //~| NOTE `OnceCell<()>` cannot be shared between threads safely + //~| NOTE use `std::sync::OnceLock` instead +} diff --git a/tests/ui/sync/suggest-once-cell.stderr b/tests/ui/sync/suggest-once-cell.stderr new file mode 100644 index 00000000000..fadf05374d8 --- /dev/null +++ b/tests/ui/sync/suggest-once-cell.stderr @@ -0,0 +1,17 @@ +error[E0277]: `OnceCell<()>` cannot be shared between threads safely + --> $DIR/suggest-once-cell.rs:8:20 + | +LL | require_sync::<std::cell::OnceCell<()>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ `OnceCell<()>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `OnceCell<()>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-once-cell.rs:3:20 + | +LL | fn require_sync<T: Sync>() {} + | ^^^^ required by this bound in `require_sync` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/sync/suggest-ref-cell.rs b/tests/ui/sync/suggest-ref-cell.rs new file mode 100644 index 00000000000..6b972ae0962 --- /dev/null +++ b/tests/ui/sync/suggest-ref-cell.rs @@ -0,0 +1,12 @@ +#![feature(once_cell)] + +fn require_sync<T: Sync>() {} +//~^ NOTE required by this bound in `require_sync` +//~| NOTE required by a bound in `require_sync` + +fn main() { + require_sync::<std::cell::RefCell<()>>(); + //~^ ERROR `RefCell<()>` cannot be shared between threads safely + //~| NOTE `RefCell<()>` cannot be shared between threads safely + //~| NOTE use `std::sync::RwLock` instead +} diff --git a/tests/ui/sync/suggest-ref-cell.stderr b/tests/ui/sync/suggest-ref-cell.stderr new file mode 100644 index 00000000000..9e8b8fcb42e --- /dev/null +++ b/tests/ui/sync/suggest-ref-cell.stderr @@ -0,0 +1,17 @@ +error[E0277]: `RefCell<()>` cannot be shared between threads safely + --> $DIR/suggest-ref-cell.rs:8:20 + | +LL | require_sync::<std::cell::RefCell<()>>(); + | ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<()>` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell<()>` + = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead +note: required by a bound in `require_sync` + --> $DIR/suggest-ref-cell.rs:3:20 + | +LL | fn require_sync<T: Sync>() {} + | ^^^^ required by this bound in `require_sync` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/thir-print/thir-flat.rs b/tests/ui/thir-print/thir-flat.rs new file mode 100644 index 00000000000..8fa95ce62b5 --- /dev/null +++ b/tests/ui/thir-print/thir-flat.rs @@ -0,0 +1,4 @@ +// compile-flags: -Z unpretty=thir-flat +// check-pass + +pub fn main() {} diff --git a/tests/ui/thir-tree.stdout b/tests/ui/thir-print/thir-flat.stdout index 4b6915f7715..c399fa66b6a 100644 --- a/tests/ui/thir-tree.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -1,4 +1,4 @@ -DefId(0:3 ~ thir_tree[8f1d]::main): +DefId(0:3 ~ thir_flat[45a6]::main): Thir { arms: [], blocks: [ @@ -6,7 +6,7 @@ Thir { targeted_by_break: false, region_scope: Node(1), opt_destruction_scope: None, - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), stmts: [], expr: None, safety_mode: Safe, @@ -18,7 +18,7 @@ Thir { temp_lifetime: Some( Node(2), ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Block { block: b0, }, @@ -28,11 +28,11 @@ Thir { temp_lifetime: Some( Node(2), ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Scope { region_scope: Node(2), lint_level: Explicit( - HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2), + HirId(DefId(0:3 ~ thir_flat[45a6]::main).2), ), value: e0, }, @@ -42,7 +42,7 @@ Thir { temp_lifetime: Some( Node(2), ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Scope { region_scope: Destruction(2), lint_level: Inherited, diff --git a/tests/ui/thir-print/thir-tree-match.rs b/tests/ui/thir-print/thir-tree-match.rs new file mode 100644 index 00000000000..a5511ec9543 --- /dev/null +++ b/tests/ui/thir-print/thir-tree-match.rs @@ -0,0 +1,23 @@ +// check-pass +// compile-flags: -Zunpretty=thir-tree + +enum Bar { + First, + Second, + Third, +} + +enum Foo { + FooOne(Bar), + FooTwo, +} + +fn has_match(foo: Foo) -> bool { + match foo { + Foo::FooOne(Bar::First) => true, + Foo::FooOne(_) => false, + Foo::FooTwo => true, + } +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout new file mode 100644 index 00000000000..d6174ec262a --- /dev/null +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -0,0 +1,342 @@ +DefId(0:16 ~ thir_tree_match[3c9a]::has_match): +params: [ + Param { + ty: Foo + ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0)) + self_kind: None + hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).1)) + param: Some( + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0) + kind: PatKind { + Binding { + mutability: Not + name: "foo" + mode: ByValue + var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2)) + ty: Foo + is_primary: true + subpattern: None + } + } + } + ) + } +] +body: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Scope { + region_scope: Destruction(26) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Scope { + region_scope: Node(26) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + region_scope: Node(25) + safety_mode: Safe + stmts: [] + expr: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) + kind: + Scope { + region_scope: Node(3) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) + kind: + Match { + scrutinee: + Expr { + ty: Foo + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) + kind: + Scope { + region_scope: Node(4) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4)) + value: + Expr { + ty: Foo + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2)) + } + } + } + } + arms: [ + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 0 + subpatterns: [ + Pat: { + ty: Bar + span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_match[3c9a]::Bar) + variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[3c9a]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[3c9a]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[3c9a]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[3c9a]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[3c9a]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[3c9a]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3125160937860410723 } + substs: [] + variant_index: 0 + subpatterns: [] + } + } + } + ] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Scope { + region_scope: Destruction(13) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Scope { + region_scope: Node(13) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12)) + scope: Node(12) + span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0) + } + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 0 + subpatterns: [ + Pat: { + ty: Bar + span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0) + kind: PatKind { + Wild + } + } + ] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Scope { + region_scope: Destruction(19) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Scope { + region_scope: Node(19) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18)) + scope: Node(18) + span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0) + } + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 1 + subpatterns: [] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Scope { + region_scope: Destruction(24) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Scope { + region_scope: Node(24) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23)) + scope: Node(23) + span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0) + } + ] + } + } + } + } + } + } + } + } + } + } + + +DefId(0:17 ~ thir_tree_match[3c9a]::main): +params: [ +] +body: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Scope { + region_scope: Destruction(2) + lint_level: Inherited + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Scope { + region_scope: Node(2) + lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2)) + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + } + } + + diff --git a/tests/ui/thir-tree.rs b/tests/ui/thir-print/thir-tree.rs index 32df7905adb..32df7905adb 100644 --- a/tests/ui/thir-tree.rs +++ b/tests/ui/thir-print/thir-tree.rs diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout new file mode 100644 index 00000000000..0a35d9fb78c --- /dev/null +++ b/tests/ui/thir-print/thir-tree.stdout @@ -0,0 +1,43 @@ +DefId(0:3 ~ thir_tree[8f1d]::main): +params: [ +] +body: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Scope { + region_scope: Destruction(2) + lint_level: Inherited + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Scope { + region_scope: Node(2) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2)) + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + } + } + + diff --git a/tests/ui/traits/alias/issue-60755.rs b/tests/ui/traits/alias/issue-60755.rs new file mode 100644 index 00000000000..6b955a75247 --- /dev/null +++ b/tests/ui/traits/alias/issue-60755.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(trait_alias)] + +struct MyStruct {} +trait MyFn = Fn(&MyStruct); + +fn foo(_: impl MyFn) {} + +fn main() { + foo(|_| {}); +} diff --git a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-3.stderr b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-3.stderr index ade552c4bab..c7af71a4214 100644 --- a/tests/ui/traits/associated_type_bound/check-trait-object-bounds-3.stderr +++ b/tests/ui/traits/associated_type_bound/check-trait-object-bounds-3.stderr @@ -1,6 +1,8 @@ error[E0597]: `s` does not live long enough --> $DIR/check-trait-object-bounds-3.rs:15:34 | +LL | let s = String::from("abcdef"); + | - binding `s` declared here LL | z = f::<dyn X<Y = &str>>(&s); | ---------------------^^- | | | diff --git a/tests/ui/traits/coercion-generic-regions.stderr b/tests/ui/traits/coercion-generic-regions.stderr index 5cfb6490123..ae70202ab7c 100644 --- a/tests/ui/traits/coercion-generic-regions.stderr +++ b/tests/ui/traits/coercion-generic-regions.stderr @@ -1,6 +1,8 @@ error[E0597]: `person` does not live long enough --> $DIR/coercion-generic-regions.rs:17:24 | +LL | let person = "Fred".to_string(); + | ------ binding `person` declared here LL | let person: &str = &person; | ^^^^^^^ | | diff --git a/tests/ui/traits/new-solver/async.fail.stderr b/tests/ui/traits/new-solver/async.fail.stderr new file mode 100644 index 00000000000..b395c23ae00 --- /dev/null +++ b/tests/ui/traits/new-solver/async.fail.stderr @@ -0,0 +1,17 @@ +error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()` + --> $DIR/async.rs:12:17 + | +LL | needs_async(async {}); + | ----------- ^^^^^^^^ expected `i32`, found `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_async` + --> $DIR/async.rs:8:31 + | +LL | fn needs_async(_: impl Future<Output = i32>) {} + | ^^^^^^^^^^^^ required by this bound in `needs_async` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/new-solver/async.rs b/tests/ui/traits/new-solver/async.rs new file mode 100644 index 00000000000..195cc35cad2 --- /dev/null +++ b/tests/ui/traits/new-solver/async.rs @@ -0,0 +1,19 @@ +// compile-flags: -Ztrait-solver=next +// edition: 2021 +// revisions: pass fail +//[pass] check-pass + +use std::future::Future; + +fn needs_async(_: impl Future<Output = i32>) {} + +#[cfg(fail)] +fn main() { + needs_async(async {}); + //[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()` +} + +#[cfg(pass)] +fn main() { + needs_async(async { 1i32 }); +} diff --git a/tests/ui/traits/new-solver/generator.fail.stderr b/tests/ui/traits/new-solver/generator.fail.stderr new file mode 100644 index 00000000000..d94d41e3587 --- /dev/null +++ b/tests/ui/traits/new-solver/generator.fail.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `[generator@$DIR/generator.rs:18:21: 18:23]: Generator<A>` is not satisfied + --> $DIR/generator.rs:18:21 + | +LL | needs_generator(|| { + | _____---------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | +LL | | yield (); +LL | | }); + | |_____^ the trait `Generator<A>` is not implemented for `[generator@$DIR/generator.rs:18:21: 18:23]` + | +note: required by a bound in `needs_generator` + --> $DIR/generator.rs:14:28 + | +LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_generator` + +error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Yield == B` + --> $DIR/generator.rs:18:21 + | +LL | needs_generator(|| { + | _____---------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | +LL | | yield (); +LL | | }); + | |_____^ types differ + | +note: required by a bound in `needs_generator` + --> $DIR/generator.rs:14:41 + | +LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {} + | ^^^^^^^^^ required by this bound in `needs_generator` + +error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Return == C` + --> $DIR/generator.rs:18:21 + | +LL | needs_generator(|| { + | _____---------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | +LL | | yield (); +LL | | }); + | |_____^ types differ + | +note: required by a bound in `needs_generator` + --> $DIR/generator.rs:14:52 + | +LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {} + | ^^^^^^^^^^ required by this bound in `needs_generator` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/new-solver/generator.rs b/tests/ui/traits/new-solver/generator.rs new file mode 100644 index 00000000000..364373ca8be --- /dev/null +++ b/tests/ui/traits/new-solver/generator.rs @@ -0,0 +1,32 @@ +// compile-flags: -Ztrait-solver=next +// edition: 2021 +// revisions: pass fail +//[pass] check-pass + +#![feature(generator_trait, generators)] + +use std::ops::Generator; + +struct A; +struct B; +struct C; + +fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {} + +#[cfg(fail)] +fn main() { + needs_generator(|| { + //[fail]~^ ERROR Generator<A>` is not satisfied + //[fail]~| ERROR as Generator<A>>::Yield == B` + //[fail]~| ERROR as Generator<A>>::Return == C` + yield (); + }); +} + +#[cfg(pass)] +fn main() { + needs_generator(|_: A| { + let _: A = yield B; + C + }) +} diff --git a/tests/ui/traits/new-solver/pointee.rs b/tests/ui/traits/new-solver/pointee.rs new file mode 100644 index 00000000000..fa6ee2e2daf --- /dev/null +++ b/tests/ui/traits/new-solver/pointee.rs @@ -0,0 +1,23 @@ +// compile-flags: -Ztrait-solver=next +// check-pass +#![feature(ptr_metadata)] + +use std::ptr::{DynMetadata, Pointee}; + +trait Trait<U> {} +struct MyDst<T: ?Sized>(T); + +fn works<T>() { + let _: <T as Pointee>::Metadata = (); + let _: <[T] as Pointee>::Metadata = 1_usize; + let _: <str as Pointee>::Metadata = 1_usize; + let _: <dyn Trait<T> as Pointee>::Metadata = give::<DynMetadata<dyn Trait<T>>>(); + let _: <MyDst<T> as Pointee>::Metadata = (); + let _: <((((([u8],),),),),) as Pointee>::Metadata = 1_usize; +} + +fn give<U>() -> U { + loop {} +} + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs new file mode 100644 index 00000000000..3c6ab86e4c6 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs @@ -0,0 +1,10 @@ +#![feature(multiple_supertrait_upcastable)] +#![deny(multiple_supertrait_upcastable)] + +trait A {} +trait B {} + +trait C: A + B {} +//~^ ERROR `C` is object-safe and has multiple supertraits + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr new file mode 100644 index 00000000000..ad80a009ece --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr @@ -0,0 +1,14 @@ +error: `C` is object-safe and has multiple supertraits + --> $DIR/multiple_supertrait_upcastable.rs:7:1 + | +LL | trait C: A + B {} + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/multiple_supertrait_upcastable.rs:2:9 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/traits/vtable/issue-97381.stderr b/tests/ui/traits/vtable/issue-97381.stderr index c4f8294e263..89360c44e78 100644 --- a/tests/ui/traits/vtable/issue-97381.stderr +++ b/tests/ui/traits/vtable/issue-97381.stderr @@ -1,6 +1,9 @@ error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/issue-97381.rs:26:14 | +LL | let v = [1, 2, 3] + | - binding `v` declared here +... LL | let el = &v[0]; | - borrow of `v` occurs here LL | diff --git a/tests/ui/try-block/try-block-bad-lifetime.stderr b/tests/ui/try-block/try-block-bad-lifetime.stderr index ea079e30d9c..28941cb0a9e 100644 --- a/tests/ui/try-block/try-block-bad-lifetime.stderr +++ b/tests/ui/try-block/try-block-bad-lifetime.stderr @@ -4,6 +4,7 @@ error[E0597]: `my_string` does not live long enough LL | let result: Result<(), &str> = try { | ------ borrow later stored here LL | let my_string = String::from(""); + | --------- binding `my_string` declared here LL | let my_str: & str = & my_string; | ^^^^^^^^^^^ borrowed value does not live long enough ... @@ -14,10 +15,10 @@ error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-bad-lifetime.rs:29:13 | LL | let k = &mut i; - | ------ borrow of `i` occurs here + | ------ `i` is borrowed here ... LL | i = 10; - | ^^^^^^ assignment to borrowed `i` occurs here + | ^^^^^^ `i` is assigned to here but it was already borrowed LL | }; LL | ::std::mem::drop(k); | - borrow later used here @@ -38,10 +39,10 @@ error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-bad-lifetime.rs:32:9 | LL | let k = &mut i; - | ------ borrow of `i` occurs here + | ------ `i` is borrowed here ... LL | i = 40; - | ^^^^^^ assignment to borrowed `i` occurs here + | ^^^^^^ `i` is assigned to here but it was already borrowed LL | LL | let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") }; | - borrow later used here diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr index f738b03eed6..71c7e460c39 100644 --- a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -2,10 +2,10 @@ error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-maybe-bad-lifetime.rs:17:9 | LL | &i - | -- borrow of `i` occurs here + | -- `i` is borrowed here LL | }; LL | i = 0; - | ^^^^^ assignment to borrowed `i` occurs here + | ^^^^^ `i` is assigned to here but it was already borrowed LL | let _ = i; LL | do_something_with(x); | - borrow later used here @@ -32,10 +32,10 @@ error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-maybe-bad-lifetime.rs:40:9 | LL | j = &i; - | -- borrow of `i` occurs here + | -- `i` is borrowed here LL | }; LL | i = 0; - | ^^^^^ assignment to borrowed `i` occurs here + | ^^^^^ `i` is assigned to here but it was already borrowed LL | let _ = i; LL | do_something_with(j); | - borrow later used here diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked.rs b/tests/ui/type-alias-impl-trait/bounds-are-checked.rs index 83d22161e4e..eeb5dca07f0 100644 --- a/tests/ui/type-alias-impl-trait/bounds-are-checked.rs +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked.rs @@ -8,7 +8,7 @@ type X<'a> = impl Into<&'static str> + From<&'a str>; fn f<'a: 'static>(t: &'a str) -> X<'a> { //~^ WARNING unnecessary lifetime parameter t - //~^ ERROR non-defining opaque type use + //~^ ERROR expected generic lifetime parameter, found `'static` } fn extend_lt<'a>(o: &'a str) -> &'static str { diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked.stderr index 920eef11da4..94882597a62 100644 --- a/tests/ui/type-alias-impl-trait/bounds-are-checked.stderr +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked.stderr @@ -6,7 +6,7 @@ LL | fn f<'a: 'static>(t: &'a str) -> X<'a> { | = help: you can use the `'static` lifetime directly, in place of `'a` -error: non-defining opaque type use in defining scope +error[E0792]: expected generic lifetime parameter, found `'static` --> $DIR/bounds-are-checked.rs:10:5 | LL | type X<'a> = impl Into<&'static str> + From<&'a str>; @@ -17,3 +17,4 @@ LL | t error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs index f5045d382aa..e7b8567b9a2 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -19,7 +19,7 @@ fn concrete_ty() -> OneTy<u32> { fn concrete_lifetime() -> OneLifetime<'static> { 6u32 - //~^ ERROR non-defining opaque type use in defining scope + //~^ ERROR expected generic lifetime parameter, found `'static` } fn concrete_const() -> OneConst<{ 123 }> { diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr index 564648630b1..966fe823f02 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -7,7 +7,7 @@ LL | type OneTy<T> = impl Debug; LL | 5u32 | ^^^^ -error: non-defining opaque type use in defining scope +error[E0792]: expected generic lifetime parameter, found `'static` --> $DIR/generic_nondefining_use.rs:21:5 | LL | type OneLifetime<'a> = impl Debug; diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.rs b/tests/ui/type/type-check/coerce-result-return-value-2.rs new file mode 100644 index 00000000000..23bafa6c5c9 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value-2.rs @@ -0,0 +1,24 @@ +struct A; +struct B; +impl From<A> for B { + fn from(_: A) -> Self { B } +} +fn foo4(x: Result<(), A>) -> Result<(), B> { + match true { + true => x, //~ ERROR mismatched types + false => x, + } +} +fn foo5(x: Result<(), A>) -> Result<(), B> { + match true { + true => return x, //~ ERROR mismatched types + false => return x, + } +} +fn main() { + let _ = foo4(Ok(())); + let _ = foo5(Ok(())); + let _: Result<(), B> = { //~ ERROR mismatched types + Err(A); + }; +} diff --git a/tests/ui/type/type-check/coerce-result-return-value-2.stderr b/tests/ui/type/type-check/coerce-result-return-value-2.stderr new file mode 100644 index 00000000000..5992162341e --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value-2.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value-2.rs:8:17 + | +LL | fn foo4(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | match true { +LL | true => x, + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | true => Ok(x?), + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value-2.rs:14:24 + | +LL | fn foo5(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | match true { +LL | true => return x, + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | true => return Ok(x?), + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value-2.rs:21:28 + | +LL | let _: Result<(), B> = { + | ____________________________^ +LL | | Err(A); +LL | | }; + | |_____^ expected enum `Result`, found `()` + | + = note: expected enum `Result<(), B>` + found unit type `()` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type/type-check/coerce-result-return-value.fixed b/tests/ui/type/type-check/coerce-result-return-value.fixed new file mode 100644 index 00000000000..8a05407070d --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.fixed @@ -0,0 +1,24 @@ +// run-rustfix +struct A; +struct B; +impl From<A> for B { + fn from(_: A) -> Self { B } +} +fn foo1(x: Result<(), A>) -> Result<(), B> { + Ok(x?) //~ ERROR mismatched types +} +fn foo2(x: Result<(), A>) -> Result<(), B> { + return Ok(x?); //~ ERROR mismatched types +} +fn foo3(x: Result<(), A>) -> Result<(), B> { + if true { + Ok(x?) //~ ERROR mismatched types + } else { + Ok(x?) //~ ERROR mismatched types + } +} +fn main() { + let _ = foo1(Ok(())); + let _ = foo2(Ok(())); + let _ = foo3(Ok(())); +} diff --git a/tests/ui/type/type-check/coerce-result-return-value.rs b/tests/ui/type/type-check/coerce-result-return-value.rs new file mode 100644 index 00000000000..442203addb7 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.rs @@ -0,0 +1,24 @@ +// run-rustfix +struct A; +struct B; +impl From<A> for B { + fn from(_: A) -> Self { B } +} +fn foo1(x: Result<(), A>) -> Result<(), B> { + x //~ ERROR mismatched types +} +fn foo2(x: Result<(), A>) -> Result<(), B> { + return x; //~ ERROR mismatched types +} +fn foo3(x: Result<(), A>) -> Result<(), B> { + if true { + x //~ ERROR mismatched types + } else { + x //~ ERROR mismatched types + } +} +fn main() { + let _ = foo1(Ok(())); + let _ = foo2(Ok(())); + let _ = foo3(Ok(())); +} diff --git a/tests/ui/type/type-check/coerce-result-return-value.stderr b/tests/ui/type/type-check/coerce-result-return-value.stderr new file mode 100644 index 00000000000..55015352078 --- /dev/null +++ b/tests/ui/type/type-check/coerce-result-return-value.stderr @@ -0,0 +1,65 @@ +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:8:5 + | +LL | fn foo1(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | x + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | Ok(x?) + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:11:12 + | +LL | fn foo2(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | return x; + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | return Ok(x?); + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:15:9 + | +LL | fn foo3(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +LL | if true { +LL | x + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | Ok(x?) + | +++ ++ + +error[E0308]: mismatched types + --> $DIR/coerce-result-return-value.rs:17:9 + | +LL | fn foo3(x: Result<(), A>) -> Result<(), B> { + | ------------- expected `Result<(), B>` because of return type +... +LL | x + | ^ expected struct `B`, found struct `A` + | + = note: expected enum `Result<_, B>` + found enum `Result<_, A>` +help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result` + | +LL | Ok(x?) + | +++ ++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/bad-type-in-vec-push.rs b/tests/ui/typeck/bad-type-in-vec-push.rs new file mode 100644 index 00000000000..a807f030cfc --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-push.rs @@ -0,0 +1,20 @@ +// The error message here still is pretty confusing. + +fn main() { + let mut result = vec![1]; + // The type of `result` is constrained to be `Vec<{integer}>` here. + // But the logic we use to find what expression constrains a type + // is not sophisticated enough to know this. + + let mut vector = Vec::new(); + vector.sort(); + result.push(vector); + //~^ ERROR mismatched types + // So it thinks that the type of `result` is constrained here. +} + +fn example2() { + let mut x = vec![1]; + x.push(""); + //~^ ERROR mismatched types +} diff --git a/tests/ui/typeck/bad-type-in-vec-push.stderr b/tests/ui/typeck/bad-type-in-vec-push.stderr new file mode 100644 index 00000000000..e4c99ec8e70 --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-push.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/bad-type-in-vec-push.rs:11:17 + | +LL | vector.sort(); + | ------ here the type of `vector` is inferred to be `Vec<_>` +LL | result.push(vector); + | ---- ^^^^^^ expected integer, found struct `Vec` + | | + | arguments to this method are incorrect + | + = note: expected type `{integer}` + found struct `Vec<_>` +note: associated function defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/bad-type-in-vec-push.rs:18:12 + | +LL | x.push(""); + | ---- ^^ expected integer, found `&str` + | | + | arguments to this method are incorrect + | +note: associated function defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-107087.rs b/tests/ui/typeck/issue-107087.rs new file mode 100644 index 00000000000..135cdf19e3e --- /dev/null +++ b/tests/ui/typeck/issue-107087.rs @@ -0,0 +1,18 @@ +struct A<T>(T); + +trait Foo { + type B; +} + +impl Foo for A<u32> { + type B = i32; +} + +impl Foo for A<i32> { + type B = i32; +} + +fn main() { + A::B::<>::C + //~^ ERROR ambiguous associated type +} diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr new file mode 100644 index 00000000000..70f19320802 --- /dev/null +++ b/tests/ui/typeck/issue-107087.stderr @@ -0,0 +1,9 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-107087.rs:16:5 + | +LL | A::B::<>::C + | ^^^^^^^^ help: use the fully-qualified path: `<A<_> as Foo>::B` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/typeck/issue-91334.stderr b/tests/ui/typeck/issue-91334.stderr index 8508f7a38e2..78f392c9a8a 100644 --- a/tests/ui/typeck/issue-91334.stderr +++ b/tests/ui/typeck/issue-91334.stderr @@ -2,8 +2,9 @@ error: this file contains an unclosed delimiter --> $DIR/issue-91334.rs:10:23 | LL | fn f(){||yield(((){), - | - - ^ - | | | + | - - - ^ + | | | | + | | | missing open `(` for this delimiter | | unclosed delimiter | unclosed delimiter @@ -11,8 +12,9 @@ error: this file contains an unclosed delimiter --> $DIR/issue-91334.rs:10:23 | LL | fn f(){||yield(((){), - | - - ^ - | | | + | - - - ^ + | | | | + | | | missing open `(` for this delimiter | | unclosed delimiter | unclosed delimiter diff --git a/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr b/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr index 21d6b4fde7e..98fe97c5c18 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-borrow-conflict.stderr @@ -4,7 +4,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed LL | let f = || x += 1; | -- - borrow occurs due to use of `x` in closure | | - | borrow of `x` occurs here + | `x` is borrowed here LL | let _y = x; | ^ use of borrowed `x` LL | f; diff --git a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr index cbdb4dd0fb5..23aa18d7156 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -16,14 +16,14 @@ error[E0506]: cannot assign to `factorial` because it is borrowed --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 | LL | let f = |x: u32| -> u32 { - | --------------- borrow of `factorial` occurs here + | --------------- `factorial` is borrowed here LL | let g = factorial.as_ref().unwrap(); | --------- borrow occurs due to use in closure ... LL | factorial = Some(Box::new(f)); | ^^^^^^^^^ | | - | assignment to borrowed `factorial` occurs here + | `factorial` is assigned to here but it was already borrowed | borrow later used here error[E0597]: `factorial` does not live long enough @@ -47,12 +47,12 @@ LL | let mut factorial: Option<Box<dyn Fn(u32) -> u32 + 'static>> = None; | ----------------------------------------- type annotation requires that `factorial` is borrowed for `'static` LL | LL | let f = |x: u32| -> u32 { - | --------------- borrow of `factorial` occurs here + | --------------- `factorial` is borrowed here LL | let g = factorial.as_ref().unwrap(); | --------- borrow occurs due to use in closure ... LL | factorial = Some(Box::new(f)); - | ^^^^^^^^^ assignment to borrowed `factorial` occurs here + | ^^^^^^^^^ `factorial` is assigned to here but it was already borrowed error: aborting due to 4 previous errors diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr index 2a3ca14433f..e47785c465a 100644 --- a/tests/ui/unop-move-semantics.stderr +++ b/tests/ui/unop-move-semantics.stderr @@ -23,6 +23,8 @@ LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) { error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/unop-move-semantics.rs:15:6 | +LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) { + | - binding `x` declared here LL | let m = &x; | -- borrow of `x` occurs here ... @@ -35,6 +37,9 @@ LL | use_mut(n); use_imm(m); error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/unop-move-semantics.rs:17:6 | +LL | fn move_borrowed<T: Not<Output=T>>(x: T, mut y: T) { + | ----- binding `y` declared here +LL | let m = &x; LL | let n = &mut y; | ------ borrow of `y` occurs here ... diff --git a/tests/ui/variance/variance-associated-types.rs b/tests/ui/variance/variance-associated-types.rs index 1165fb53c73..ecb0821827d 100644 --- a/tests/ui/variance/variance-associated-types.rs +++ b/tests/ui/variance/variance-associated-types.rs @@ -10,7 +10,7 @@ trait Trait<'a> { } #[rustc_variance] -struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +] +struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +] field: (T, &'a ()) } diff --git a/tests/ui/variance/variance-associated-types.stderr b/tests/ui/variance/variance-associated-types.stderr index 51f17c7c228..70cb246f6e9 100644 --- a/tests/ui/variance/variance-associated-types.stderr +++ b/tests/ui/variance/variance-associated-types.stderr @@ -1,4 +1,4 @@ -error: [-, +] +error: [+, +] --> $DIR/variance-associated-types.rs:13:1 | LL | struct Foo<'a, T : Trait<'a>> { diff --git a/tests/ui/variance/variance-issue-20533.stderr b/tests/ui/variance/variance-issue-20533.stderr index 008e2a002bb..258f67db5ce 100644 --- a/tests/ui/variance/variance-issue-20533.stderr +++ b/tests/ui/variance/variance-issue-20533.stderr @@ -1,6 +1,8 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:28:14 | +LL | let a = AffineU32(1); + | - binding `a` declared here LL | let x = foo(&a); | -- borrow of `a` occurs here LL | drop(a); @@ -11,6 +13,8 @@ LL | drop(x); error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:34:14 | +LL | let a = AffineU32(1); + | - binding `a` declared here LL | let x = bar(&a); | -- borrow of `a` occurs here LL | drop(a); @@ -21,6 +25,8 @@ LL | drop(x); error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:40:14 | +LL | let a = AffineU32(1); + | - binding `a` declared here LL | let x = baz(&a); | -- borrow of `a` occurs here LL | drop(a); diff --git a/tests/ui/variance/variance-regions-direct.rs b/tests/ui/variance/variance-regions-direct.rs index 3f34e7655f3..39ea77a8aa2 100644 --- a/tests/ui/variance/variance-regions-direct.rs +++ b/tests/ui/variance/variance-regions-direct.rs @@ -6,7 +6,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -] +struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +] x: &'a isize, y: &'b [isize], c: &'c str @@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +] +struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), c: extern "Rust" fn(&'c str), @@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR [-, o] +struct Test4<'a, 'b:'a> { //~ ERROR [+, o] x: &'a mut &'b isize, } @@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [-, o] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b:'a> { //~ ERROR [+, o] +struct Test5<'a, 'b:'a> { //~ ERROR [-, o] x: extern "Rust" fn(&'a mut &'b isize), } @@ -42,7 +42,7 @@ struct Test5<'a, 'b:'a> { //~ ERROR [+, o] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b:'a> { //~ ERROR [-, o] +struct Test6<'a, 'b:'a> { //~ ERROR [+, o] x: &'a mut extern "Rust" fn(&'b isize), } @@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR [*] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), diff --git a/tests/ui/variance/variance-regions-direct.stderr b/tests/ui/variance/variance-regions-direct.stderr index eda02e9b03b..c55730296f1 100644 --- a/tests/ui/variance/variance-regions-direct.stderr +++ b/tests/ui/variance/variance-regions-direct.stderr @@ -1,28 +1,28 @@ -error: [-, -, -] +error: [+, +, +] --> $DIR/variance-regions-direct.rs:9:1 | LL | struct Test2<'a, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, +, +] +error: [-, -, -] --> $DIR/variance-regions-direct.rs:18:1 | LL | struct Test3<'a, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: [-, o] +error: [+, o] --> $DIR/variance-regions-direct.rs:27:1 | LL | struct Test4<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, o] +error: [-, o] --> $DIR/variance-regions-direct.rs:35:1 | LL | struct Test5<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [-, o] +error: [+, o] --> $DIR/variance-regions-direct.rs:45:1 | LL | struct Test6<'a, 'b:'a> { @@ -34,7 +34,7 @@ error: [*] LL | struct Test7<'a> { | ^^^^^^^^^^^^^^^^ -error: [+, -, o] +error: [-, +, o] --> $DIR/variance-regions-direct.rs:59:1 | LL | enum Test8<'a, 'b, 'c:'b> { diff --git a/tests/ui/variance/variance-regions-indirect.rs b/tests/ui/variance/variance-regions-indirect.rs index f84f25ada14..0d00535fef1 100644 --- a/tests/ui/variance/variance-regions-indirect.rs +++ b/tests/ui/variance/variance-regions-indirect.rs @@ -5,14 +5,14 @@ #![feature(rustc_attrs)] #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -] f: Base<'z, 'y, 'x, 'w> } @@ -22,12 +22,12 @@ struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *] } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *] f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o] f: Base<'a, 'b, 'c, 'a> } diff --git a/tests/ui/variance/variance-regions-indirect.stderr b/tests/ui/variance/variance-regions-indirect.stderr index fa2f4d507f3..edf2626d598 100644 --- a/tests/ui/variance/variance-regions-indirect.stderr +++ b/tests/ui/variance/variance-regions-indirect.stderr @@ -1,10 +1,10 @@ -error: [+, -, o, *] +error: [-, +, o, *] --> $DIR/variance-regions-indirect.rs:8:1 | LL | enum Base<'a, 'b, 'c:'b, 'd> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, o, -, +] +error: [*, o, +, -] --> $DIR/variance-regions-indirect.rs:15:1 | LL | struct Derived1<'w, 'x:'y, 'y, 'z> { @@ -16,13 +16,13 @@ error: [o, o, *] LL | struct Derived2<'a, 'b:'a, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, -, *] +error: [o, +, *] --> $DIR/variance-regions-indirect.rs:25:1 | LL | struct Derived3<'a:'b, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, -, o] +error: [-, +, o] --> $DIR/variance-regions-indirect.rs:30:1 | LL | struct Derived4<'a, 'b, 'c:'b> { diff --git a/tests/ui/variance/variance-trait-object-bound.rs b/tests/ui/variance/variance-trait-object-bound.rs index ec3c973bc76..11303c46520 100644 --- a/tests/ui/variance/variance-trait-object-bound.rs +++ b/tests/ui/variance/variance-trait-object-bound.rs @@ -11,7 +11,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR [-] +struct TOption<'a> { //~ ERROR [+] v: Option<Box<dyn T + 'a>>, } diff --git a/tests/ui/variance/variance-trait-object-bound.stderr b/tests/ui/variance/variance-trait-object-bound.stderr index 7c46b553f43..bfcc8d4a1d1 100644 --- a/tests/ui/variance/variance-trait-object-bound.stderr +++ b/tests/ui/variance/variance-trait-object-bound.stderr @@ -1,4 +1,4 @@ -error: [-] +error: [+] --> $DIR/variance-trait-object-bound.rs:14:1 | LL | struct TOption<'a> { diff --git a/tests/ui/variance/variance-types.rs b/tests/ui/variance/variance-types.rs index b9b6d9c9bb5..cfc03b75473 100644 --- a/tests/ui/variance/variance-types.rs +++ b/tests/ui/variance/variance-types.rs @@ -7,7 +7,7 @@ use std::cell::Cell; // not considered bivariant. #[rustc_variance] -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o] t: &'a mut (A,B) } diff --git a/tests/ui/variance/variance-types.stderr b/tests/ui/variance/variance-types.stderr index 9f7f1d9b0e3..0fda4b8036e 100644 --- a/tests/ui/variance/variance-types.stderr +++ b/tests/ui/variance/variance-types.stderr @@ -1,4 +1,4 @@ -error: [-, o, o] +error: [+, o, o] --> $DIR/variance-types.rs:10:1 | LL | struct InvariantMut<'a,A:'a,B:'a> { diff --git a/triagebot.toml b/triagebot.toml index 16a31321513..79958729fc5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -456,6 +456,9 @@ These commits modify **compiler targets**. (See the [Target Tier Policy](https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html).) """ +[mentions."src/doc/style-guide"] +cc = ["@rust-lang/style"] + [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html" @@ -560,6 +563,12 @@ ast_lowering = [ fallback = [ "@Mark-Simulacrum" ] +style-team = [ + "@calebcartwright", + "@compiler-errors", + "@joshtriplett", + "@yaahc", +] [assign.owners] "/.github/workflows" = ["infra-ci"] @@ -604,6 +613,7 @@ fallback = [ "/src/doc/rust-by-example" = ["@ehuss"] "/src/doc/rustc-dev-guide" = ["@ehuss"] "/src/doc/rustdoc" = ["rustdoc"] +"/src/doc/style-guide" = ["style-team"] "/src/etc" = ["@Mark-Simulacrum"] "/src/librustdoc" = ["rustdoc"] "/src/llvm-project" = ["@cuviper"] |
